#189 - Polishing.

Refactored DefaultDatabaseClientUnitTests in order to make the relevant differences in setup easier to spot.

Original pull request: #308.
This commit is contained in:
Jens Schauder
2020-02-25 11:17:40 +01:00
parent 6a8ab608e5
commit 4a5184830d

View File

@@ -39,47 +39,49 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscription;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.annotation.Id;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.r2dbc.dialect.PostgresDialect;
import org.springframework.data.r2dbc.mapping.SettableValue;
import org.springframework.data.r2dbc.support.R2dbcExceptionTranslator;
import org.springframework.lang.Nullable;
/**
* Unit tests for {@link DefaultDatabaseClient}.
*
* @author Mark Paluch
* @author Ferdinand Jacobs
* @author Jens Schauder
*/
@RunWith(MockitoJUnitRunner.class)
public class DefaultDatabaseClientUnitTests {
@Mock ConnectionFactory connectionFactory;
@Mock Connection connection;
@Mock R2dbcExceptionTranslator translator;
private DatabaseClient.Builder databaseClientBuilder;
@Before
public void before() {
ConnectionFactory connectionFactory = Mockito.mock(ConnectionFactory.class);
when(connectionFactory.create()).thenReturn((Publisher) Mono.just(connection));
when(connection.close()).thenReturn(Mono.empty());
databaseClientBuilder = DatabaseClient.builder() //
.connectionFactory(connectionFactory) //
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE));
}
@Test // gh-48
public void shouldCloseConnectionOnlyOnce() {
DefaultDatabaseClient databaseClient = (DefaultDatabaseClient) DatabaseClient.builder()
.connectionFactory(connectionFactory)
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE))
.exceptionTranslator(translator).build();
DefaultDatabaseClient databaseClient = (DefaultDatabaseClient) databaseClientBuilder.build();
Flux<Object> flux = databaseClient.inConnectionMany(it -> {
return Flux.empty();
});
Flux<Object> flux = databaseClient.inConnectionMany(it -> Flux.empty());
flux.subscribe(new CoreSubscriber<Object>() {
Subscription subscription;
@@ -108,13 +110,9 @@ public class DefaultDatabaseClientUnitTests {
@Test // gh-128
public void executeShouldBindNullValues() {
Statement statement = mock(Statement.class);
when(connection.createStatement("SELECT * FROM table WHERE key = $1")).thenReturn(statement);
when(statement.execute()).thenReturn(Mono.empty());
Statement statement = mockStatementFor("SELECT * FROM table WHERE key = $1");
DefaultDatabaseClient databaseClient = (DefaultDatabaseClient) DatabaseClient.builder()
.connectionFactory(connectionFactory)
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build();
DatabaseClient databaseClient = databaseClientBuilder.build();
databaseClient.execute("SELECT * FROM table WHERE key = $1") //
.bindNull(0, String.class) //
@@ -136,13 +134,9 @@ public class DefaultDatabaseClientUnitTests {
@Test // gh-162
public void executeShouldBindSettableValues() {
Statement statement = mock(Statement.class);
when(connection.createStatement("SELECT * FROM table WHERE key = $1")).thenReturn(statement);
when(statement.execute()).thenReturn(Mono.empty());
Statement statement = mockStatementFor("SELECT * FROM table WHERE key = $1");
DefaultDatabaseClient databaseClient = (DefaultDatabaseClient) DatabaseClient.builder()
.connectionFactory(connectionFactory)
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build();
DatabaseClient databaseClient = databaseClientBuilder.build();
databaseClient.execute("SELECT * FROM table WHERE key = $1") //
.bind(0, SettableValue.empty(String.class)) //
@@ -164,13 +158,8 @@ public class DefaultDatabaseClientUnitTests {
@Test // gh-128
public void executeShouldBindNamedNullValues() {
Statement statement = mock(Statement.class);
when(connection.createStatement("SELECT * FROM table WHERE key = $1")).thenReturn(statement);
when(statement.execute()).thenReturn(Mono.empty());
DefaultDatabaseClient databaseClient = (DefaultDatabaseClient) DatabaseClient.builder()
.connectionFactory(connectionFactory)
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build();
Statement statement = mockStatementFor("SELECT * FROM table WHERE key = $1");
DatabaseClient databaseClient = databaseClientBuilder.build();
databaseClient.execute("SELECT * FROM table WHERE key = :key") //
.bindNull("key", String.class) //
@@ -184,14 +173,9 @@ public class DefaultDatabaseClientUnitTests {
@Test // gh-178
public void executeShouldBindNamedValuesFromIndexes() {
Statement statement = mock(Statement.class);
when(connection.createStatement("SELECT id, name, manual FROM legoset WHERE name IN ($1, $2, $3)"))
.thenReturn(statement);
when(statement.execute()).thenReturn(Mono.empty());
Statement statement = mockStatementFor("SELECT id, name, manual FROM legoset WHERE name IN ($1, $2, $3)");
DefaultDatabaseClient databaseClient = (DefaultDatabaseClient) DatabaseClient.builder()
.connectionFactory(connectionFactory)
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build();
DatabaseClient databaseClient = databaseClientBuilder.build();
databaseClient.execute("SELECT id, name, manual FROM legoset WHERE name IN (:name)") //
.bind(0, Arrays.asList("unknown", "dunno", "other")) //
@@ -209,13 +193,9 @@ public class DefaultDatabaseClientUnitTests {
@Test // gh-128, gh-162
public void executeShouldBindValues() {
Statement statement = mock(Statement.class);
when(connection.createStatement("SELECT * FROM table WHERE key = $1")).thenReturn(statement);
when(statement.execute()).thenReturn(Mono.empty());
Statement statement = mockStatementFor("SELECT * FROM table WHERE key = $1");
DefaultDatabaseClient databaseClient = (DefaultDatabaseClient) DatabaseClient.builder()
.connectionFactory(connectionFactory)
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build();
DatabaseClient databaseClient = databaseClientBuilder.build();
databaseClient.execute("SELECT * FROM table WHERE key = $1") //
.bind(0, SettableValue.from("foo")) //
@@ -237,14 +217,8 @@ public class DefaultDatabaseClientUnitTests {
@Test // gh-162
public void insertShouldAcceptNullValues() {
Statement statement = mock(Statement.class);
when(connection.createStatement("INSERT INTO foo (first, second) VALUES ($1, $2)")).thenReturn(statement);
when(statement.returnGeneratedValues()).thenReturn(statement);
when(statement.execute()).thenReturn(Mono.empty());
DefaultDatabaseClient databaseClient = (DefaultDatabaseClient) DatabaseClient.builder()
.connectionFactory(connectionFactory)
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build();
Statement statement = mockStatementFor("INSERT INTO foo (first, second) VALUES ($1, $2)");
DatabaseClient databaseClient = databaseClientBuilder.build();
databaseClient.insert().into("foo") //
.value("first", "foo") //
@@ -260,14 +234,8 @@ public class DefaultDatabaseClientUnitTests {
@Test // gh-162
public void insertShouldAcceptSettableValue() {
Statement statement = mock(Statement.class);
when(connection.createStatement("INSERT INTO foo (first, second) VALUES ($1, $2)")).thenReturn(statement);
when(statement.returnGeneratedValues()).thenReturn(statement);
when(statement.execute()).thenReturn(Mono.empty());
DefaultDatabaseClient databaseClient = (DefaultDatabaseClient) DatabaseClient.builder()
.connectionFactory(connectionFactory)
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build();
Statement statement = mockStatementFor("INSERT INTO foo (first, second) VALUES ($1, $2)");
DatabaseClient databaseClient = databaseClientBuilder.build();
databaseClient.insert().into("foo") //
.value("first", SettableValue.from("foo")) //
@@ -283,13 +251,8 @@ public class DefaultDatabaseClientUnitTests {
@Test // gh-128
public void executeShouldBindNamedValuesByIndex() {
Statement statement = mock(Statement.class);
when(connection.createStatement("SELECT * FROM table WHERE key = $1")).thenReturn(statement);
when(statement.execute()).thenReturn(Mono.empty());
DefaultDatabaseClient databaseClient = (DefaultDatabaseClient) DatabaseClient.builder()
.connectionFactory(connectionFactory)
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build();
Statement statement = mockStatementFor("SELECT * FROM table WHERE key = $1");
DatabaseClient databaseClient = databaseClientBuilder.build();
databaseClient.execute("SELECT * FROM table WHERE key = :key") //
.bind("key", "foo") //
@@ -303,14 +266,8 @@ public class DefaultDatabaseClientUnitTests {
@Test // gh-177
public void deleteNotInShouldRenderCorrectQuery() {
Statement statement = mock(Statement.class);
when(connection.createStatement("DELETE FROM tab WHERE tab.pole = $1 AND tab.id NOT IN ($2, $3)"))
.thenReturn(statement);
when(statement.execute()).thenReturn(Mono.empty());
DefaultDatabaseClient databaseClient = (DefaultDatabaseClient) DatabaseClient.builder()
.connectionFactory(connectionFactory)
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build();
Statement statement = mockStatementFor("DELETE FROM tab WHERE tab.pole = $1 AND tab.id NOT IN ($2, $3)");
DatabaseClient databaseClient = databaseClientBuilder.build();
databaseClient.delete().from("tab").matching(where("pole").is("foo").and("id").notIn(1, 2)) //
.then() //
@@ -318,23 +275,18 @@ public class DefaultDatabaseClientUnitTests {
.verifyComplete();
verify(statement).bind(0, "foo");
verify(statement).bind(1, (Object) 1);
verify(statement).bind(2, (Object) 2);
verify(statement).bind(1, 1);
verify(statement).bind(2, 2);
}
@Test // gh-243
public void rowsUpdatedShouldEmitSingleValue() {
Statement statement = mock(Statement.class);
when(connection.createStatement("DROP TABLE tab;")).thenReturn(statement);
Result result = mock(Result.class);
doReturn(Flux.just(result)).when(statement).execute();
DefaultDatabaseClient databaseClient = (DefaultDatabaseClient) DatabaseClient.builder()
.connectionFactory(connectionFactory)
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)).build();
when(result.getRowsUpdated()).thenReturn(Mono.empty(), Mono.just(2), Flux.just(1, 2, 3));
mockStatementFor("DROP TABLE tab;", result);
DatabaseClient databaseClient = databaseClientBuilder.build();
databaseClient.execute("DROP TABLE tab;") //
.fetch() //
@@ -361,10 +313,7 @@ public class DefaultDatabaseClientUnitTests {
@Test // gh-250
public void shouldThrowExceptionForSingleColumnObjectUpdate() {
DefaultDatabaseClient databaseClient = (DefaultDatabaseClient) DatabaseClient.builder()
.connectionFactory(connectionFactory) //
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)) //
.build();
DatabaseClient databaseClient = databaseClientBuilder.build();
assertThatIllegalArgumentException().isThrownBy(() -> databaseClient.update() //
.table(IdOnly.class) //
@@ -375,20 +324,11 @@ public class DefaultDatabaseClientUnitTests {
@Test // gh-260
public void shouldProjectGenericExecuteAs() {
Statement statement = mock(Statement.class);
when(connection.createStatement(anyString())).thenReturn(statement);
MockResult result = mockSingleColumnResult(MockRow.builder().identified(0, Object.class, "Walter"));
mockStatement(result);
MockRowMetadata metadata = MockRowMetadata.builder()
.columnMetadata(MockColumnMetadata.builder().name("name").build()).build();
MockResult result = MockResult.builder().rowMetadata(metadata)
.row(MockRow.builder().identified(0, Object.class, "Walter").build()).build();
doReturn(Flux.just(result)).when(statement).execute();
DatabaseClient databaseClient = DatabaseClient.builder() //
.connectionFactory(connectionFactory) //
DatabaseClient databaseClient = databaseClientBuilder //
.projectionFactory(new SpelAwareProxyProjectionFactory()) //
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)) //
.build();
databaseClient.execute("SELECT * FROM person") //
@@ -408,20 +348,11 @@ public class DefaultDatabaseClientUnitTests {
@Test // gh-260
public void shouldProjectGenericSelectAs() {
Statement statement = mock(Statement.class);
when(connection.createStatement(anyString())).thenReturn(statement);
MockResult result = mockSingleColumnResult(MockRow.builder().identified(0, Object.class, "Walter"));
mockStatement(result);
MockRowMetadata metadata = MockRowMetadata.builder()
.columnMetadata(MockColumnMetadata.builder().name("name").build()).build();
MockResult result = MockResult.builder().rowMetadata(metadata)
.row(MockRow.builder().identified(0, Object.class, "Walter").build()).build();
doReturn(Flux.just(result)).when(statement).execute();
DatabaseClient databaseClient = DatabaseClient.builder() //
.connectionFactory(connectionFactory) //
DatabaseClient databaseClient = databaseClientBuilder //
.projectionFactory(new SpelAwareProxyProjectionFactory()) //
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)) //
.build();
databaseClient.select().from("person") //
@@ -442,20 +373,11 @@ public class DefaultDatabaseClientUnitTests {
@Test // gh-260
public void shouldProjectTypedSelectAs() {
Statement statement = mock(Statement.class);
when(connection.createStatement(anyString())).thenReturn(statement);
MockResult result = mockSingleColumnResult(MockRow.builder().identified("name", Object.class, "Walter"));
mockStatement(result);
MockRowMetadata metadata = MockRowMetadata.builder()
.columnMetadata(MockColumnMetadata.builder().name("name").build()).build();
MockResult result = MockResult.builder().rowMetadata(metadata)
.row(MockRow.builder().identified("name", Object.class, "Walter").build()).build();
doReturn(Flux.just(result)).when(statement).execute();
DatabaseClient databaseClient = DatabaseClient.builder() //
.connectionFactory(connectionFactory) //
DatabaseClient databaseClient = databaseClientBuilder //
.projectionFactory(new SpelAwareProxyProjectionFactory()) //
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)) //
.build();
databaseClient.select().from(Person.class) //
@@ -474,18 +396,12 @@ public class DefaultDatabaseClientUnitTests {
@Test // gh-189
public void shouldApplyExecuteFunction() {
Statement statement = mock(Statement.class);
when(connection.createStatement(anyString())).thenReturn(statement);
Statement statement = mockStatement();
MockResult result = mockSingleColumnResult(MockRow.builder().identified(0, Object.class, "Walter"));
MockRowMetadata metadata = MockRowMetadata.builder()
.columnMetadata(MockColumnMetadata.builder().name("name").build()).build();
MockResult result = MockResult.builder().rowMetadata(metadata)
.row(MockRow.builder().identified(0, Object.class, "Walter").build()).build();
DatabaseClient databaseClient = DatabaseClient.builder() //
.connectionFactory(connectionFactory) //
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)) //
.executeFunction(it -> Mono.just(result)).build();
DatabaseClient databaseClient = databaseClientBuilder //
.executeFunction(it -> Mono.just(result)) //
.build();
databaseClient.execute("SELECT") //
.fetch().all() //
@@ -498,20 +414,13 @@ public class DefaultDatabaseClientUnitTests {
@Test // gh-189
public void shouldApplyStatementFilterFunctions() {
Statement statement = mock(Statement.class);
when(connection.createStatement(anyString())).thenReturn(statement);
when(statement.returnGeneratedValues(anyString())).thenReturn(statement);
MockRowMetadata metadata = MockRowMetadata.builder()
.columnMetadata(MockColumnMetadata.builder().name("name").build()).build();
MockResult result = MockResult.builder().rowMetadata(metadata).build();
doReturn(Flux.just(result)).when(statement).execute();
Statement statement = mockStatement(result);
DatabaseClient databaseClient = DatabaseClient.builder() //
.connectionFactory(connectionFactory) //
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)) //
.build();
DatabaseClient databaseClient = databaseClientBuilder.build();
databaseClient.execute("SELECT") //
.filter((s, next) -> next.execute(s.returnGeneratedValues("foo"))) //
@@ -530,20 +439,13 @@ public class DefaultDatabaseClientUnitTests {
@Test // gh-189
public void shouldApplyStatementFilterFunctionsToTypedExecute() {
Statement statement = mock(Statement.class);
when(connection.createStatement(anyString())).thenReturn(statement);
when(statement.returnGeneratedValues(anyString())).thenReturn(statement);
MockRowMetadata metadata = MockRowMetadata.builder()
.columnMetadata(MockColumnMetadata.builder().name("name").build()).build();
MockResult result = MockResult.builder().rowMetadata(metadata).build();
doReturn(Flux.just(result)).when(statement).execute();
Statement statement = mockStatement(result);
DatabaseClient databaseClient = DatabaseClient.builder() //
.connectionFactory(connectionFactory) //
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)) //
.build();
DatabaseClient databaseClient = databaseClientBuilder.build();
databaseClient.execute("SELECT") //
.filter((s, next) -> next.execute(s.returnGeneratedValues("foo"))) //
@@ -561,20 +463,11 @@ public class DefaultDatabaseClientUnitTests {
@Test // gh-189
public void shouldApplySimpleStatementFilterFunctions() {
Statement statement = mock(Statement.class);
when(connection.createStatement(anyString())).thenReturn(statement);
when(statement.returnGeneratedValues(anyString())).thenReturn(statement);
MockResult result = mockSingleColumnEmptyResult();
MockRowMetadata metadata = MockRowMetadata.builder()
.columnMetadata(MockColumnMetadata.builder().name("name").build()).build();
MockResult result = MockResult.builder().rowMetadata(metadata).build();
Statement statement = mockStatement(result);
doReturn(Flux.just(result)).when(statement).execute();
DatabaseClient databaseClient = DatabaseClient.builder() //
.connectionFactory(connectionFactory) //
.dataAccessStrategy(new DefaultReactiveDataAccessStrategy(PostgresDialect.INSTANCE)) //
.build();
DatabaseClient databaseClient = databaseClientBuilder.build();
databaseClient.execute("SELECT") //
.filter(s -> s.returnGeneratedValues("foo")) //
@@ -590,6 +483,49 @@ public class DefaultDatabaseClientUnitTests {
inOrder.verifyNoMoreInteractions();
}
private Statement mockStatement() {
return mockStatementFor(null, null);
}
private Statement mockStatement(Result result) {
return mockStatementFor(null, result);
}
private Statement mockStatementFor(String sql) {
return mockStatementFor(sql, null);
}
private Statement mockStatementFor(@Nullable String sql, @Nullable Result result) {
Statement statement = mock(Statement.class);
when(connection.createStatement(sql == null ? anyString() : eq(sql))).thenReturn(statement);
when(statement.returnGeneratedValues(anyString())).thenReturn(statement);
when(statement.returnGeneratedValues()).thenReturn(statement);
doReturn(result == null ? Mono.empty() : Flux.just(result)).when(statement).execute();
return statement;
}
private MockResult mockSingleColumnEmptyResult() {
return mockSingleColumnResult(null);
}
/**
* Mocks a {@link Result} with a single column "name" and a single row if a non null row is provided.
*/
private MockResult mockSingleColumnResult(@Nullable MockRow.Builder row) {
MockRowMetadata metadata = MockRowMetadata.builder()
.columnMetadata(MockColumnMetadata.builder().name("name").build()).build();
MockResult.Builder resultBuilder = MockResult.builder().rowMetadata(metadata);
if (row != null) {
resultBuilder = resultBuilder.row(row.build());
}
return resultBuilder.build();
}
static class Person {
String name;