@ -15,15 +15,20 @@
* /
package org.springframework.boot.actuate.cassandra ;
import com.datastax.dse.driver.api.core.cql.reactive.ReactiveResultSet ;
import com.datastax.dse.driver.api.core.cql.reactive.ReactiveRow ;
import java.util.ArrayList ;
import java.util.Collections ;
import java.util.HashMap ;
import java.util.List ;
import java.util.Map ;
import java.util.UUID ;
import com.datastax.oss.driver.api.core.CqlSession ;
import com.datastax.oss.driver.api.core.DriverTimeoutException ;
import com.datastax.oss.driver.api.core.cql.SimpleStatement ;
import com.datastax.oss.driver.api.core.Version ;
import com.datastax.oss.driver.api.core.metadata.Metadata ;
import com.datastax.oss.driver.api.core.metadata.Node ;
import com.datastax.oss.driver.api.core.metadata.NodeState ;
import org.junit.jupiter.api.Test ;
import org.mockito.stubbing.Answer ;
import org.reactivestreams.Subscriber ;
import org.reactivestreams.Subscription ;
import reactor.core.publisher.Mono ;
import reactor.test.StepVerifier ;
@ -32,16 +37,14 @@ import org.springframework.boot.actuate.health.Status;
import static org.assertj.core.api.Assertions.assertThat ;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException ;
import static org.mockito.ArgumentMatchers.any ;
import static org.mockito.BDDMockito.given ;
import static org.mockito.BDDMockito.willAnswer ;
import static org.mockito.Mockito.mock ;
/ * *
* Tests for { @link CassandraDriverReactiveHealthIndicator } .
*
* @author Alexandre Dutra
* @ since 2.4 .0
* @ author Stephane Nicoll
* /
class CassandraDriverReactiveHealthIndicatorTests {
@ -51,28 +54,101 @@ class CassandraDriverReactiveHealthIndicatorTests {
}
@Test
void testCassandraIsUp ( ) {
void healthWithOneHealthyNodeShouldReturnUp ( ) {
CqlSession session = mockCqlSessionWithNodeState ( NodeState . UP ) ;
CassandraDriverReactiveHealthIndicator healthIndicator = new CassandraDriverReactiveHealthIndicator ( session ) ;
Mono < Health > health = healthIndicator . health ( ) ;
StepVerifier . create ( health ) . consumeNextWith ( ( h ) - > assertThat ( h . getStatus ( ) ) . isEqualTo ( Status . UP ) )
. verifyComplete ( ) ;
}
@Test
void healthWithOneUnhealthyNodeShouldReturnDown ( ) {
CqlSession session = mockCqlSessionWithNodeState ( NodeState . DOWN ) ;
CassandraDriverReactiveHealthIndicator healthIndicator = new CassandraDriverReactiveHealthIndicator ( session ) ;
Mono < Health > health = healthIndicator . health ( ) ;
StepVerifier . create ( health ) . consumeNextWith ( ( h ) - > assertThat ( h . getStatus ( ) ) . isEqualTo ( Status . DOWN ) )
. verifyComplete ( ) ;
}
@Test
void healthWithOneUnknownNodeShouldReturnDown ( ) {
CqlSession session = mockCqlSessionWithNodeState ( NodeState . UNKNOWN ) ;
CassandraDriverReactiveHealthIndicator healthIndicator = new CassandraDriverReactiveHealthIndicator ( session ) ;
Mono < Health > health = healthIndicator . health ( ) ;
StepVerifier . create ( health ) . consumeNextWith ( ( h ) - > assertThat ( h . getStatus ( ) ) . isEqualTo ( Status . DOWN ) )
. verifyComplete ( ) ;
}
@Test
void healthWithOneForcedDownNodeShouldReturnDown ( ) {
CqlSession session = mockCqlSessionWithNodeState ( NodeState . FORCED_DOWN ) ;
CassandraDriverReactiveHealthIndicator healthIndicator = new CassandraDriverReactiveHealthIndicator ( session ) ;
Mono < Health > health = healthIndicator . health ( ) ;
StepVerifier . create ( health ) . consumeNextWith ( ( h ) - > assertThat ( h . getStatus ( ) ) . isEqualTo ( Status . DOWN ) )
. verifyComplete ( ) ;
}
@Test
void healthWithOneHealthyNodeAndOneUnhealthyNodeShouldReturnUp ( ) {
CqlSession session = mockCqlSessionWithNodeState ( NodeState . UP , NodeState . DOWN ) ;
CassandraDriverReactiveHealthIndicator healthIndicator = new CassandraDriverReactiveHealthIndicator ( session ) ;
Mono < Health > health = healthIndicator . health ( ) ;
StepVerifier . create ( health ) . consumeNextWith ( ( h ) - > assertThat ( h . getStatus ( ) ) . isEqualTo ( Status . UP ) )
. verifyComplete ( ) ;
}
@Test
void healthWithOneHealthyNodeAndOneUnknownNodeShouldReturnUp ( ) {
CqlSession session = mockCqlSessionWithNodeState ( NodeState . UP , NodeState . UNKNOWN ) ;
CassandraDriverReactiveHealthIndicator healthIndicator = new CassandraDriverReactiveHealthIndicator ( session ) ;
Mono < Health > health = healthIndicator . health ( ) ;
StepVerifier . create ( health ) . consumeNextWith ( ( h ) - > assertThat ( h . getStatus ( ) ) . isEqualTo ( Status . UP ) )
. verifyComplete ( ) ;
}
@Test
void healthWithOneHealthyNodeAndOneForcedDownNodeShouldReturnUp ( ) {
CqlSession session = mockCqlSessionWithNodeState ( NodeState . UP , NodeState . FORCED_DOWN ) ;
CassandraDriverReactiveHealthIndicator healthIndicator = new CassandraDriverReactiveHealthIndicator ( session ) ;
Mono < Health > health = healthIndicator . health ( ) ;
StepVerifier . create ( health ) . consumeNextWith ( ( h ) - > assertThat ( h . getStatus ( ) ) . isEqualTo ( Status . UP ) )
. verifyComplete ( ) ;
}
@Test
void healthWithNodeVersionShouldAddVersionDetail ( ) {
CqlSession session = mock ( CqlSession . class ) ;
ReactiveResultSet results = mock ( ReactiveResultSet . class ) ;
ReactiveRow row = mock ( ReactiveRow . class ) ;
given ( session . executeReactive ( any ( SimpleStatement . class ) ) ) . willReturn ( results ) ;
willAnswer ( mockReactiveResultSetBehavior ( row ) ) . given ( results ) . subscribe ( any ( ) ) ;
given ( row . getString ( 0 ) ) . willReturn ( "6.0.0" ) ;
CassandraDriverReactiveHealthIndicator cassandraReactiveHealthIndicator = new CassandraDriverReactiveHealthIndicator (
session ) ;
Mono < Health > health = cassandraReactiveHealthIndicator . health ( ) ;
Metadata metadata = mock ( Metadata . class ) ;
given( session . getMetadata ( ) ) . willReturn ( metadata ) ;
Node node = mock ( Node . clas s) ;
given( node . getState ( ) ) . willReturn ( NodeState . UP ) ;
given ( node. getCassandraVersion ( ) ) . willReturn ( Version . V4_0_0 ) ;
given( metadata . getNodes ( ) ) . willReturn ( createNodesWithRandomUUID ( Collections . singletonList ( node ) ) ) ;
CassandraDriverReactiveHealthIndicator healthIndicator = new CassandraDriverReactiveHealthIndicator ( session ) ;
Mono < Health > health = h ealthIndicator. health ( ) ;
StepVerifier . create ( health ) . consumeNextWith ( ( h ) - > {
assertThat ( h . getStatus ( ) ) . isEqualTo ( Status . UP ) ;
assertThat ( h . getDetails ( ) ) . containsOnlyKeys ( "version" ) ;
assertThat ( h . getDetails ( ) . get ( "version" ) ) . isEqualTo ( "6.0.0" ) ;
assertThat ( h . getDetails ( ) . get ( "version" ) ) . isEqualTo ( Version . V4_0_0 ) ;
} ) . verifyComplete ( ) ;
}
@Test
void testCassandraIsDown ( ) {
void healthWithoutNodeVersionShouldNotAddVersionDetail ( ) {
CqlSession session = mockCqlSessionWithNodeState ( NodeState . UP ) ;
CassandraDriverReactiveHealthIndicator healthIndicator = new CassandraDriverReactiveHealthIndicator ( session ) ;
Mono < Health > health = healthIndicator . health ( ) ;
StepVerifier . create ( health ) . consumeNextWith ( ( h ) - > {
assertThat ( h . getStatus ( ) ) . isEqualTo ( Status . UP ) ;
assertThat ( h . getDetails ( ) . get ( "version" ) ) . isNull ( ) ;
} ) . verifyComplete ( ) ;
}
@Test
void healthWithCassandraDownShouldReturnDown ( ) {
CqlSession session = mock ( CqlSession . class ) ;
given ( session . executeReactive ( any ( SimpleStatement . class ) ) )
. willThrow ( new DriverTimeoutException ( "Test Exception" ) ) ;
given ( session . getMetadata ( ) ) . willThrow ( new DriverTimeoutException ( "Test Exception" ) ) ;
CassandraDriverReactiveHealthIndicator cassandraReactiveHealthIndicator = new CassandraDriverReactiveHealthIndicator (
session ) ;
Mono < Health > health = cassandraReactiveHealthIndicator . health ( ) ;
@ -84,23 +160,24 @@ class CassandraDriverReactiveHealthIndicatorTests {
} ) . verifyComplete ( ) ;
}
private Answer < Void > mockReactiveResultSetBehavior ( ReactiveRow row ) {
return ( invocation ) - > {
Subscriber < ReactiveRow > subscriber = invocation . getArgument ( 0 ) ;
Subscription s = new Subscription ( ) {
@Override
public void request ( long n ) {
subscriber . onNext ( row ) ;
subscriber . onComplete ( ) ;
}
@Override
public void cancel ( ) {
}
} ;
subscriber . onSubscribe ( s ) ;
return null ;
} ;
private CqlSession mockCqlSessionWithNodeState ( NodeState . . . nodeStates ) {
CqlSession session = mock ( CqlSession . class ) ;
Metadata metadata = mock ( Metadata . class ) ;
List < Node > nodes = new ArrayList < > ( ) ;
for ( NodeState nodeState : nodeStates ) {
Node node = mock ( Node . class ) ;
given ( node . getState ( ) ) . willReturn ( nodeState ) ;
nodes . add ( node ) ;
}
given ( session . getMetadata ( ) ) . willReturn ( metadata ) ;
given ( metadata . getNodes ( ) ) . willReturn ( createNodesWithRandomUUID ( nodes ) ) ;
return session ;
}
private Map < UUID , Node > createNodesWithRandomUUID ( List < Node > nodes ) {
Map < UUID , Node > indexedNodes = new HashMap < > ( ) ;
nodes . forEach ( ( node ) - > indexedNodes . put ( UUID . randomUUID ( ) , node ) ) ;
return indexedNodes ;
}
}