|
34 | 34 | import org.bson.BsonDocument; |
35 | 35 | import org.bson.ByteBufNIO; |
36 | 36 | import org.junit.jupiter.api.AfterEach; |
| 37 | +import org.junit.jupiter.api.Assertions; |
37 | 38 | import org.junit.jupiter.api.Test; |
38 | 39 | import org.opentest4j.AssertionFailedError; |
39 | 40 |
|
@@ -254,6 +255,66 @@ public void serverHeartbeatFailed(final ServerHeartbeatFailedEvent event) { |
254 | 255 | assertEquals(expectedEvents, events); |
255 | 256 | } |
256 | 257 |
|
| 258 | + @Test |
| 259 | + void shouldSendHeartbeatEventAfterInitialConnectionInPollMode() throws Exception { |
| 260 | + // This test verifies that in POLL mode with a long heartbeat frequency, |
| 261 | + // the monitor still fires a ServerHeartbeatSucceededEvent shortly after initial connection. |
| 262 | + // This is critical for some unified tests like backpressure-network-error-fail.yml that rely on |
| 263 | + // receiving an initial heartbeat event even with very long polling intervals. |
| 264 | + |
| 265 | + // Given |
| 266 | + ConnectionDescription connectionDescription = createDefaultConnectionDescription(); |
| 267 | + ServerDescription initialServerDescription = createDefaultServerDescription(); |
| 268 | + String helloResponse = "{" |
| 269 | + + LEGACY_HELLO_LOWER + ": true," |
| 270 | + + "maxBsonObjectSize : 16777216, " |
| 271 | + + "maxMessageSizeBytes : 48000000, " |
| 272 | + + "maxWriteBatchSize : 1000, " |
| 273 | + + "localTime : ISODate(\"2016-04-05T20:36:36.082Z\"), " |
| 274 | + + "maxWireVersion : 4, " |
| 275 | + + "minWireVersion : 0, " |
| 276 | + + "ok : 1 " |
| 277 | + + "}"; |
| 278 | + |
| 279 | + InternalConnection mockConnection = mock(InternalConnection.class); |
| 280 | + when(mockConnection.getDescription()).thenReturn(connectionDescription); |
| 281 | + when(mockConnection.getInitialServerDescription()).thenReturn(initialServerDescription); |
| 282 | + when(mockConnection.getBuffer(anyInt())).thenReturn(new ByteBufNIO(ByteBuffer.allocate(1024))); |
| 283 | + when(mockConnection.receive(any(), any())).thenReturn(BsonDocument.parse(helloResponse)); |
| 284 | + |
| 285 | + // When |
| 286 | + TestServerMonitorListener listener = createTestServerMonitorListener(); |
| 287 | + // Create monitor explicitly in POLL mode with long heartbeat frequency |
| 288 | + DefaultServerMonitor monitor = new DefaultServerMonitor( |
| 289 | + new ServerId(new ClusterId(), new ServerAddress()), |
| 290 | + ServerSettings.builder() |
| 291 | + .heartbeatFrequency(10000, TimeUnit.MILLISECONDS) |
| 292 | + .serverMonitoringMode(com.mongodb.connection.ServerMonitoringMode.POLL) |
| 293 | + .addServerMonitorListener(listener) |
| 294 | + .build(), |
| 295 | + createConnectionFactory(mockConnection), |
| 296 | + ClusterConnectionMode.SINGLE, |
| 297 | + null, |
| 298 | + false, |
| 299 | + SameObjectProvider.initialized(mock(SdamServerDescriptionManager.class)), |
| 300 | + OPERATION_CONTEXT_FACTORY); |
| 301 | + monitor.start(); |
| 302 | + this.monitor = monitor; |
| 303 | + |
| 304 | + // Wait for heartbeat event - should happen quickly despite long heartbeatFrequency |
| 305 | + listener.waitForEvents(ServerHeartbeatSucceededEvent.class, event -> true, 1, Duration.ofSeconds(2)); |
| 306 | + ServerHeartbeatStartedEvent startedEvent = getEvent(ServerHeartbeatStartedEvent.class, listener); |
| 307 | + ServerHeartbeatSucceededEvent succeededEvent = getEvent(ServerHeartbeatSucceededEvent.class, listener); |
| 308 | + |
| 309 | + // Then |
| 310 | + assertEquals(connectionDescription.getConnectionId(), startedEvent.getConnectionId()); |
| 311 | + assertEquals(connectionDescription.getConnectionId(), succeededEvent.getConnectionId()); |
| 312 | + assertEquals(BsonDocument.parse(helloResponse), succeededEvent.getReply()); |
| 313 | + assertTrue(succeededEvent.getElapsedTime(TimeUnit.NANOSECONDS) > 0); |
| 314 | + // The event should not be awaited in POLL mode |
| 315 | + Assertions.assertFalse(succeededEvent.isAwaited()); |
| 316 | + } |
| 317 | + |
257 | 318 |
|
258 | 319 | private InternalConnectionFactory createConnectionFactory(final InternalConnection connection) { |
259 | 320 | InternalConnectionFactory factory = mock(InternalConnectionFactory.class); |
|
0 commit comments