|
22 | 22 | import static org.hamcrest.junit.MatcherAssert.assertThat;
|
23 | 23 | import static org.junit.jupiter.api.Assertions.assertEquals;
|
24 | 24 | import static org.junit.jupiter.api.Assertions.assertFalse;
|
| 25 | +import static org.junit.jupiter.api.Assertions.assertInstanceOf; |
| 26 | +import static org.junit.jupiter.api.Assertions.assertNotNull; |
| 27 | +import static org.junit.jupiter.api.Assertions.assertNull; |
| 28 | +import static org.neo4j.driver.internal.async.connection.ChannelAttributes.setConnectionReadTimeout; |
25 | 29 | import static org.neo4j.driver.internal.async.connection.ChannelAttributes.setCreationTimestamp;
|
26 | 30 | import static org.neo4j.driver.internal.async.connection.ChannelAttributes.setLastUsedTimestamp;
|
27 | 31 | import static org.neo4j.driver.internal.async.connection.ChannelAttributes.setMessageDispatcher;
|
|
34 | 38 | import static org.neo4j.driver.util.TestUtil.await;
|
35 | 39 |
|
36 | 40 | import io.netty.channel.Channel;
|
| 41 | +import io.netty.channel.ChannelHandler; |
37 | 42 | import io.netty.channel.embedded.EmbeddedChannel;
|
38 | 43 | import io.netty.util.concurrent.Future;
|
39 | 44 | import java.util.Collections;
|
|
46 | 51 | import org.junit.jupiter.api.Test;
|
47 | 52 | import org.neo4j.driver.Value;
|
48 | 53 | import org.neo4j.driver.exceptions.AuthorizationExpiredException;
|
| 54 | +import org.neo4j.driver.internal.async.inbound.ConnectionReadTimeoutHandler; |
49 | 55 | import org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher;
|
50 | 56 | import org.neo4j.driver.internal.messaging.request.ResetMessage;
|
51 | 57 | import org.neo4j.driver.internal.util.Clock;
|
@@ -155,6 +161,65 @@ void shouldKeepIdleConnectionWhenPingSucceeds() {
|
155 | 161 | testPing(true);
|
156 | 162 | }
|
157 | 163 |
|
| 164 | + @Test |
| 165 | + void shouldHandlePingWithConnectionReceiveTimeout() { |
| 166 | + int idleTimeBeforeConnectionTest = 1000; |
| 167 | + long connectionReadTimeout = 60L; |
| 168 | + PoolSettings settings = new PoolSettings( |
| 169 | + DEFAULT_MAX_CONNECTION_POOL_SIZE, |
| 170 | + DEFAULT_CONNECTION_ACQUISITION_TIMEOUT, |
| 171 | + NOT_CONFIGURED, |
| 172 | + idleTimeBeforeConnectionTest); |
| 173 | + Clock clock = Clock.SYSTEM; |
| 174 | + NettyChannelHealthChecker healthChecker = newHealthChecker(settings, clock); |
| 175 | + |
| 176 | + setCreationTimestamp(channel, clock.millis()); |
| 177 | + setConnectionReadTimeout(channel, connectionReadTimeout); |
| 178 | + setLastUsedTimestamp(channel, clock.millis() - idleTimeBeforeConnectionTest * 2); |
| 179 | + |
| 180 | + Future<Boolean> healthy = healthChecker.isHealthy(channel); |
| 181 | + channel.runPendingTasks(); |
| 182 | + |
| 183 | + ChannelHandler firstElementOnPipeline = channel.pipeline().first(); |
| 184 | + assertInstanceOf(ConnectionReadTimeoutHandler.class, firstElementOnPipeline); |
| 185 | + assertNotNull(dispatcher.getBeforeLastHandlerHook()); |
| 186 | + ConnectionReadTimeoutHandler readTimeoutHandler = (ConnectionReadTimeoutHandler) firstElementOnPipeline; |
| 187 | + assertEquals(connectionReadTimeout * 1000L, readTimeoutHandler.getReaderIdleTimeInMillis()); |
| 188 | + assertEquals(ResetMessage.RESET, single(channel.outboundMessages())); |
| 189 | + assertFalse(healthy.isDone()); |
| 190 | + |
| 191 | + dispatcher.handleSuccessMessage(Collections.emptyMap()); |
| 192 | + assertThat(await(healthy), is(true)); |
| 193 | + assertNull(channel.pipeline().first()); |
| 194 | + assertNull(dispatcher.getBeforeLastHandlerHook()); |
| 195 | + } |
| 196 | + |
| 197 | + @Test |
| 198 | + void shouldHandlePingWithoutConnectionReceiveTimeout() { |
| 199 | + int idleTimeBeforeConnectionTest = 1000; |
| 200 | + PoolSettings settings = new PoolSettings( |
| 201 | + DEFAULT_MAX_CONNECTION_POOL_SIZE, |
| 202 | + DEFAULT_CONNECTION_ACQUISITION_TIMEOUT, |
| 203 | + NOT_CONFIGURED, |
| 204 | + idleTimeBeforeConnectionTest); |
| 205 | + Clock clock = Clock.SYSTEM; |
| 206 | + NettyChannelHealthChecker healthChecker = newHealthChecker(settings, clock); |
| 207 | + |
| 208 | + setCreationTimestamp(channel, clock.millis()); |
| 209 | + setLastUsedTimestamp(channel, clock.millis() - idleTimeBeforeConnectionTest * 2); |
| 210 | + |
| 211 | + Future<Boolean> healthy = healthChecker.isHealthy(channel); |
| 212 | + channel.runPendingTasks(); |
| 213 | + |
| 214 | + assertNull(channel.pipeline().first()); |
| 215 | + assertEquals(ResetMessage.RESET, single(channel.outboundMessages())); |
| 216 | + assertFalse(healthy.isDone()); |
| 217 | + |
| 218 | + dispatcher.handleSuccessMessage(Collections.emptyMap()); |
| 219 | + assertThat(await(healthy), is(true)); |
| 220 | + assertNull(channel.pipeline().first()); |
| 221 | + } |
| 222 | + |
158 | 223 | @Test
|
159 | 224 | void shouldDropIdleConnectionWhenPingFails() {
|
160 | 225 | testPing(false);
|
|
0 commit comments