Browse Source

Upgrade to R2DBC 0.9.

Remove MySQL support as the MySQL driver is not yet published. Update groupId for Postgres driver to org.postgresql.

See #710
pull/1188/head
Mark Paluch 4 years ago
parent
commit
907f4865b5
No known key found for this signature in database
GPG Key ID: 4406B84C1661DCD1
  1. 10
      pom.xml
  2. 4
      src/test/java/org/springframework/data/r2dbc/core/ReactiveDataAccessStrategyTestSupport.java
  3. 5
      src/test/java/org/springframework/data/r2dbc/dialect/DialectResolverUnitTests.java
  4. 5
      src/test/java/org/springframework/data/r2dbc/repository/AbstractR2dbcRepositoryIntegrationTests.java
  5. 137
      src/test/java/org/springframework/data/r2dbc/repository/MySqlR2dbcRepositoryIntegrationTests.java
  6. 95
      src/test/java/org/springframework/data/r2dbc/repository/MySqlR2dbcRepositoryWithMixedCaseNamesIntegrationTests.java
  7. 160
      src/test/java/org/springframework/data/r2dbc/testing/MySqlTestSupport.java
  8. 28
      src/test/java/org/springframework/data/r2dbc/testing/StatementRecorder.java
  9. 8
      src/test/resources/org/springframework/data/r2dbc/connectionfactory/init/users-schema-h2.sql

10
pom.xml

@ -30,7 +30,7 @@ @@ -30,7 +30,7 @@
<degraph-check.version>0.1.4</degraph-check.version>
<postgresql.version>42.2.5</postgresql.version>
<mysql.version>8.0.21</mysql.version>
<r2dbc-spi-test.version>0.8.5.RELEASE</r2dbc-spi-test.version>
<r2dbc-spi-test.version>0.9.1.RELEASE</r2dbc-spi-test.version>
<mssql-jdbc.version>7.1.2.jre8-preview</mssql-jdbc.version>
<mariadb-jdbc.version>2.5.4</mariadb-jdbc.version>
<r2dbc-releasetrain.version>Borca-RELEASE</r2dbc-releasetrain.version>
@ -224,7 +224,7 @@ @@ -224,7 +224,7 @@
<!-- R2DBC Drivers -->
<dependency>
<groupId>io.r2dbc</groupId>
<groupId>org.postgresql</groupId>
<artifactId>r2dbc-postgresql</artifactId>
<optional>true</optional>
</dependency>
@ -241,12 +241,6 @@ @@ -241,12 +241,6 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>dev.miku</groupId>
<artifactId>r2dbc-mysql</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mariadb</groupId>
<artifactId>r2dbc-mariadb</artifactId>

4
src/test/java/org/springframework/data/r2dbc/core/ReactiveDataAccessStrategyTestSupport.java

@ -18,6 +18,8 @@ package org.springframework.data.r2dbc.core; @@ -18,6 +18,8 @@ package org.springframework.data.r2dbc.core;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import io.r2dbc.spi.Parameters;
import io.r2dbc.spi.R2dbcType;
import io.r2dbc.spi.Row;
import io.r2dbc.spi.RowMetadata;
import io.r2dbc.spi.test.MockColumnMetadata;
@ -198,7 +200,7 @@ public abstract class ReactiveDataAccessStrategyTestSupport { @@ -198,7 +200,7 @@ public abstract class ReactiveDataAccessStrategyTestSupport {
ReactiveDataAccessStrategy strategy = getStrategy();
Row rowMock = mock(Row.class);
RowMetadata metadataMock = MockRowMetadata.builder()
.columnMetadata(MockColumnMetadata.builder().name(fieldname).build()).build();
.columnMetadata(MockColumnMetadata.builder().name(fieldname).type(Parameters.in(testValue.getClass()).getType()).build()).build();
PrimitiveTypes toSave = new PrimitiveTypes();
setter.accept(toSave, testValue);

5
src/test/java/org/springframework/data/r2dbc/dialect/DialectResolverUnitTests.java

@ -2,8 +2,6 @@ package org.springframework.data.r2dbc.dialect; @@ -2,8 +2,6 @@ package org.springframework.data.r2dbc.dialect;
import static org.assertj.core.api.Assertions.*;
import dev.miku.r2dbc.mysql.MySqlConnectionConfiguration;
import dev.miku.r2dbc.mysql.MySqlConnectionFactory;
import io.r2dbc.h2.H2ConnectionConfiguration;
import io.r2dbc.h2.H2ConnectionFactory;
import io.r2dbc.mssql.MssqlConnectionConfiguration;
@ -41,13 +39,10 @@ public class DialectResolverUnitTests { @@ -41,13 +39,10 @@ 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());
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(mysql)).isEqualTo(MySqlDialect.INSTANCE);
}
@Test // gh-20, gh-104

5
src/test/java/org/springframework/data/r2dbc/repository/AbstractR2dbcRepositoryIntegrationTests.java

@ -24,6 +24,7 @@ import lombok.NoArgsConstructor; @@ -24,6 +24,7 @@ import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.Value;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Hooks;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
@ -60,6 +61,10 @@ import org.springframework.transaction.reactive.TransactionalOperator; @@ -60,6 +61,10 @@ import org.springframework.transaction.reactive.TransactionalOperator;
*/
public abstract class AbstractR2dbcRepositoryIntegrationTests extends R2dbcIntegrationTestSupport {
static {
Hooks.onOperatorDebug();
}
@Autowired private LegoSetRepository repository;
@Autowired private ConnectionFactory connectionFactory;
protected JdbcTemplate jdbc;

137
src/test/java/org/springframework/data/r2dbc/repository/MySqlR2dbcRepositoryIntegrationTests.java

@ -1,137 +0,0 @@ @@ -1,137 +0,0 @@
/*
* Copyright 2019-2021 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 lombok.AllArgsConstructor;
import lombok.Data;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import java.time.LocalDateTime;
import javax.sql.DataSource;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.springframework.beans.factory.annotation.Autowired;
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.dao.DataAccessException;
import org.springframework.data.annotation.Id;
import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration;
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
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.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
/**
* Integration tests for {@link LegoSetRepository} using {@link R2dbcRepositoryFactory} against MySQL.
*
* @author Mark Paluch
*/
@ExtendWith(SpringExtension.class)
@ContextConfiguration
public class MySqlR2dbcRepositoryIntegrationTests extends AbstractR2dbcRepositoryIntegrationTests {
@RegisterExtension public static final ExternalDatabase database = MySqlTestSupport.database();
@Autowired DateTestsRepository dateTestsRepository;
@Configuration
@EnableR2dbcRepositories(considerNestedRepositories = true,
includeFilters = { @Filter(classes = MySqlLegoSetRepository.class, type = FilterType.ASSIGNABLE_TYPE),
@Filter(classes = DateTestsRepository.class, type = FilterType.ASSIGNABLE_TYPE) })
static class IntegrationTestConfiguration extends AbstractR2dbcConfiguration {
@Bean
@Override
public ConnectionFactory connectionFactory() {
return MySqlTestSupport.createConnectionFactory(database);
}
}
@Override
protected DataSource createDataSource() {
return MySqlTestSupport.createDataSource(database);
}
@Override
protected ConnectionFactory createConnectionFactory() {
return MySqlTestSupport.createConnectionFactory(database);
}
@Override
protected String getCreateTableStatement() {
return MySqlTestSupport.CREATE_TABLE_LEGOSET_WITH_ID_GENERATION;
}
@Override
protected Class<? extends LegoSetRepository> getRepositoryInterfaceType() {
return MySqlLegoSetRepository.class;
}
@Test
public void shouldUserJsr310Types() {
JdbcTemplate jdbcTemplate = createJdbcTemplate(createDataSource());
try {
jdbcTemplate.execute("DROP TABLE date_tests");
} catch (DataAccessException e) {}
jdbcTemplate.execute("CREATE TABLE date_tests (id int, created_timestamp TIMESTAMP, created_date datetime);");
dateTestsRepository.save(new DateTests(null, LocalDateTime.now(), LocalDateTime.now())).as(StepVerifier::create)
.expectNextCount(1).verifyComplete();
}
@Data
@AllArgsConstructor
static class DateTests {
@Id Integer id;
LocalDateTime createdTimestamp;
LocalDateTime createdDate;
}
interface MySqlLegoSetRepository extends LegoSetRepository {
@Override
@Query("SELECT name FROM legoset")
Flux<Named> findAsProjection();
@Override
@Query("SELECT * FROM legoset WHERE manual = :manual")
Mono<LegoSet> findByManual(int manual);
@Override
@Query("SELECT id FROM legoset")
Flux<Integer> findAllIds();
}
interface DateTestsRepository extends ReactiveCrudRepository<DateTests, Integer> {
}
}

95
src/test/java/org/springframework/data/r2dbc/repository/MySqlR2dbcRepositoryWithMixedCaseNamesIntegrationTests.java

@ -1,95 +0,0 @@ @@ -1,95 +0,0 @@
/*
* Copyright 2021 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 java.util.Optional;
import javax.sql.DataSource;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;
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.convert.R2dbcCustomConversions;
import org.springframework.data.r2dbc.mapping.R2dbcMappingContext;
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
import org.springframework.data.r2dbc.testing.ExternalDatabase;
import org.springframework.data.r2dbc.testing.MySqlTestSupport;
import org.springframework.data.relational.core.mapping.NamingStrategy;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
/**
* Integration tests for {@link LegoSetRepository} with table and column names that contain upper and lower case
* characters against MySql.
*
* @author Jens Schauder
*/
@ExtendWith(SpringExtension.class)
@ContextConfiguration
public class MySqlR2dbcRepositoryWithMixedCaseNamesIntegrationTests
extends AbstractR2dbcRepositoryWithMixedCaseNamesIntegrationTests {
@RegisterExtension public static final ExternalDatabase database = MySqlTestSupport.database();
@Configuration
@EnableR2dbcRepositories(considerNestedRepositories = true,
includeFilters = @Filter(classes = { LegoSetRepository.class }, type = FilterType.ASSIGNABLE_TYPE))
static class IntegrationTestConfiguration extends AbstractR2dbcConfiguration {
@Bean
@Override
public ConnectionFactory connectionFactory() {
return MySqlTestSupport.createConnectionFactory(database);
}
@Override
public R2dbcMappingContext r2dbcMappingContext(Optional<NamingStrategy> namingStrategy,
R2dbcCustomConversions r2dbcCustomConversions) {
R2dbcMappingContext r2dbcMappingContext = super.r2dbcMappingContext(namingStrategy, r2dbcCustomConversions);
r2dbcMappingContext.setForceQuote(true);
return r2dbcMappingContext;
}
}
@Override
protected DataSource createDataSource() {
return MySqlTestSupport.createDataSource(database);
}
@Override
protected ConnectionFactory createConnectionFactory() {
return MySqlTestSupport.createConnectionFactory(database);
}
@Override
protected String getCreateTableStatement() {
return MySqlTestSupport.CREATE_TABLE_LEGOSET_WITH_MIXED_CASE_NAMES;
}
@Override
protected String getDropTableStatement() {
return MySqlTestSupport.DROP_TABLE_LEGOSET_WITH_MIXED_CASE_NAMES;
}
}

160
src/test/java/org/springframework/data/r2dbc/testing/MySqlTestSupport.java

@ -1,160 +0,0 @@ @@ -1,160 +0,0 @@
/*
* Copyright 2019-2021 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.testing;
import dev.miku.r2dbc.mysql.MySqlConnectionFactoryProvider;
import io.r2dbc.spi.ConnectionFactory;
import io.r2dbc.spi.ConnectionFactoryOptions;
import java.util.function.Supplier;
import java.util.stream.Stream;
import javax.sql.DataSource;
import org.springframework.data.r2dbc.testing.ExternalDatabase.ProvidedDatabase;
import org.testcontainers.containers.MySQLContainer;
import com.mysql.cj.jdbc.MysqlDataSource;
/**
* Utility class for testing against MySQL.
*
* @author Mark Paluch
* @author Bogdan Ilchyshyn
* @author Jens Schauder
*/
public class MySqlTestSupport {
private static ExternalDatabase testContainerDatabase;
public static String CREATE_TABLE_LEGOSET = "CREATE TABLE legoset (\n" //
+ " id integer PRIMARY KEY,\n" //
+ " version integer NULL,\n" //
+ " name varchar(255) NOT NULL,\n" //
+ " manual integer NULL\n," //
+ " cert varbinary(255) NULL\n" //
+ ") ENGINE=InnoDB;";
public static String CREATE_TABLE_LEGOSET_WITH_ID_GENERATION = "CREATE TABLE legoset (\n" //
+ " id integer AUTO_INCREMENT PRIMARY KEY,\n" //
+ " version integer NULL,\n" //
+ " name varchar(255) NOT NULL,\n" //
+ " flag boolean NULL,\n" //
+ " manual integer NULL\n" //
+ ") ENGINE=InnoDB;";
public static final String CREATE_TABLE_LEGOSET_WITH_MIXED_CASE_NAMES = "CREATE TABLE `LegoSet` (\n" //
+ " `Id` integer AUTO_INCREMENT PRIMARY KEY,\n" //
+ " `Name` varchar(255) NOT NULL,\n" //
+ " `Manual` integer NULL\n" //
+ ") ENGINE=InnoDB;";
public static final String DROP_TABLE_LEGOSET_WITH_MIXED_CASE_NAMES = "DROP TABLE LegoSet";
/**
* Returns a database either hosted locally or running inside Docker.
*
* @return information about the database. Guaranteed to be not {@literal null}.
*/
public static ExternalDatabase database() {
if (Boolean.getBoolean("spring.data.r2dbc.test.preferLocalDatabase")) {
return getFirstWorkingDatabase( //
MySqlTestSupport::local, //
MySqlTestSupport::testContainer //
);
} else {
return getFirstWorkingDatabase( //
MySqlTestSupport::testContainer, //
MySqlTestSupport::local //
);
}
}
@SafeVarargs
private static ExternalDatabase getFirstWorkingDatabase(Supplier<ExternalDatabase>... suppliers) {
return Stream.of(suppliers).map(Supplier::get) //
.filter(ExternalDatabase::checkValidity) //
.findFirst() //
.orElse(ExternalDatabase.unavailable());
}
/**
* Returns a locally provided database.
*/
private static ExternalDatabase local() {
return ProvidedDatabase.builder() //
.hostname("localhost") //
.port(3306) //
.database("mysql") //
.username("root") //
.password("my-secret-pw") //
.jdbcUrl("jdbc:mysql://localhost:3306/mysql?allowPublicKeyRetrieval=true") //
.build();
}
/**
* Returns a database provided via Testcontainers.
*/
private static ExternalDatabase testContainer() {
if (testContainerDatabase == null) {
try {
MySQLContainer container = new MySQLContainer("mysql:8.0.24");
container.start();
testContainerDatabase = ProvidedDatabase.builder(container) //
.database(container.getDatabaseName()) //
.username("root") //
.build();
} catch (IllegalStateException ise) {
// docker not available.
testContainerDatabase = ExternalDatabase.unavailable();
}
}
return testContainerDatabase;
}
/**
* Creates a new R2DBC MySQL {@link ConnectionFactory} configured from the {@link ExternalDatabase}.
*/
public static ConnectionFactory createConnectionFactory(ExternalDatabase database) {
ConnectionFactoryOptions options = ConnectionUtils.createOptions("mysql", database);
return new MySqlConnectionFactoryProvider().create(options);
}
/**
* Creates a new {@link DataSource} configured from the {@link ExternalDatabase}.
*/
public static DataSource createDataSource(ExternalDatabase database) {
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setUser(database.getUsername());
dataSource.setPassword(database.getPassword());
dataSource.setURL(database.getJdbcUrl() + "?useSSL=false&allowPublicKeyRetrieval=true");
return dataSource;
}
}

28
src/test/java/org/springframework/data/r2dbc/testing/StatementRecorder.java

@ -23,10 +23,12 @@ import io.r2dbc.spi.ConnectionMetadata; @@ -23,10 +23,12 @@ import io.r2dbc.spi.ConnectionMetadata;
import io.r2dbc.spi.IsolationLevel;
import io.r2dbc.spi.Result;
import io.r2dbc.spi.Statement;
import io.r2dbc.spi.TransactionDefinition;
import io.r2dbc.spi.ValidationDepth;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
@ -156,11 +158,17 @@ public class StatementRecorder implements ConnectionFactory { @@ -156,11 +158,17 @@ public class StatementRecorder implements ConnectionFactory {
}
class RecorderConnection implements Connection {
@Override
public Publisher<Void> beginTransaction() {
return createStatement("BEGIN").execute().then();
}
@Override
public Publisher<Void> beginTransaction(TransactionDefinition definition) {
return createStatement("BEGIN " + definition).execute().then();
}
@Override
public Publisher<Void> close() {
return createStatement("CLOSE").execute().then();
@ -238,6 +246,16 @@ public class StatementRecorder implements ConnectionFactory { @@ -238,6 +246,16 @@ public class StatementRecorder implements ConnectionFactory {
return createStatement("SET AUTOCOMMIT " + autoCommit).execute().then();
}
@Override
public Publisher<Void> setLockWaitTimeout(Duration timeout) {
return createStatement("SET LOCK WAIT TIMEOUT " + timeout).execute().then();
}
@Override
public Publisher<Void> setStatementTimeout(Duration timeout) {
return createStatement("SET STATEMENT TIMEOUT " + timeout).execute().then();
}
@Override
public Publisher<Void> setTransactionIsolationLevel(IsolationLevel isolationLevel) {
return createStatement("SET TRANSACTION ISOLATION LEVEL " + isolationLevel.asSql()).execute().then();
@ -307,6 +325,16 @@ public class StatementRecorder implements ConnectionFactory { @@ -307,6 +325,16 @@ public class StatementRecorder implements ConnectionFactory {
public Flux<Result> execute() {
return Flux.fromIterable(results).doOnSubscribe(subscription -> executedStatements.add(this));
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer();
sb.append(getClass().getSimpleName());
sb.append(" [sql='").append(sql).append('\'');
sb.append(", bindings=").append(bindings);
sb.append(']');
return sb.toString();
}
}
}

8
src/test/resources/org/springframework/data/r2dbc/connectionfactory/init/users-schema-h2.sql

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
DROP TABLE users IF EXISTS;
CREATE TABLE users
(
id INTEGER NOT NULL AUTO_INCREMENT,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL
);
Loading…
Cancel
Save