/* * Copyright 2016-2017 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.cassandra.core; import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; import java.util.Collections; import java.util.function.Consumer; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.cassandra.core.session.DefaultReactiveSessionFactory; import org.springframework.cassandra.core.session.ReactiveResultSet; import org.springframework.cassandra.core.session.ReactiveSession; import org.springframework.cassandra.core.session.ReactiveSessionFactory; import org.springframework.cassandra.support.exception.CassandraConnectionFailureException; import org.springframework.cassandra.support.exception.CassandraInvalidQueryException; import org.springframework.dao.IncorrectResultSizeDataAccessException; import com.datastax.driver.core.BoundStatement; import com.datastax.driver.core.ColumnDefinitions; import com.datastax.driver.core.ConsistencyLevel; import com.datastax.driver.core.PreparedStatement; import com.datastax.driver.core.Row; import com.datastax.driver.core.SimpleStatement; import com.datastax.driver.core.Statement; import com.datastax.driver.core.exceptions.InvalidQueryException; import com.datastax.driver.core.exceptions.NoHostAvailableException; import com.datastax.driver.core.policies.DowngradingConsistencyRetryPolicy; /** * Unit tests for {@link ReactiveCqlTemplate}. * * @author Mark Paluch */ @RunWith(MockitoJUnitRunner.class) public class ReactiveCqlTemplateUnitTests { @Mock ReactiveSession session; @Mock ReactiveResultSet reactiveResultSet; @Mock Row row; @Mock PreparedStatement preparedStatement; @Mock BoundStatement boundStatement; @Mock ColumnDefinitions columnDefinitions; ReactiveCqlTemplate template; ReactiveSessionFactory sessionFactory; @Before public void setup() throws Exception { this.sessionFactory = new DefaultReactiveSessionFactory(session); this.template = new ReactiveCqlTemplate(sessionFactory); } // ------------------------------------------------------------------------- // Tests dealing with a plain org.springframework.cassandra.core.ReactiveSession // ------------------------------------------------------------------------- @Test // DATACASS-335 public void executeCallbackShouldExecuteDeferred() { Flux<String> flux = template.execute((ReactiveSessionCallback<String>) session -> { session.close(); return Mono.just("OK"); }); verify(session, never()).close(); StepVerifier.create(flux).expectNext("OK").verifyComplete(); verify(session).close(); } @Test // DATACASS-335 public void executeCallbackShouldTranslateExceptions() { Flux<String> flux = template.execute((ReactiveSessionCallback<String>) session -> { throw new InvalidQueryException("wrong query"); }); StepVerifier.create(flux).expectError(CassandraInvalidQueryException.class).verify(); } @Test // DATACASS-335 public void executeCqlShouldExecuteDeferred() { when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); Mono<Boolean> mono = template.execute("UPDATE user SET a = 'b';"); verifyZeroInteractions(session); StepVerifier.create(mono).expectNext(false).verifyComplete(); verify(session).execute(any(Statement.class)); } @Test // DATACASS-335 public void executeCqlShouldTranslateExceptions() { when(session.execute(any(Statement.class))).thenThrow(new NoHostAvailableException(Collections.emptyMap())); Mono<Boolean> mono = template.execute("UPDATE user SET a = 'b';"); StepVerifier.create(mono).expectError(CassandraConnectionFailureException.class).verify(); } // ------------------------------------------------------------------------- // Tests dealing with static CQL // ------------------------------------------------------------------------- @Test // DATACASS-335 public void executeCqlShouldCallExecution() { doTestStrings(null, null, null, reactiveCqlTemplate -> { StepVerifier.create(reactiveCqlTemplate.execute("SELECT * from USERS")).expectNextCount(1).verifyComplete(); verify(session).execute(any(Statement.class)); }); } @Test // DATACASS-335 public void executeCqlWithArgumentsShouldCallExecution() { doTestStrings(5, ConsistencyLevel.ONE, DowngradingConsistencyRetryPolicy.INSTANCE, reactiveCqlTemplate -> { StepVerifier.create(reactiveCqlTemplate.execute("SELECT * from USERS")) // .expectNextCount(1) // .verifyComplete(); verify(session).execute(any(Statement.class)); }); } @Test // DATACASS-335 public void queryForResultSetShouldCallExecution() { doTestStrings(null, null, null, reactiveCqlTemplate -> { Mono<ReactiveResultSet> mono = reactiveCqlTemplate.queryForResultSet("SELECT * from USERS"); StepVerifier.create(mono.flatMapMany(ReactiveResultSet::rows)).expectNextCount(3).verifyComplete(); verify(session).execute(any(Statement.class)); }); } @Test // DATACASS-335 public void queryWithResultSetExtractorShouldCallExecution() { doTestStrings(null, null, null, reactiveCqlTemplate -> { Flux<String> flux = reactiveCqlTemplate.query("SELECT * from USERS", (row, index) -> row.getString(0)); StepVerifier.create(flux).expectNext("Walter", "Hank", " Jesse").verifyComplete(); verify(session).execute(any(Statement.class)); }); } @Test // DATACASS-335 public void queryWithResultSetExtractorWithArgumentsShouldCallExecution() { doTestStrings(5, ConsistencyLevel.ONE, DowngradingConsistencyRetryPolicy.INSTANCE, reactiveCqlTemplate -> { Flux<String> flux = reactiveCqlTemplate.query("SELECT * from USERS", (row, index) -> row.getString(0)); StepVerifier.create(flux).expectNext("Walter", "Hank", " Jesse").verifyComplete(); verify(session).execute(any(Statement.class)); }); } @Test // DATACASS-335 public void queryCqlShouldExecuteDeferred() { when(reactiveResultSet.wasApplied()).thenReturn(true); when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); Flux<Boolean> flux = template.query("UPDATE user SET a = 'b';", resultSet -> Mono.just(resultSet.wasApplied())); verifyZeroInteractions(session); StepVerifier.create(flux).expectNext(true).verifyComplete(); verify(session).execute(any(Statement.class)); } @Test // DATACASS-335 public void queryCqlShouldTranslateExceptions() { when(session.execute(any(Statement.class))).thenThrow(new NoHostAvailableException(Collections.emptyMap())); Flux<Boolean> flux = template.query("UPDATE user SET a = 'b';", resultSet -> Mono.just(resultSet.wasApplied())); StepVerifier.create(flux).expectError(CassandraConnectionFailureException.class).verify(); } @Test // DATACASS-335 public void queryForObjectCqlShouldBeEmpty() { when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.empty()); Mono<String> mono = template.queryForObject("SELECT * FROM user", (row, rowNum) -> "OK"); StepVerifier.create(mono).verifyComplete(); } @Test // DATACASS-335 public void queryForObjectCqlShouldReturnRecord() { when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row)); Mono<String> mono = template.queryForObject("SELECT * FROM user", (row, rowNum) -> "OK"); StepVerifier.create(mono).expectNext("OK").verifyComplete(); } @Test // DATACASS-335 public void queryForObjectCqlShouldReturnNullValue() { when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row)); Mono<String> mono = template.queryForObject("SELECT * FROM user", (row, rowNum) -> null); StepVerifier.create(mono).verifyComplete(); } @Test // DATACASS-335 public void queryForObjectCqlShouldFailReturningManyRecords() { when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row, row)); Mono<String> mono = template.queryForObject("SELECT * FROM user", (row, rowNum) -> "OK"); StepVerifier.create(mono).expectError(IncorrectResultSizeDataAccessException.class).verify(); } @Test // DATACASS-335 public void queryForObjectCqlWithTypeShouldReturnRecord() { when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row)); when(row.getColumnDefinitions()).thenReturn(columnDefinitions); when(columnDefinitions.size()).thenReturn(1); when(row.getString(0)).thenReturn("OK"); Mono<String> mono = template.queryForObject("SELECT * FROM user", String.class); StepVerifier.create(mono).expectNext("OK").verifyComplete(); } @Test // DATACASS-335 public void queryForFluxCqlWithTypeShouldReturnRecord() { when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row, row)); when(row.getColumnDefinitions()).thenReturn(columnDefinitions); when(columnDefinitions.size()).thenReturn(1); when(row.getString(0)).thenReturn("OK", "NOT OK"); Flux<String> flux = template.queryForFlux("SELECT * FROM user", String.class); StepVerifier.create(flux).expectNext("OK", "NOT OK").verifyComplete(); } @Test // DATACASS-335 public void queryForRowsCqlReturnRows() { when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row, row)); Flux<Row> flux = template.queryForRows("SELECT * FROM user"); StepVerifier.create(flux).expectNext(row, row).verifyComplete(); } @Test // DATACASS-335 public void executeCqlShouldReturnWasApplied() { when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.wasApplied()).thenReturn(true); Mono<Boolean> mono = template.execute("UPDATE user SET a = 'b';"); StepVerifier.create(mono).expectNext(true).verifyComplete(); } @Test // DATACASS-335 public void executeCqlPublisherShouldReturnWasApplied() { when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.wasApplied()).thenReturn(true, false); Flux<Boolean> flux = template.execute(Flux.just("UPDATE user SET a = 'b';", "UPDATE user SET x = 'y';")); verifyZeroInteractions(session); StepVerifier.create(flux).expectNext(true).expectNext(false).verifyComplete(); verify(session, times(2)).execute(any(Statement.class)); } // ------------------------------------------------------------------------- // Tests dealing with com.datastax.driver.core.Statement // ------------------------------------------------------------------------- @Test // DATACASS-335 public void executeStatementShouldCallExecution() { doTestStrings(null, null, null, reactiveCqlTemplate -> { StepVerifier.create(reactiveCqlTemplate.execute(new SimpleStatement("SELECT * from USERS"))) // .expectNextCount(1) // .verifyComplete(); verify(session).execute(any(Statement.class)); }); } @Test // DATACASS-335 public void executeStatementWithArgumentsShouldCallExecution() { doTestStrings(5, ConsistencyLevel.ONE, DowngradingConsistencyRetryPolicy.INSTANCE, reactiveCqlTemplate -> { StepVerifier.create(reactiveCqlTemplate.execute(new SimpleStatement("SELECT * from USERS"))) // .expectNextCount(1) // .verifyComplete(); verify(session).execute(any(Statement.class)); }); } @Test // DATACASS-335 public void queryForResultStatementSetShouldCallExecution() { doTestStrings(null, null, null, reactiveCqlTemplate -> { StepVerifier .create(reactiveCqlTemplate.queryForResultSet(new SimpleStatement("SELECT * from USERS")) .flatMapMany(ReactiveResultSet::rows)) // .expectNextCount(3) // .verifyComplete(); verify(session).execute(any(Statement.class)); }); } @Test // DATACASS-335 public void queryWithResultSetStatementExtractorShouldCallExecution() { doTestStrings(null, null, null, reactiveCqlTemplate -> { Flux<String> flux = reactiveCqlTemplate.query(new SimpleStatement("SELECT * from USERS"), (row, index) -> row.getString(0)); StepVerifier.create(flux).expectNext("Walter", "Hank", " Jesse").verifyComplete(); verify(session).execute(any(Statement.class)); }); } @Test // DATACASS-335 public void queryWithResultSetStatementExtractorWithArgumentsShouldCallExecution() { doTestStrings(5, ConsistencyLevel.ONE, DowngradingConsistencyRetryPolicy.INSTANCE, reactiveCqlTemplate -> { Flux<String> flux = reactiveCqlTemplate.query(new SimpleStatement("SELECT * from USERS"), (row, index) -> row.getString(0)); StepVerifier.create(flux.collectList()).consumeNextWith(rows -> { assertThat(rows).hasSize(3).contains("Walter", "Hank", " Jesse"); }).verifyComplete(); verify(session).execute(any(Statement.class)); }); } @Test // DATACASS-335 public void queryStatementShouldExecuteDeferred() { when(reactiveResultSet.wasApplied()).thenReturn(true); when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); Flux<Boolean> flux = template.query(new SimpleStatement("UPDATE user SET a = 'b';"), resultSet -> Mono.just(resultSet.wasApplied())); verifyZeroInteractions(session); StepVerifier.create(flux).expectNext(true).verifyComplete(); verify(session).execute(any(Statement.class)); } @Test // DATACASS-335 public void queryStatementShouldTranslateExceptions() { when(session.execute(any(Statement.class))).thenThrow(new NoHostAvailableException(Collections.emptyMap())); Flux<Boolean> flux = template.query(new SimpleStatement("UPDATE user SET a = 'b';"), resultSet -> Mono.just(resultSet.wasApplied())); StepVerifier.create(flux).expectError(CassandraConnectionFailureException.class).verify(); } @Test // DATACASS-335 public void queryForObjectStatementShouldBeEmpty() { when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.empty()); Mono<String> mono = template.queryForObject(new SimpleStatement("SELECT * FROM user"), (row, rowNum) -> "OK"); StepVerifier.create(mono).verifyComplete(); } @Test // DATACASS-335 public void queryForObjectStatementShouldReturnRecord() { when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row)); Mono<String> mono = template.queryForObject(new SimpleStatement("SELECT * FROM user"), (row, rowNum) -> "OK"); StepVerifier.create(mono).expectNext("OK").verifyComplete(); } @Test // DATACASS-335 public void queryForObjectStatementShouldReturnNullValue() { when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row)); Mono<String> mono = template.queryForObject(new SimpleStatement("SELECT * FROM user"), (row, rowNum) -> null); StepVerifier.create(mono).verifyComplete(); } @Test // DATACASS-335 public void queryForObjectStatementShouldFailReturningManyRecords() { when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row, row)); Mono<String> mono = template.queryForObject(new SimpleStatement("SELECT * FROM user"), (row, rowNum) -> "OK"); StepVerifier.create(mono).expectError(IncorrectResultSizeDataAccessException.class).verify(); } @Test // DATACASS-335 public void queryForObjectStatementWithTypeShouldReturnRecord() { when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row)); when(row.getColumnDefinitions()).thenReturn(columnDefinitions); when(columnDefinitions.size()).thenReturn(1); when(row.getString(0)).thenReturn("OK"); Mono<String> mono = template.queryForObject(new SimpleStatement("SELECT * FROM user"), String.class); StepVerifier.create(mono).expectNext("OK").verifyComplete(); } @Test // DATACASS-335 public void queryForFluxStatementWithTypeShouldReturnRecord() { when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row, row)); when(row.getColumnDefinitions()).thenReturn(columnDefinitions); when(columnDefinitions.size()).thenReturn(1); when(row.getString(0)).thenReturn("OK", "NOT OK"); Flux<String> flux = template.queryForFlux(new SimpleStatement("SELECT * FROM user"), String.class); StepVerifier.create(flux).expectNext("OK", "NOT OK").verifyComplete(); } @Test // DATACASS-335 public void queryForRowsStatementReturnRows() { when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row, row)); Flux<Row> flux = template.queryForRows(new SimpleStatement("SELECT * FROM user")); StepVerifier.create(flux).expectNext(row, row).verifyComplete(); } @Test // DATACASS-335 public void executeStatementShouldReturnWasApplied() { when(session.execute(any(Statement.class))).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.wasApplied()).thenReturn(true); StepVerifier.create(template.execute(new SimpleStatement("UPDATE user SET a = 'b';"))).expectNext(true) .verifyComplete(); } // ------------------------------------------------------------------------- // Methods dealing with prepared statements // ------------------------------------------------------------------------- @Test // DATACASS-335 public void queryPreparedStatementWithCallbackShouldCallExecution() { doTestStrings(null, null, null, reactiveCqlTemplate -> { Flux<Row> flux = reactiveCqlTemplate.execute("SELECT * from USERS", (session, ps) -> { return session.execute(ps.bind("A")).flatMapMany(ReactiveResultSet::rows); }); StepVerifier.create(flux).expectNextCount(3).verifyComplete(); }); } @Test // DATACASS-335 public void executePreparedStatementWithCallbackShouldCallExecution() { doTestStrings(null, null, null, reactiveCqlTemplate -> { Mono<Boolean> applied = reactiveCqlTemplate.execute("UPDATE users SET name = ?", "White"); when(this.preparedStatement.bind("White")).thenReturn(this.boundStatement); when(this.reactiveResultSet.wasApplied()).thenReturn(true); StepVerifier.create(applied).expectNext(true).verifyComplete(); }); } @Test // DATACASS-335 public void executePreparedStatementCallbackShouldExecuteDeferred() { when(session.prepare(anyString())).thenReturn(Mono.just(preparedStatement)); when(preparedStatement.bind()).thenReturn(boundStatement); when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet)); Flux<ReactiveResultSet> flux = template.execute("UPDATE user SET a = 'b';", (session, ps) -> session.execute(ps.bind())); verifyZeroInteractions(session); StepVerifier.create(flux).expectNext(reactiveResultSet).verifyComplete(); verify(session).prepare(anyString()); verify(session).execute(boundStatement); } @Test // DATACASS-335 public void executePreparedStatementCreatorShouldExecuteDeferred() { when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet)); Flux<ReactiveResultSet> flux = template.execute(session -> Mono.just(preparedStatement), (session, ps) -> session.execute(boundStatement)); verifyZeroInteractions(session); StepVerifier.create(flux).expectNext(reactiveResultSet).verifyComplete(); verify(session).execute(boundStatement); } @Test // DATACASS-335 public void executePreparedStatementCreatorShouldTranslateStatementCreationExceptions() { Flux<ReactiveResultSet> flux = template.execute(session -> { throw new NoHostAvailableException(Collections.emptyMap()); }, (session, ps) -> session.execute(boundStatement)); StepVerifier.create(flux).expectError(CassandraConnectionFailureException.class).verify(); } @Test // DATACASS-335 public void executePreparedStatementCreatorShouldTranslateStatementCallbackExceptions() { Flux<ReactiveResultSet> flux = template.execute(session -> Mono.just(preparedStatement), (session, ps) -> { throw new NoHostAvailableException(Collections.emptyMap()); }); StepVerifier.create(flux).expectError(CassandraConnectionFailureException.class).verify(); } @Test // DATACASS-335 public void queryPreparedStatementCreatorShouldReturnResult() { when(preparedStatement.bind()).thenReturn(boundStatement); when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row)); Flux<Row> flux = template.query(session -> Mono.just(preparedStatement), ReactiveResultSet::rows); verifyZeroInteractions(session); StepVerifier.create(flux).expectNext(row).verifyComplete(); verify(preparedStatement).bind(); } @Test // DATACASS-335 public void queryPreparedStatementCreatorAndBinderShouldReturnResult() { when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row)); Flux<Row> flux = template.query(session -> Mono.just(preparedStatement), ps -> { ps.bind("a", "b"); return boundStatement; }, ReactiveResultSet::rows); verifyZeroInteractions(session); StepVerifier.create(flux).expectNext(row).verifyComplete(); verify(preparedStatement).bind("a", "b"); } @Test // DATACASS-335 public void queryPreparedStatementCreatorAndBinderAndMapperShouldReturnResult() { when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row)); Flux<Row> flux = template.query(session -> Mono.just(preparedStatement), ps -> { ps.bind("a", "b"); return boundStatement; }, (row, rowNum) -> row); verifyZeroInteractions(session); StepVerifier.create(flux).expectNext(row).verifyComplete(); verify(preparedStatement).bind("a", "b"); } @Test // DATACASS-335 public void queryForObjectPreparedStatementShouldBeEmpty() { when(session.prepare("SELECT * FROM user WHERE username = ?")).thenReturn(Mono.just(preparedStatement)); when(preparedStatement.bind("Walter")).thenReturn(boundStatement); when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.empty()); Mono<String> mono = template.queryForObject("SELECT * FROM user WHERE username = ?", (row, rowNum) -> "OK", "Walter"); StepVerifier.create(mono).verifyComplete(); } @Test // DATACASS-335 public void queryForObjectPreparedStatementShouldReturnRecord() { when(session.prepare("SELECT * FROM user WHERE username = ?")).thenReturn(Mono.just(preparedStatement)); when(preparedStatement.bind("Walter")).thenReturn(boundStatement); when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row)); Mono<String> mono = template.queryForObject("SELECT * FROM user WHERE username = ?", (row, rowNum) -> "OK", "Walter"); StepVerifier.create(mono).expectNext("OK").verifyComplete(); } @Test // DATACASS-335 public void queryForObjectPreparedStatementShouldFailReturningManyRecords() { when(session.prepare("SELECT * FROM user WHERE username = ?")).thenReturn(Mono.just(preparedStatement)); when(preparedStatement.bind("Walter")).thenReturn(boundStatement); when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row, row)); Mono<String> mono = template.queryForObject("SELECT * FROM user WHERE username = ?", (row, rowNum) -> "OK", "Walter"); StepVerifier.create(mono).expectError(IncorrectResultSizeDataAccessException.class).verify(); } @Test // DATACASS-335 public void queryForObjectPreparedStatementWithTypeShouldReturnRecord() { when(session.prepare("SELECT * FROM user WHERE username = ?")).thenReturn(Mono.just(preparedStatement)); when(preparedStatement.bind("Walter")).thenReturn(boundStatement); when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row)); when(row.getColumnDefinitions()).thenReturn(columnDefinitions); when(columnDefinitions.size()).thenReturn(1); when(row.getString(0)).thenReturn("OK"); Mono<String> mono = template.queryForObject("SELECT * FROM user WHERE username = ?", String.class, "Walter"); StepVerifier.create(mono).expectNext("OK").verifyComplete(); } @Test // DATACASS-335 public void queryForFluxPreparedStatementWithTypeShouldReturnRecord() { when(session.prepare("SELECT * FROM user WHERE username = ?")).thenReturn(Mono.just(preparedStatement)); when(preparedStatement.bind("Walter")).thenReturn(boundStatement); when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row, row)); when(row.getColumnDefinitions()).thenReturn(columnDefinitions); when(columnDefinitions.size()).thenReturn(1); when(row.getString(0)).thenReturn("OK", "NOT OK"); Flux<String> flux = template.queryForFlux("SELECT * FROM user WHERE username = ?", String.class, "Walter"); StepVerifier.create(flux).expectNext("OK", "NOT OK").verifyComplete(); } @Test // DATACASS-335 public void queryForRowsPreparedStatementReturnRows() { when(session.prepare("SELECT * FROM user WHERE username = ?")).thenReturn(Mono.just(preparedStatement)); when(preparedStatement.bind("Walter")).thenReturn(boundStatement); when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.rows()).thenReturn(Flux.just(row, row)); Flux<Row> flux = template.queryForRows("SELECT * FROM user WHERE username = ?", "Walter"); StepVerifier.create(flux).expectNextCount(2).verifyComplete(); } @Test // DATACASS-335 public void updatePreparedStatementShouldReturnApplied() { when(session.prepare("UPDATE user SET username = ?")).thenReturn(Mono.just(preparedStatement)); when(preparedStatement.bind("Walter")).thenReturn(boundStatement); when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.wasApplied()).thenReturn(true); Mono<Boolean> mono = template.execute("UPDATE user SET username = ?", "Walter"); StepVerifier.create(mono).expectNext(true).verifyComplete(); } @Test // DATACASS-335 public void updatePreparedStatementArgsPublisherShouldReturnApplied() { when(session.prepare("UPDATE user SET username = ?")).thenReturn(Mono.just(preparedStatement)); when(preparedStatement.bind("Walter")).thenReturn(boundStatement); when(preparedStatement.bind("Hank")).thenReturn(boundStatement); when(session.execute(boundStatement)).thenReturn(Mono.just(reactiveResultSet)); when(reactiveResultSet.wasApplied()).thenReturn(true); Flux<Boolean> flux = template.execute("UPDATE user SET username = ?", Flux.just(new Object[] { "Walter" }, new Object[] { "Hank" })); StepVerifier.create(flux).expectNext(true, true).verifyComplete(); verify(session, atMost(1)).prepare("UPDATE user SET username = ?"); verify(session, times(2)).execute(boundStatement); } private <T> void doTestStrings(Integer fetchSize, com.datastax.driver.core.ConsistencyLevel consistencyLevel, com.datastax.driver.core.policies.RetryPolicy retryPolicy, Consumer<ReactiveCqlTemplate> cqlTemplateConsumer) { String[] results = { "Walter", "Hank", " Jesse" }; when(this.session.execute((Statement) any())).thenReturn(Mono.just(reactiveResultSet)); when(this.reactiveResultSet.rows()).thenReturn(Flux.just(row, row, row)); when(this.row.getString(0)).thenReturn(results[0], results[1], results[2]); when(this.session.prepare(anyString())).thenReturn(Mono.just(this.preparedStatement)); ReactiveCqlTemplate template = new ReactiveCqlTemplate(); template.setSessionFactory(this.sessionFactory); if (fetchSize != null) { template.setFetchSize(fetchSize); } if (retryPolicy != null) { template.setRetryPolicy(retryPolicy); } if (consistencyLevel != null) { template.setConsistencyLevel(consistencyLevel); } cqlTemplateConsumer.accept(template); ArgumentCaptor<Statement> statementArgumentCaptor = ArgumentCaptor.forClass(Statement.class); verify(this.session).execute(statementArgumentCaptor.capture()); Statement statement = statementArgumentCaptor.getValue(); if (statement instanceof PreparedStatement || statement instanceof BoundStatement) { if (fetchSize != null) { verify(statement).setFetchSize(fetchSize.intValue()); } if (retryPolicy != null) { verify(statement).setRetryPolicy(retryPolicy); } if (consistencyLevel != null) { verify(statement).setConsistencyLevel(consistencyLevel); } } else { if (fetchSize != null) { assertThat(statement.getFetchSize()).isEqualTo(fetchSize.intValue()); } if (retryPolicy != null) { assertThat(statement.getRetryPolicy()).isEqualTo(retryPolicy); } if (consistencyLevel != null) { assertThat(statement.getConsistencyLevel()).isEqualTo(consistencyLevel); } } } }