1717
1818import static org .assertj .core .api .Assertions .assertThat ;
1919import static org .mockito .Mockito .inOrder ;
20+ import static org .mockito .Mockito .timeout ;
2021import static org .mockito .Mockito .verify ;
2122
2223import com .datastax .oss .driver .api .core .CqlSession ;
3334import com .datastax .oss .driver .api .testinfra .session .SessionUtils ;
3435import com .datastax .oss .driver .api .testinfra .simulacron .SimulacronRule ;
3536import com .datastax .oss .driver .categories .ParallelizableTests ;
37+ import com .datastax .oss .driver .shaded .guava .common .util .concurrent .Uninterruptibles ;
3638import com .datastax .oss .simulacron .common .cluster .ClusterSpec ;
3739import edu .umd .cs .findbugs .annotations .NonNull ;
3840import java .util .Collections ;
41+ import java .util .concurrent .CountDownLatch ;
42+ import java .util .concurrent .TimeUnit ;
3943import org .junit .ClassRule ;
4044import org .junit .Test ;
4145import org .junit .experimental .categories .Category ;
@@ -90,6 +94,9 @@ public void should_inject_session_in_listeners() throws Exception {
9094 .build ())
9195 .build ()) {
9296
97+ // These NodeStateListeners are wrapped with SafeInitNodeStateListener which delays #onUp
98+ // callbacks until #onSessionReady is called, these will all happen during session
99+ // initialization
93100 InOrder inOrder1 = inOrder (nodeListener1 );
94101 inOrder1 .verify (nodeListener1 ).onSessionReady (session );
95102 inOrder1 .verify (nodeListener1 ).onUp (nodeCaptor1 .capture ());
@@ -104,20 +111,29 @@ public void should_inject_session_in_listeners() throws Exception {
104111 assertThat (nodeCaptor2 .getValue ().getEndPoint ())
105112 .isEqualTo (SIMULACRON_RULE .getContactPoints ().iterator ().next ());
106113
107- verify (schemaListener1 ).onSessionReady (session );
108- verify (schemaListener2 ).onSessionReady (session );
114+ // SchemaChangeListener#onSessionReady is called asynchronously from AdminExecutor so we may
115+ // have to wait a little
116+ verify (schemaListener1 , timeout (500 ).times (1 )).onSessionReady (session );
117+ verify (schemaListener2 , timeout (500 ).times (1 )).onSessionReady (session );
109118
119+ // Request tracker #onSessionReady is called synchronously during session initialization
110120 verify (requestTracker1 ).onSessionReady (session );
111121 verify (requestTracker2 ).onSessionReady (session );
112122
113123 assertThat (MyNodeStateListener .onSessionReadyCalled ).isTrue ();
114124 assertThat (MyNodeStateListener .onUpCalled ).isTrue ();
115125
116- assertThat (MySchemaChangeListener .onSessionReadyCalled ).isTrue ();
126+ // SchemaChangeListener#onSessionReady is called asynchronously from AdminExecutor so we may
127+ // have to wait a little
128+ assertThat (
129+ Uninterruptibles .awaitUninterruptibly (
130+ MySchemaChangeListener .onSessionReadyLatch , 500 , TimeUnit .MILLISECONDS ))
131+ .isTrue ();
117132
118133 assertThat (MyRequestTracker .onSessionReadyCalled ).isTrue ();
119134 }
120135
136+ // CqlSession#close waits for all listener close methods to be called
121137 verify (nodeListener1 ).close ();
122138 verify (nodeListener2 ).close ();
123139
@@ -163,14 +179,14 @@ public void close() {
163179
164180 public static class MySchemaChangeListener extends SchemaChangeListenerBase {
165181
166- private static volatile boolean onSessionReadyCalled = false ;
182+ private static CountDownLatch onSessionReadyLatch = new CountDownLatch ( 1 ) ;
167183 private static volatile boolean closeCalled = false ;
168184
169185 public MySchemaChangeListener (@ SuppressWarnings ("unused" ) DriverContext ignored ) {}
170186
171187 @ Override
172188 public void onSessionReady (@ NonNull Session session ) {
173- onSessionReadyCalled = true ;
189+ onSessionReadyLatch . countDown () ;
174190 }
175191
176192 @ Override
0 commit comments