From e15e6b19d4919e120eac428f47062cc65a4b210b Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 15 Aug 2019 12:22:37 +0200 Subject: [PATCH] #163 - Add tests for R2DBC MySQL. --- pom.xml | 28 ++++- ...ncMySqlDatabaseClientIntegrationTests.java | 58 ++++++++++ ...ctionalDatabaseClientIntegrationTests.java | 78 ++++++++++++++ .../MySqlDatabaseClientIntegrationTests.java | 10 +- ...ctionalDatabaseClientIntegrationTests.java | 19 +++- .../dialect/DialectResolverUnitTests.java | 8 +- ...cMySqlR2dbcRepositoryIntegrationTests.java | 102 ++++++++++++++++++ .../data/r2dbc/testing/ConnectionUtils.java | 2 +- .../data/r2dbc/testing/MySqlTestSupport.java | 22 +++- 9 files changed, 305 insertions(+), 22 deletions(-) create mode 100644 src/test/java/org/springframework/data/r2dbc/core/JasyncMySqlDatabaseClientIntegrationTests.java create mode 100644 src/test/java/org/springframework/data/r2dbc/core/JasyncMySqlTransactionalDatabaseClientIntegrationTests.java create mode 100644 src/test/java/org/springframework/data/r2dbc/repository/JasyncMySqlR2dbcRepositoryIntegrationTests.java diff --git a/pom.xml b/pom.xml index 85485e4..f4aa287 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,7 @@ - + 4.0.0 @@ -30,6 +32,7 @@ 42.2.5 5.1.47 0.9.52 + 0.2.0.M2 7.1.2.jre8-preview Arabba-M8 1.0.1 @@ -171,6 +174,8 @@ test + + org.postgresql postgresql @@ -192,6 +197,8 @@ test + + io.r2dbc r2dbc-postgresql @@ -218,12 +225,14 @@ - de.schauderhaft.degraph - degraph-check - ${degraph-check.version} + com.github.mirromutth + r2dbc-mysql + ${r2dbc-mysql.version} test + + org.testcontainers mysql @@ -242,6 +251,13 @@ test + + de.schauderhaft.degraph + degraph-check + ${degraph-check.version} + test + + io.mockk mockk @@ -421,6 +437,10 @@ jcenter https://jcenter.bintray.com/ + + jitpack.io + https://jitpack.io + diff --git a/src/test/java/org/springframework/data/r2dbc/core/JasyncMySqlDatabaseClientIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/JasyncMySqlDatabaseClientIntegrationTests.java new file mode 100644 index 0000000..65b062c --- /dev/null +++ b/src/test/java/org/springframework/data/r2dbc/core/JasyncMySqlDatabaseClientIntegrationTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2019 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. + */ +package org.springframework.data.r2dbc.core; + +import io.r2dbc.spi.ConnectionFactory; + +import javax.sql.DataSource; + +import org.junit.ClassRule; +import org.junit.Ignore; +import org.junit.Test; + +import org.springframework.data.r2dbc.testing.ExternalDatabase; +import org.springframework.data.r2dbc.testing.MySqlTestSupport; + +/** + * Integration tests for {@link DatabaseClient} against MySQL using Jasync MySQL. + * + * @author Mark Paluch + */ +public class JasyncMySqlDatabaseClientIntegrationTests extends AbstractDatabaseClientIntegrationTests { + + @ClassRule public static final ExternalDatabase database = MySqlTestSupport.database(); + + @Override + protected DataSource createDataSource() { + return MySqlTestSupport.createDataSource(database); + } + + @Override + protected ConnectionFactory createConnectionFactory() { + return MySqlTestSupport.createJasyncConnectionFactory(database); + } + + @Override + protected String getCreateTableStatement() { + return MySqlTestSupport.CREATE_TABLE_LEGOSET; + } + + @Override + @Ignore("Jasync currently uses its own exceptions, see jasync-sql/jasync-sql#106") + @Test + public void shouldTranslateDuplicateKeyException() {} + +} diff --git a/src/test/java/org/springframework/data/r2dbc/core/JasyncMySqlTransactionalDatabaseClientIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/JasyncMySqlTransactionalDatabaseClientIntegrationTests.java new file mode 100644 index 0000000..68ad4ed --- /dev/null +++ b/src/test/java/org/springframework/data/r2dbc/core/JasyncMySqlTransactionalDatabaseClientIntegrationTests.java @@ -0,0 +1,78 @@ +/* + * Copyright 2019 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. + */ +package org.springframework.data.r2dbc.core; + +import io.r2dbc.spi.ConnectionFactory; +import reactor.core.publisher.Mono; + +import java.time.Duration; + +import javax.sql.DataSource; + +import org.junit.ClassRule; + +import org.springframework.data.r2dbc.testing.ExternalDatabase; +import org.springframework.data.r2dbc.testing.MySqlTestSupport; + +/** + * Transactional integration tests for {@link DatabaseClient} against MySQL using Jasync MySQL. + * + * @author Mark Paluch + */ +public class JasyncMySqlTransactionalDatabaseClientIntegrationTests + extends AbstractTransactionalDatabaseClientIntegrationTests { + + @ClassRule public static final ExternalDatabase database = MySqlTestSupport.database(); + + @Override + protected DataSource createDataSource() { + return MySqlTestSupport.createDataSource(database); + } + + @Override + protected ConnectionFactory createConnectionFactory() { + return MySqlTestSupport.createJasyncConnectionFactory(database); + } + + @Override + protected String getCreateTableStatement() { + return MySqlTestSupport.CREATE_TABLE_LEGOSET; + } + + @Override + protected Mono prepareForTransaction(DatabaseClient client) { + + /* + * We have to execute a sql statement first. + * Otherwise MySql don't have a transaction id. + * And we need to delay emitting the result so that MySql has time to write the transaction id, which is done in + * batches every now and then. + * @see: https://dev.mysql.com/doc/refman/5.7/en/innodb-information-schema-internal-data.html + */ + return client.execute(getInsertIntoLegosetStatement()) // + .bind(0, 42055) // + .bind(1, "SCHAUFELRADBAGGER") // + .bindNull(2, Integer.class) // + .fetch().rowsUpdated() // + .delayElement(Duration.ofMillis(50)) // + .then(); + } + + @Override + protected String getCurrentTransactionIdStatement() { + return "SELECT tx.trx_id FROM information_schema.innodb_trx tx WHERE tx.trx_mysql_thread_id = connection_id()"; + } +} diff --git a/src/test/java/org/springframework/data/r2dbc/core/MySqlDatabaseClientIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/MySqlDatabaseClientIntegrationTests.java index 3aaf86c..415ad36 100644 --- a/src/test/java/org/springframework/data/r2dbc/core/MySqlDatabaseClientIntegrationTests.java +++ b/src/test/java/org/springframework/data/r2dbc/core/MySqlDatabaseClientIntegrationTests.java @@ -20,9 +20,7 @@ import io.r2dbc.spi.ConnectionFactory; import javax.sql.DataSource; import org.junit.ClassRule; -import org.junit.Ignore; -import org.junit.Test; -import org.springframework.data.r2dbc.core.DatabaseClient; + import org.springframework.data.r2dbc.testing.ExternalDatabase; import org.springframework.data.r2dbc.testing.MySqlTestSupport; @@ -49,10 +47,4 @@ public class MySqlDatabaseClientIntegrationTests extends AbstractDatabaseClientI protected String getCreateTableStatement() { return MySqlTestSupport.CREATE_TABLE_LEGOSET; } - - @Override - @Ignore("Jasync currently uses its own exceptions, see jasync-sql/jasync-sql#106") - @Test - public void shouldTranslateDuplicateKeyException() {} - } diff --git a/src/test/java/org/springframework/data/r2dbc/core/MySqlTransactionalDatabaseClientIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/core/MySqlTransactionalDatabaseClientIntegrationTests.java index 65eb7b4..d88d993 100644 --- a/src/test/java/org/springframework/data/r2dbc/core/MySqlTransactionalDatabaseClientIntegrationTests.java +++ b/src/test/java/org/springframework/data/r2dbc/core/MySqlTransactionalDatabaseClientIntegrationTests.java @@ -15,17 +15,19 @@ */ package org.springframework.data.r2dbc.core; -import javax.sql.DataSource; +import io.r2dbc.spi.ConnectionFactory; +import reactor.core.publisher.Mono; + import java.time.Duration; -import io.r2dbc.spi.ConnectionFactory; +import javax.sql.DataSource; + import org.junit.ClassRule; import org.junit.Ignore; import org.junit.Test; import org.springframework.data.r2dbc.testing.ExternalDatabase; import org.springframework.data.r2dbc.testing.MySqlTestSupport; -import reactor.core.publisher.Mono; /** * Transactional integration tests for {@link DatabaseClient} against MySQL. @@ -71,6 +73,17 @@ public class MySqlTransactionalDatabaseClientIntegrationTests .then(); } + @Test + @Ignore("https://github.com/mirromutth/r2dbc-mysql/issues/45") + @Override + public void emitTransactionIds() {} + + @Test + @Ignore("https://github.com/mirromutth/r2dbc-mysql/issues/45") + public void emitTransactionIdsUsingManagedTransactions() { + super.emitTransactionIdsUsingManagedTransactions(); + } + @Override protected String getCurrentTransactionIdStatement() { return "SELECT tx.trx_id FROM information_schema.innodb_trx tx WHERE tx.trx_mysql_thread_id = connection_id()"; diff --git a/src/test/java/org/springframework/data/r2dbc/dialect/DialectResolverUnitTests.java b/src/test/java/org/springframework/data/r2dbc/dialect/DialectResolverUnitTests.java index 29fa29a..6691faf 100644 --- a/src/test/java/org/springframework/data/r2dbc/dialect/DialectResolverUnitTests.java +++ b/src/test/java/org/springframework/data/r2dbc/dialect/DialectResolverUnitTests.java @@ -3,6 +3,8 @@ package org.springframework.data.r2dbc.dialect; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; +import io.github.mirromutth.r2dbc.mysql.MySqlConnectionConfiguration; +import io.github.mirromutth.r2dbc.mysql.MySqlConnectionFactory; import io.r2dbc.h2.H2ConnectionConfiguration; import io.r2dbc.h2.H2ConnectionFactory; import io.r2dbc.mssql.MssqlConnectionConfiguration; @@ -24,6 +26,7 @@ import org.springframework.data.relational.core.sql.render.SelectRenderContext; import com.github.jasync.r2dbc.mysql.JasyncConnectionFactory; import com.github.jasync.sql.db.mysql.pool.MySQLConnectionFactory; +import reactor.core.publisher.Mono; /** * Unit tests for {@link DialectResolver}. @@ -40,11 +43,14 @@ public class DialectResolverUnitTests { MssqlConnectionFactory mssql = new MssqlConnectionFactory(MssqlConnectionConfiguration.builder().host("localhost") .database("foo").username("bar").password("password").build()); H2ConnectionFactory h2 = new H2ConnectionFactory(H2ConnectionConfiguration.builder().inMemory("mem").build()); - JasyncConnectionFactory mysql = new JasyncConnectionFactory(mock(MySQLConnectionFactory.class)); + JasyncConnectionFactory jasyncMysql = new JasyncConnectionFactory(mock(MySQLConnectionFactory.class)); + MySqlConnectionFactory mysql = MySqlConnectionFactory + .from(MySqlConnectionConfiguration.builder().host("localhost").username("mysql").build()); assertThat(DialectResolver.getDialect(postgres)).isEqualTo(PostgresDialect.INSTANCE); assertThat(DialectResolver.getDialect(mssql)).isEqualTo(SqlServerDialect.INSTANCE); assertThat(DialectResolver.getDialect(h2)).isEqualTo(H2Dialect.INSTANCE); + assertThat(DialectResolver.getDialect(jasyncMysql)).isEqualTo(MySqlDialect.INSTANCE); assertThat(DialectResolver.getDialect(mysql)).isEqualTo(MySqlDialect.INSTANCE); } diff --git a/src/test/java/org/springframework/data/r2dbc/repository/JasyncMySqlR2dbcRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/r2dbc/repository/JasyncMySqlR2dbcRepositoryIntegrationTests.java new file mode 100644 index 0000000..486ea28 --- /dev/null +++ b/src/test/java/org/springframework/data/r2dbc/repository/JasyncMySqlR2dbcRepositoryIntegrationTests.java @@ -0,0 +1,102 @@ +/* + * Copyright 2019 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. + */ +package org.springframework.data.r2dbc.repository; + +import io.r2dbc.spi.ConnectionFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import javax.sql.DataSource; + +import org.junit.ClassRule; +import org.junit.runner.RunWith; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration; +import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories; +import org.springframework.data.r2dbc.repository.query.Query; +import org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactory; +import org.springframework.data.r2dbc.testing.ExternalDatabase; +import org.springframework.data.r2dbc.testing.MySqlTestSupport; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * Integration tests for {@link LegoSetRepository} using {@link R2dbcRepositoryFactory} against MySQL using Jasync + * MySQL. + * + * @author Mark Paluch + */ +@RunWith(SpringRunner.class) +@ContextConfiguration +public class JasyncMySqlR2dbcRepositoryIntegrationTests extends AbstractR2dbcRepositoryIntegrationTests { + + @ClassRule public static final ExternalDatabase database = MySqlTestSupport.database(); + + @Configuration + @EnableR2dbcRepositories(considerNestedRepositories = true, + includeFilters = @Filter(classes = MySqlLegoSetRepository.class, type = FilterType.ASSIGNABLE_TYPE)) + static class IntegrationTestConfiguration extends AbstractR2dbcConfiguration { + + @Bean + @Override + public ConnectionFactory connectionFactory() { + return MySqlTestSupport.createJasyncConnectionFactory(database); + } + } + + @Override + protected DataSource createDataSource() { + return MySqlTestSupport.createDataSource(database); + } + + @Override + protected ConnectionFactory createConnectionFactory() { + return MySqlTestSupport.createJasyncConnectionFactory(database); + } + + @Override + protected String getCreateTableStatement() { + return MySqlTestSupport.CREATE_TABLE_LEGOSET_WITH_ID_GENERATION; + } + + @Override + protected Class getRepositoryInterfaceType() { + return MySqlLegoSetRepository.class; + } + + interface MySqlLegoSetRepository extends LegoSetRepository { + + @Override + @Query("SELECT * FROM legoset WHERE name like ?") + Flux findByNameContains(String name); + + @Override + @Query("SELECT name FROM legoset") + Flux findAsProjection(); + + @Override + @Query("SELECT * FROM legoset WHERE manual = :manual") + Mono findByManual(int manual); + + @Override + @Query("SELECT id FROM legoset") + Flux findAllIds(); + } +} diff --git a/src/test/java/org/springframework/data/r2dbc/testing/ConnectionUtils.java b/src/test/java/org/springframework/data/r2dbc/testing/ConnectionUtils.java index a0725e8..9eb8c00 100644 --- a/src/test/java/org/springframework/data/r2dbc/testing/ConnectionUtils.java +++ b/src/test/java/org/springframework/data/r2dbc/testing/ConnectionUtils.java @@ -48,7 +48,7 @@ abstract class ConnectionUtils { * @param configuration * @return */ - private static ConnectionFactoryOptions createOptions(String driver, ExternalDatabase configuration) { + static ConnectionFactoryOptions createOptions(String driver, ExternalDatabase configuration) { return ConnectionFactoryOptions.builder().option(DRIVER, driver) // .option(USER, configuration.getUsername()) // diff --git a/src/test/java/org/springframework/data/r2dbc/testing/MySqlTestSupport.java b/src/test/java/org/springframework/data/r2dbc/testing/MySqlTestSupport.java index 387dc40..6221f6a 100644 --- a/src/test/java/org/springframework/data/r2dbc/testing/MySqlTestSupport.java +++ b/src/test/java/org/springframework/data/r2dbc/testing/MySqlTestSupport.java @@ -15,7 +15,9 @@ */ package org.springframework.data.r2dbc.testing; +import io.github.mirromutth.r2dbc.mysql.MySqlConnectionFactoryProvider; import io.r2dbc.spi.ConnectionFactory; +import io.r2dbc.spi.ConnectionFactoryOptions; import java.util.function.Supplier; import java.util.stream.Stream; @@ -26,6 +28,7 @@ import org.springframework.data.r2dbc.testing.ExternalDatabase.ProvidedDatabase; import org.testcontainers.containers.MySQLContainer; +import com.github.jasync.r2dbc.mysql.MysqlConnectionFactoryProvider; import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; /** @@ -90,7 +93,7 @@ public class MySqlTestSupport { .port(3306) // .database("mysql") // .username("root") // - .password("my-secret-pw").build(); + .password("my-secret-pw").jdbcUrl("jdbc:mysql://localhost:3306/mysql").build(); } /** @@ -101,7 +104,7 @@ public class MySqlTestSupport { if (testContainerDatabase == null) { try { - MySQLContainer container = new MySQLContainer("mysql:5.6.43"); + MySQLContainer container = new MySQLContainer(); container.start(); testContainerDatabase = ProvidedDatabase.builder(container) // @@ -117,10 +120,21 @@ public class MySqlTestSupport { } /** - * Creates a new {@link ConnectionFactory} configured from the {@link ExternalDatabase}.. + * Creates a new Jasync MySQL {@link ConnectionFactory} configured from the {@link ExternalDatabase}. + */ + public static ConnectionFactory createJasyncConnectionFactory(ExternalDatabase database) { + + ConnectionFactoryOptions options = ConnectionUtils.createOptions("mysql", database); + return new MysqlConnectionFactoryProvider().create(options); + } + + /** + * Creates a new R2DBC MySQL {@link ConnectionFactory} configured from the {@link ExternalDatabase}. */ public static ConnectionFactory createConnectionFactory(ExternalDatabase database) { - return ConnectionUtils.getConnectionFactory("mysql", database); + + ConnectionFactoryOptions options = ConnectionUtils.createOptions("mysql", database); + return new MySqlConnectionFactoryProvider().create(options); } /**