This is an automated email from the ASF dual-hosted git repository. ntimofeev pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/cayenne.git
commit ee4790da3419a041478c04091ed46cf3bbd3ccd0 Author: Nikita Timofeev <stari...@gmail.com> AuthorDate: Wed Aug 18 20:44:29 2021 +0300 Use testcontainers for the test db setup --- .travis.yml | 6 +- cayenne-client/pom.xml | 170 +++-------- cayenne-dbsync/pom.xml | 169 +++-------- cayenne-jcache/pom.xml | 170 +++-------- cayenne-server/pom.xml | 170 +++-------- .../unit/di/server/ConnectionProperties.java | 2 +- .../server/ServerCaseDataSourceInfoProvider.java | 41 ++- .../cayenne/unit/di/server/ServerCaseModule.java | 15 + .../unit/testcontainers/Db2ContainerProvider.java | 41 +++ .../testcontainers/MariaDbContainerProvider.java | 25 ++ .../testcontainers/MysqlContainerProvider.java | 34 +++ .../testcontainers/OracleContainerProvider.java | 41 +++ .../testcontainers/PostgresContainerProvider.java | 24 ++ .../testcontainers/SqlServerContainerProvider.java | 25 ++ .../unit/testcontainers/TestContainerProvider.java | 25 ++ pom.xml | 324 ++++++++------------- 16 files changed, 534 insertions(+), 748 deletions(-) diff --git a/.travis.yml b/.travis.yml index b5e177f..65bb354 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,9 +26,9 @@ env: - DB_PROFILE=hsql - DB_PROFILE=h2 - DB_PROFILE=derby - - DB_PROFILE=mysql-docker - - DB_PROFILE=postgres-docker - - DB_PROFILE=sqlserver-docker + - DB_PROFILE=mysql-tc + - DB_PROFILE=postgres-tc + - DB_PROFILE=sqlserver-tc global: # travis encrypt -r apache/cayenne "SNAPSHOT_REPO_USERNAME='username'" # travis encrypt -r apache/cayenne "SNAPSHOT_REPO_PASSWORD='password'" diff --git a/cayenne-client/pom.xml b/cayenne-client/pom.xml index c02906a..37df551 100644 --- a/cayenne-client/pom.xml +++ b/cayenne-client/pom.xml @@ -79,6 +79,41 @@ <artifactId>slf4j-simple</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>testcontainers</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>mysql</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>mariadb</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>postgresql</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>oracle-xe</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>mssqlserver</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>db2</artifactId> + <scope>test</scope> + </dependency> </dependencies> <build> @@ -97,139 +132,4 @@ </plugins> </build> - <profiles> - <profile> - <id>postgres-docker</id> - <activation> - <property> - <name>cayenneTestConnection</name> - <value>postgres-docker</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <executions> - <execution> - <id>start-postgres</id> - <phase>pre-integration-test</phase> - <goals> - <goal>start</goal> - </goals> - </execution> - <execution> - <id>stop-postgres</id> - <phase>post-integration-test</phase> - <goals> - <goal>stop</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>mysql-docker</id> - <activation> - <property> - <name>cayenneTestConnection</name> - <value>mysql-docker</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <executions> - <execution> - <id>start-mysql</id> - <phase>pre-integration-test</phase> - <goals> - <goal>start</goal> - </goals> - </execution> - <execution> - <id>stop-mysql</id> - <phase>post-integration-test</phase> - <goals> - <goal>stop</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>mariadb-docker</id> - <activation> - <property> - <name>cayenneTestConnection</name> - <value>mariadb-docker</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <executions> - <execution> - <id>start-mariadb</id> - <phase>pre-integration-test</phase> - <goals> - <goal>start</goal> - </goals> - </execution> - <execution> - <id>stop-mariadb</id> - <phase>post-integration-test</phase> - <goals> - <goal>stop</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>sqlserver-docker</id> - <activation> - <property> - <name>cayenneTestConnection</name> - <value>sqlserver-docker</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <executions> - <execution> - <id>start-sqlserver</id> - <phase>pre-integration-test</phase> - <goals> - <goal>start</goal> - </goals> - </execution> - <execution> - <id>stop-sqlserver</id> - <phase>post-integration-test</phase> - <goals> - <goal>stop</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - </profiles> - </project> diff --git a/cayenne-dbsync/pom.xml b/cayenne-dbsync/pom.xml index 3dc58c0..1a83867 100644 --- a/cayenne-dbsync/pom.xml +++ b/cayenne-dbsync/pom.xml @@ -79,6 +79,41 @@ <artifactId>slf4j-simple</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>testcontainers</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>mysql</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>mariadb</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>postgresql</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>oracle-xe</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>mssqlserver</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>db2</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>org.apache.cayenne.build-tools</groupId> @@ -134,138 +169,4 @@ </plugin> </plugins> </build> - <profiles> - <profile> - <id>postgres-docker</id> - <activation> - <property> - <name>cayenneTestConnection</name> - <value>postgres-docker</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <executions> - <execution> - <id>start-postgres</id> - <phase>pre-integration-test</phase> - <goals> - <goal>start</goal> - </goals> - </execution> - <execution> - <id>stop-postgres</id> - <phase>post-integration-test</phase> - <goals> - <goal>stop</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>mysql-docker</id> - <activation> - <property> - <name>cayenneTestConnection</name> - <value>mysql-docker</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <executions> - <execution> - <id>start-mysql</id> - <phase>pre-integration-test</phase> - <goals> - <goal>start</goal> - </goals> - </execution> - <execution> - <id>stop-mysql</id> - <phase>post-integration-test</phase> - <goals> - <goal>stop</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>mariadb-docker</id> - <activation> - <property> - <name>cayenneTestConnection</name> - <value>mariadb-docker</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <executions> - <execution> - <id>start-mariadb</id> - <phase>pre-integration-test</phase> - <goals> - <goal>start</goal> - </goals> - </execution> - <execution> - <id>stop-mariadb</id> - <phase>post-integration-test</phase> - <goals> - <goal>stop</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>sqlserver-docker</id> - <activation> - <property> - <name>cayenneTestConnection</name> - <value>sqlserver-docker</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <executions> - <execution> - <id>start-sqlserver</id> - <phase>pre-integration-test</phase> - <goals> - <goal>start</goal> - </goals> - </execution> - <execution> - <id>stop-sqlserver</id> - <phase>post-integration-test</phase> - <goals> - <goal>stop</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - </profiles> </project> diff --git a/cayenne-jcache/pom.xml b/cayenne-jcache/pom.xml index 53a7250..c188a34 100644 --- a/cayenne-jcache/pom.xml +++ b/cayenne-jcache/pom.xml @@ -119,6 +119,41 @@ <artifactId>slf4j-simple</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>testcontainers</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>mysql</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>mariadb</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>postgresql</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>oracle-xe</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>mssqlserver</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>db2</artifactId> + <scope>test</scope> + </dependency> </dependencies> <build> @@ -137,139 +172,4 @@ </plugins> </build> - <profiles> - <profile> - <id>postgres-docker</id> - <activation> - <property> - <name>cayenneTestConnection</name> - <value>postgres-docker</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <executions> - <execution> - <id>start-postgres</id> - <phase>pre-integration-test</phase> - <goals> - <goal>start</goal> - </goals> - </execution> - <execution> - <id>stop-postgres</id> - <phase>post-integration-test</phase> - <goals> - <goal>stop</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>mysql-docker</id> - <activation> - <property> - <name>cayenneTestConnection</name> - <value>mysql-docker</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <executions> - <execution> - <id>start-mysql</id> - <phase>pre-integration-test</phase> - <goals> - <goal>start</goal> - </goals> - </execution> - <execution> - <id>stop-mysql</id> - <phase>post-integration-test</phase> - <goals> - <goal>stop</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>mariadb-docker</id> - <activation> - <property> - <name>cayenneTestConnection</name> - <value>mariadb-docker</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <executions> - <execution> - <id>start-mariadb</id> - <phase>pre-integration-test</phase> - <goals> - <goal>start</goal> - </goals> - </execution> - <execution> - <id>stop-mariadb</id> - <phase>post-integration-test</phase> - <goals> - <goal>stop</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>sqlserver-docker</id> - <activation> - <property> - <name>cayenneTestConnection</name> - <value>sqlserver-docker</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <executions> - <execution> - <id>start-sqlserver</id> - <phase>pre-integration-test</phase> - <goals> - <goal>start</goal> - </goals> - </execution> - <execution> - <id>stop-sqlserver</id> - <phase>post-integration-test</phase> - <goals> - <goal>stop</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - </profiles> - </project> \ No newline at end of file diff --git a/cayenne-server/pom.xml b/cayenne-server/pom.xml index 9a2defd..da15744 100644 --- a/cayenne-server/pom.xml +++ b/cayenne-server/pom.xml @@ -93,6 +93,41 @@ <artifactId>xmlunit</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>testcontainers</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>mysql</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>mariadb</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>postgresql</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>oracle-xe</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>mssqlserver</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>db2</artifactId> + <scope>test</scope> + </dependency> </dependencies> <build> <resources> @@ -202,139 +237,4 @@ </plugin> </plugins> </build> - - <profiles> - <profile> - <id>postgres-docker</id> - <activation> - <property> - <name>cayenneTestConnection</name> - <value>postgres-docker</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <executions> - <execution> - <id>start-postgres</id> - <phase>pre-integration-test</phase> - <goals> - <goal>start</goal> - </goals> - </execution> - <execution> - <id>stop-postgres</id> - <phase>post-integration-test</phase> - <goals> - <goal>stop</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>mysql-docker</id> - <activation> - <property> - <name>cayenneTestConnection</name> - <value>mysql-docker</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <executions> - <execution> - <id>start-mysql</id> - <phase>pre-integration-test</phase> - <goals> - <goal>start</goal> - </goals> - </execution> - <execution> - <id>stop-mysql</id> - <phase>post-integration-test</phase> - <goals> - <goal>stop</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>mariadb-docker</id> - <activation> - <property> - <name>cayenneTestConnection</name> - <value>mariadb-docker</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <executions> - <execution> - <id>start-mariadb</id> - <phase>pre-integration-test</phase> - <goals> - <goal>start</goal> - </goals> - </execution> - <execution> - <id>stop-mariadb</id> - <phase>post-integration-test</phase> - <goals> - <goal>stop</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - <profile> - <id>sqlserver-docker</id> - <activation> - <property> - <name>cayenneTestConnection</name> - <value>sqlserver-docker</value> - </property> - </activation> - <build> - <plugins> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <executions> - <execution> - <id>start-sqlserver</id> - <phase>pre-integration-test</phase> - <goals> - <goal>start</goal> - </goals> - </execution> - <execution> - <id>stop-sqlserver</id> - <phase>post-integration-test</phase> - <goals> - <goal>stop</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - </profile> - </profiles> </project> diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ConnectionProperties.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ConnectionProperties.java index 238fda5..e974b45 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ConnectionProperties.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ConnectionProperties.java @@ -36,7 +36,7 @@ import java.util.stream.Collectors; class ConnectionProperties { static final int MIN_CONNECTIONS = 1; - static final int MAX_CONNECTIONS = 2; + static final int MAX_CONNECTIONS = 3; private static final String ADAPTER_KEY = "adapter"; private static final String ADAPTER20_KEY = "cayenne.adapter"; diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceInfoProvider.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceInfoProvider.java index edc7a6b..9c8186c 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceInfoProvider.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceInfoProvider.java @@ -24,9 +24,12 @@ import org.apache.cayenne.dba.derby.DerbyAdapter; import org.apache.cayenne.dba.h2.H2Adapter; import org.apache.cayenne.dba.hsqldb.HSQLDBAdapter; import org.apache.cayenne.dba.sqlite.SQLiteAdapter; +import org.apache.cayenne.di.Inject; import org.apache.cayenne.di.Provider; +import org.apache.cayenne.unit.testcontainers.TestContainerProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.testcontainers.containers.JdbcDatabaseContainer; import java.io.File; import java.io.FileReader; @@ -41,6 +44,7 @@ public class ServerCaseDataSourceInfoProvider implements Provider<DataSourceInfo private static final String PROPERTIES_FILE = "connection.properties"; private static final String CONNECTION_NAME_KEY = "cayenneTestConnection"; + private static final String CONNECTION_DB_VERSION = "cayenneTestDbVersion"; private static final String ADAPTER_KEY_MAVEN = "cayenneAdapter"; private static final String USER_NAME_KEY_MAVEN = "cayenneJdbcUsername"; @@ -51,8 +55,12 @@ public class ServerCaseDataSourceInfoProvider implements Provider<DataSourceInfo private Map<String, DataSourceInfo> inMemoryDataSources; private ConnectionProperties connectionProperties; - public ServerCaseDataSourceInfoProvider() throws IOException { + private final Map<String, TestContainerProvider> testContainerProviders; + public ServerCaseDataSourceInfoProvider(@Inject Map<String, TestContainerProvider> testContainerProviders) + throws IOException { + + this.testContainerProviders = testContainerProviders; Map<String, String> propertiesMap = new HashMap<>(); File file = connectionPropertiesFile(); @@ -126,6 +134,10 @@ public class ServerCaseDataSourceInfoProvider implements Provider<DataSourceInfo connectionInfo = inMemoryDataSources.get(connectionKey); } + if (connectionInfo == null) { + connectionInfo = checkTestContainersDataSource(connectionKey); + } + connectionInfo = applyOverrides(connectionInfo); if (connectionInfo == null) { @@ -136,6 +148,33 @@ public class ServerCaseDataSourceInfoProvider implements Provider<DataSourceInfo return connectionInfo; } + private DataSourceInfo checkTestContainersDataSource(String connectionKey) { + // special case for the testcontainers profile + if (!connectionKey.endsWith("-tc")) { + return null; + } + + String db = connectionKey.substring(0, connectionKey.length() - 3); + + TestContainerProvider testContainerProvider = testContainerProviders.get(db); + if(testContainerProvider == null) { + return null; + } + + String version = property(CONNECTION_DB_VERSION); + JdbcDatabaseContainer<?> container = testContainerProvider.startContainer(version); + + DataSourceInfo sourceInfo = new DataSourceInfo(); + sourceInfo.setAdapterClassName(testContainerProvider.getAdapterClass().getName()); + sourceInfo.setUserName(container.getUsername()); + sourceInfo.setPassword(container.getPassword()); + sourceInfo.setDataSourceUrl(container.getJdbcUrl()); + sourceInfo.setJdbcDriver(container.getDriverClassName()); + sourceInfo.setMinConnections(ConnectionProperties.MIN_CONNECTIONS); + sourceInfo.setMaxConnections(ConnectionProperties.MAX_CONNECTIONS); + return sourceInfo; + } + private File connectionPropertiesFile() { return new File(cayenneUserDir(), PROPERTIES_FILE); } diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java index 83ce2b6..27a8e5a 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java @@ -135,6 +135,13 @@ import org.apache.cayenne.unit.SybaseUnitDbAdapter; import org.apache.cayenne.unit.UnitDbAdapter; import org.apache.cayenne.unit.di.DataChannelInterceptor; import org.apache.cayenne.unit.di.UnitTestLifecycleManager; +import org.apache.cayenne.unit.testcontainers.Db2ContainerProvider; +import org.apache.cayenne.unit.testcontainers.MariaDbContainerProvider; +import org.apache.cayenne.unit.testcontainers.MysqlContainerProvider; +import org.apache.cayenne.unit.testcontainers.OracleContainerProvider; +import org.apache.cayenne.unit.testcontainers.PostgresContainerProvider; +import org.apache.cayenne.unit.testcontainers.SqlServerContainerProvider; +import org.apache.cayenne.unit.testcontainers.TestContainerProvider; import org.apache.cayenne.unit.util.SQLTemplateCustomizer; import org.xml.sax.XMLReader; @@ -237,6 +244,14 @@ public class ServerCaseModule implements Module { // singleton objects binder.bind(UnitTestLifecycleManager.class).toInstance(new ServerCaseLifecycleManager(testScope)); + binder.bindMap(TestContainerProvider.class) + .put("mysql", MysqlContainerProvider.class) + .put("mariadb", MariaDbContainerProvider.class) + .put("postgres", PostgresContainerProvider.class) + .put("sqlserver", SqlServerContainerProvider.class) + .put("oracle", OracleContainerProvider.class) + .put("db2", Db2ContainerProvider.class); + binder.bind(DataSourceInfo.class).toProvider(ServerCaseDataSourceInfoProvider.class); binder.bind(DataSourceFactory.class).to(ServerCaseSharedDataSourceFactory.class); binder.bind(DbAdapter.class).toProvider(ServerCaseDbAdapterProvider.class); diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/Db2ContainerProvider.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/Db2ContainerProvider.java new file mode 100644 index 0000000..e286362 --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/Db2ContainerProvider.java @@ -0,0 +1,41 @@ +package org.apache.cayenne.unit.testcontainers; + +import java.time.Duration; + +import org.apache.cayenne.dba.JdbcAdapter; +import org.apache.cayenne.dba.db2.DB2Adapter; +import org.testcontainers.containers.Db2Container; +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.utility.DockerImageName; + +public class Db2ContainerProvider extends TestContainerProvider { + + @Override + public JdbcDatabaseContainer<?> startContainer(String version) { + JdbcDatabaseContainer<?> container = super.startContainer(version); + // need to wait to ensure Oracle DB has started + try { + Thread.sleep(40000); + } catch (InterruptedException ignored) { + } + return container; + } + + @Override + JdbcDatabaseContainer<?> createContainer(DockerImageName dockerImageName) { + return new Db2Container(dockerImageName) + .withStartupTimeout(Duration.ofMinutes(15)) + .withDatabaseName("testdb") + .acceptLicense(); + } + + @Override + String getDockerImage() { + return "ibmcom/db2"; + } + + @Override + public Class<? extends JdbcAdapter> getAdapterClass() { + return DB2Adapter.class; + } +} diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/MariaDbContainerProvider.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/MariaDbContainerProvider.java new file mode 100644 index 0000000..3630d87 --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/MariaDbContainerProvider.java @@ -0,0 +1,25 @@ +package org.apache.cayenne.unit.testcontainers; + +import org.apache.cayenne.dba.JdbcAdapter; +import org.apache.cayenne.dba.mysql.MySQLAdapter; +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.containers.MariaDBContainer; +import org.testcontainers.utility.DockerImageName; + +public class MariaDbContainerProvider extends TestContainerProvider { + + @Override + JdbcDatabaseContainer<?> createContainer(DockerImageName dockerImageName) { + return new MariaDBContainer<>(dockerImageName); + } + + @Override + String getDockerImage() { + return "mariadb:10.3"; + } + + @Override + public Class<? extends JdbcAdapter> getAdapterClass() { + return MySQLAdapter.class; + } +} diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/MysqlContainerProvider.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/MysqlContainerProvider.java new file mode 100644 index 0000000..eef3535 --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/MysqlContainerProvider.java @@ -0,0 +1,34 @@ +package org.apache.cayenne.unit.testcontainers; + +import java.util.Calendar; + +import org.apache.cayenne.dba.JdbcAdapter; +import org.apache.cayenne.dba.mysql.MySQLAdapter; +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.containers.MySQLContainer; +import org.testcontainers.utility.DockerImageName; + +public class MysqlContainerProvider extends TestContainerProvider { + + @Override + JdbcDatabaseContainer<?> createContainer(DockerImageName dockerImageName) { + return new MySQLContainer<>(dockerImageName) + .withUrlParam("useUnicode", "true") + .withUrlParam("characterEncoding", "UTF-8") + .withUrlParam("generateSimpleParameterMetadata", "true") + .withUrlParam("useLegacyDatetimeCode", "false") + .withUrlParam("serverTimezone", Calendar.getInstance().getTimeZone().getID()) + .withCommand("--character-set-server=utf8mb4") + .withCommand("--max-allowed-packet=5242880"); + } + + @Override + String getDockerImage() { + return "mysql:8"; + } + + @Override + public Class<? extends JdbcAdapter> getAdapterClass() { + return MySQLAdapter.class; + } +} diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/OracleContainerProvider.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/OracleContainerProvider.java new file mode 100644 index 0000000..c7c66f6 --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/OracleContainerProvider.java @@ -0,0 +1,41 @@ +package org.apache.cayenne.unit.testcontainers; + +import java.time.Duration; + +import org.apache.cayenne.dba.JdbcAdapter; +import org.apache.cayenne.dba.oracle.OracleAdapter; +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.containers.OracleContainer; +import org.testcontainers.utility.DockerImageName; + +public class OracleContainerProvider extends TestContainerProvider { + + @Override + public JdbcDatabaseContainer<?> startContainer(String version) { + JdbcDatabaseContainer<?> container = super.startContainer(version); + // need to wait to ensure Oracle DB has started + try { + Thread.sleep(40000); + } catch (InterruptedException ignored) { + } + return container; + } + + @Override + JdbcDatabaseContainer<?> createContainer(DockerImageName dockerImageName) { + return new OracleContainer(dockerImageName) + .withStartupTimeout(Duration.ofMinutes(5)) + .withEnv("ORACLE_ALLOW_REMOTE", "true") + .withEnv("ORACLE_DISABLE_ASYNCH_IO", "true"); + } + + @Override + String getDockerImage() { + return "oracleinanutshell/oracle-xe-11g"; + } + + @Override + public Class<? extends JdbcAdapter> getAdapterClass() { + return OracleAdapter.class; + } +} diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/PostgresContainerProvider.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/PostgresContainerProvider.java new file mode 100644 index 0000000..a6b11b9 --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/PostgresContainerProvider.java @@ -0,0 +1,24 @@ +package org.apache.cayenne.unit.testcontainers; + +import org.apache.cayenne.dba.JdbcAdapter; +import org.apache.cayenne.dba.postgres.PostgresAdapter; +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.utility.DockerImageName; + +public class PostgresContainerProvider extends TestContainerProvider { + @Override + JdbcDatabaseContainer<?> createContainer(DockerImageName dockerImageName) { + return new PostgreSQLContainer<>(dockerImageName); + } + + @Override + String getDockerImage() { + return "postgres:9"; + } + + @Override + public Class<? extends JdbcAdapter> getAdapterClass() { + return PostgresAdapter.class; + } +} diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/SqlServerContainerProvider.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/SqlServerContainerProvider.java new file mode 100644 index 0000000..8123cd2 --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/SqlServerContainerProvider.java @@ -0,0 +1,25 @@ +package org.apache.cayenne.unit.testcontainers; + +import org.apache.cayenne.dba.JdbcAdapter; +import org.apache.cayenne.dba.sqlserver.SQLServerAdapter; +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.containers.MSSQLServerContainer; +import org.testcontainers.utility.DockerImageName; + +public class SqlServerContainerProvider extends TestContainerProvider { + @Override + JdbcDatabaseContainer<?> createContainer(DockerImageName dockerImageName) { + return new MSSQLServerContainer<>(dockerImageName) + .acceptLicense(); + } + + @Override + String getDockerImage() { + return "mcr.microsoft.com/mssql/server"; + } + + @Override + public Class<? extends JdbcAdapter> getAdapterClass() { + return SQLServerAdapter.class; + } +} diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/TestContainerProvider.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/TestContainerProvider.java new file mode 100644 index 0000000..7991272 --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/testcontainers/TestContainerProvider.java @@ -0,0 +1,25 @@ +package org.apache.cayenne.unit.testcontainers; + +import org.apache.cayenne.dba.JdbcAdapter; +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.utility.DockerImageName; + +public abstract class TestContainerProvider { + + abstract JdbcDatabaseContainer<?> createContainer(DockerImageName dockerImageName); + + abstract String getDockerImage(); + + public abstract Class<? extends JdbcAdapter> getAdapterClass(); + + public JdbcDatabaseContainer<?> startContainer(String version) { + DockerImageName dockerImageName = DockerImageName.parse(getDockerImage()); + if(version != null) { + dockerImageName = dockerImageName.withTag(version); + } + JdbcDatabaseContainer<?> container = createContainer(dockerImageName); + container.start(); + return container; + } + +} diff --git a/pom.xml b/pom.xml index f739e89..4b9e865 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,8 @@ specific language governing permissions and limitations under the License. --> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <artifactId>cayenne-parent</artifactId> @@ -40,6 +41,7 @@ <jacoco.version>0.7.9</jacoco.version> <slf4j.version>1.7.25</slf4j.version> <ant.version>1.10.7</ant.version> + <testcontainers.version>1.16.0</testcontainers.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> @@ -496,6 +498,48 @@ <version>1.1.1</version> <scope>provided</scope> </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>testcontainers</artifactId> + <version>${testcontainers.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>mysql</artifactId> + <version>${testcontainers.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>mariadb</artifactId> + <version>${testcontainers.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>postgresql</artifactId> + <version>${testcontainers.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>oracle-xe</artifactId> + <version>${testcontainers.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>mssqlserver</artifactId> + <version>${testcontainers.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>db2</artifactId> + <version>${testcontainers.version}</version> + <scope>test</scope> + </dependency> </dependencies> </dependencyManagement> @@ -1350,138 +1394,44 @@ <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> - <version>5.1.42</version> + <version>8.0.24</version> <scope>test</scope> </dependency> </dependencies> </profile> <profile> - <id>mysql-docker</id> + <id>mysql-tc</id> <activation> <property> <name>cayenneTestConnection</name> - <value>mysql-docker</value> + <value>mysql-tc</value> </property> </activation> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> - <version>5.1.42</version> + <version>8.0.24</version> <scope>test</scope> </dependency> </dependencies> - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-failsafe-plugin</artifactId> - <configuration> - <systemPropertyVariables> - <!-- See https://hub.docker.com/_/mysql/ for details--> - <!-- ${db.host} and ${db.port} are dynamically set by docker-maven-plugin below --> - <cayenneAdapter>org.apache.cayenne.dba.mysql.MySQLAdapter</cayenneAdapter> - <cayenneJdbcUsername>root</cayenneJdbcUsername> - <cayenneJdbcPassword /> - <cayenneJdbcUrl>jdbc:mysql://${db.host}:${db.port}/cayenne?useUnicode=true&characterEncoding=UTF-8&generateSimpleParameterMetadata=true&useSSL=false</cayenneJdbcUrl> - <cayenneJdbcDriver>com.mysql.jdbc.Driver</cayenneJdbcDriver> - </systemPropertyVariables> - </configuration> - </plugin> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <configuration> - <images> - <image> - <alias>db</alias> - <name>mysql:5.7</name> - <run> - <ports> - <port>${db.host}:${db.port}:3306</port> - </ports> - <wait> - <log>MySQL init process done. Ready for start up.</log> - <time>60000</time> - </wait> - <env> - <MYSQL_ALLOW_EMPTY_PASSWORD>yes</MYSQL_ALLOW_EMPTY_PASSWORD> - <MYSQL_DATABASE>cayenne</MYSQL_DATABASE> - </env> - <cmd> - --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci - </cmd> - </run> - </image> - </images> - </configuration> - </plugin> - </plugins> - </build> </profile> <profile> - <id>mariadb-docker</id> + <id>mariadb-tc</id> <activation> <property> <name>cayenneTestConnection</name> - <value>mariadb-docker</value> + <value>mariadb-tc</value> </property> </activation> <dependencies> <dependency> - <groupId>mysql</groupId> - <artifactId>mysql-connector-java</artifactId> - <version>5.1.42</version> + <groupId>org.mariadb.jdbc</groupId> + <artifactId>mariadb-java-client</artifactId> + <version>2.7.4</version> <scope>test</scope> </dependency> </dependencies> - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-failsafe-plugin</artifactId> - <configuration> - <systemPropertyVariables> - <!-- See https://hub.docker.com/_/mariadb/ for details--> - <!-- ${db.host} and ${db.port} are dynamically set by docker-maven-plugin below --> - <cayenneAdapter>org.apache.cayenne.dba.mysql.MySQLAdapter</cayenneAdapter> - <cayenneJdbcUsername>root</cayenneJdbcUsername> - <cayenneJdbcPassword /> - <cayenneJdbcUrl>jdbc:mysql://${db.host}:${db.port}/cayenne?useUnicode=true&characterEncoding=UTF-8&generateSimpleParameterMetadata=true&useSSL=false</cayenneJdbcUrl> - <cayenneJdbcDriver>com.mysql.jdbc.Driver</cayenneJdbcDriver> - </systemPropertyVariables> - </configuration> - </plugin> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <configuration> - <images> - <image> - <alias>db</alias> - <name>mariadb:10.4</name> - <run> - <ports> - <port>${db.host}:${db.port}:3306</port> - </ports> - <wait> - <log>MySQL init process done. Ready for start up.</log> - <time>60000</time> - </wait> - <env> - <MYSQL_ALLOW_EMPTY_PASSWORD>yes</MYSQL_ALLOW_EMPTY_PASSWORD> - <MYSQL_DATABASE>cayenne</MYSQL_DATABASE> - </env> - <cmd> - --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci - </cmd> - </run> - </image> - </images> - </configuration> - </plugin> - </plugins> - </build> </profile> <profile> <id>oracle</id> @@ -1491,11 +1441,48 @@ <value>oracle</value> </property> </activation> + <dependencyManagement> + <dependencies> + <dependency> + <groupId>com.oracle.database.jdbc</groupId> + <artifactId>ojdbc-bom</artifactId> + <version>21.1.0.0</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + <dependencies> + <dependency> + <groupId>com.oracle.database.jdbc</groupId> + <artifactId>ojdbc8</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + </profile> + <profile> + <id>oracle-tc</id> + <activation> + <property> + <name>cayenneTestConnection</name> + <value>oracle-tc</value> + </property> + </activation> + <dependencyManagement> + <dependencies> + <dependency> + <groupId>com.oracle.database.jdbc</groupId> + <artifactId>ojdbc-bom</artifactId> + <version>21.1.0.0</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> <dependencies> <dependency> - <groupId>com.oracle</groupId> - <artifactId>oracle-driver</artifactId> - <version>11</version> + <groupId>com.oracle.database.jdbc</groupId> + <artifactId>ojdbc8</artifactId> <scope>test</scope> </dependency> </dependencies> @@ -1512,70 +1499,27 @@ <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> - <version>9.4.1212.jre7</version> + <version>42.2.12</version> <scope>test</scope> </dependency> </dependencies> </profile> <profile> - <id>postgres-docker</id> + <id>postgres-tc</id> <activation> <property> <name>cayenneTestConnection</name> - <value>postgres-docker</value> + <value>postgres-tc</value> </property> </activation> <dependencies> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> - <version>9.4.1212.jre7</version> + <version>42.2.12</version> <scope>test</scope> </dependency> </dependencies> - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-failsafe-plugin</artifactId> - <configuration> - <systemPropertyVariables> - <!-- Default user, password, and DB name is "postgres", see https://hub.docker.com/_/postgres/ --> - <!-- ${db.host} and ${db.port} are dynamically set by docker-maven-plugin below --> - <cayenneAdapter>org.apache.cayenne.dba.postgres.PostgresAdapter</cayenneAdapter> - <cayenneJdbcUsername>postgres</cayenneJdbcUsername> - <cayenneJdbcPassword>postgres</cayenneJdbcPassword> - <cayenneJdbcUrl>jdbc:postgresql://${db.host}:${db.port}/postgres</cayenneJdbcUrl> - <cayenneJdbcDriver>org.postgresql.Driver</cayenneJdbcDriver> - </systemPropertyVariables> - </configuration> - </plugin> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <configuration> - <images> - <image> - <alias>db</alias> - <name>postgres:12</name> - <run> - <env> - <POSTGRES_HOST_AUTH_METHOD>trust</POSTGRES_HOST_AUTH_METHOD> - </env> - <ports> - <port>${db.host}:${db.port}:5432</port> - </ports> - <wait> - <log>PostgreSQL init process complete; ready for start up.</log> - <time>60000</time> - </wait> - </run> - </image> - </images> - </configuration> - </plugin> - </plugins> - </build> </profile> <profile> <id>derby</id> @@ -1604,73 +1548,27 @@ <dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>mssql-jdbc</artifactId> - <version>7.0.0.jre8</version> + <version>9.2.1.jre8</version> <scope>test</scope> </dependency> </dependencies> </profile> <profile> - <id>sqlserver-docker</id> + <id>sqlserver-tc</id> <activation> <property> <name>cayenneTestConnection</name> - <value>sqlserver-docker</value> + <value>sqlserver-tc</value> </property> </activation> <dependencies> <dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>mssql-jdbc</artifactId> - <version>7.0.0.jre8</version> + <version>9.2.1.jre8</version> <scope>test</scope> </dependency> </dependencies> - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-failsafe-plugin</artifactId> - <configuration> - <systemPropertyVariables> - <!-- ${db.host} and ${db.port} are dynamically set by docker-maven-plugin below --> - <cayenneAdapter>org.apache.cayenne.dba.sqlserver.SQLServerAdapter</cayenneAdapter> - <cayenneJdbcUsername>sa</cayenneJdbcUsername> - <cayenneJdbcPassword>Cayenne#123</cayenneJdbcPassword> - <cayenneJdbcUrl>jdbc:sqlserver://${sqlserver.host}:${sqlserver.port};</cayenneJdbcUrl> - <cayenneJdbcDriver>com.microsoft.sqlserver.jdbc.SQLServerDriver</cayenneJdbcDriver> - <cayenne.runtime.db.collation.assume.ci>true</cayenne.runtime.db.collation.assume.ci> - </systemPropertyVariables> - </configuration> - </plugin> - <plugin> - <groupId>io.fabric8</groupId> - <artifactId>docker-maven-plugin</artifactId> - <configuration> - <verbose>true</verbose> - <images> - <image> - <alias>sqlserver</alias> - <name>microsoft/mssql-server-linux:2017-latest</name> - <run> - <ports> - <port>${sqlserver.host}:${sqlserver.port}:1433</port> - </ports> - <env> - <ACCEPT_EULA>Y</ACCEPT_EULA> - <SA_PASSWORD>Cayenne#123</SA_PASSWORD> - </env> - <wait> - <log>SQL Server is now ready for client connections.</log> - <time>60000</time> - </wait> - <cmd>/opt/mssql/bin/sqlservr</cmd> - </run> - </image> - </images> - </configuration> - </plugin> - </plugins> - </build> </profile> <profile> <id>ingres</id> @@ -1719,6 +1617,7 @@ <groupId>org.xerial</groupId> <artifactId>sqlite-jdbc</artifactId> <version>3.25.2</version> + <scope>test</scope> </dependency> </dependencies> </profile> @@ -1740,6 +1639,23 @@ </dependencies> </profile> <profile> + <id>db2-tc</id> + <activation> + <property> + <name>cayenneTestConnection</name> + <value>db2-tc</value> + </property> + </activation> + <dependencies> + <dependency> + <groupId>com.ibm.db2</groupId> + <artifactId>jcc</artifactId> + <version>11.5.6.0</version> + <scope>test</scope> + </dependency> + </dependencies> + </profile> + <profile> <id>java8-disable-strict-javadoc</id> <activation> <jdk>[1.8,)</jdk>