|
11 | 11 | ******************************************************************************/ |
12 | 12 | package org.eclipse.lsp4j.jsonrpc.test; |
13 | 13 |
|
14 | | -import org.eclipse.lsp4j.jsonrpc.*; |
15 | | -import org.eclipse.lsp4j.jsonrpc.TracingMessageConsumer.RequestMetadata; |
16 | | -import org.eclipse.lsp4j.jsonrpc.json.MessageJsonHandler; |
17 | | -import org.eclipse.lsp4j.jsonrpc.json.StreamMessageConsumer; |
18 | | -import org.eclipse.lsp4j.jsonrpc.messages.*; |
19 | | -import org.junit.Test; |
| 14 | +import static java.util.Collections.emptyMap; |
| 15 | +import static org.junit.Assert.*; |
20 | 16 |
|
21 | 17 | import java.io.ByteArrayOutputStream; |
22 | 18 | import java.io.File; |
|
27 | 23 | import java.time.Clock; |
28 | 24 | import java.time.Instant; |
29 | 25 | import java.time.ZoneId; |
| 26 | +import java.util.ArrayList; |
30 | 27 | import java.util.HashMap; |
31 | 28 | import java.util.Locale; |
32 | 29 | import java.util.Map; |
33 | 30 | import java.util.concurrent.CompletableFuture; |
34 | 31 |
|
35 | | -import static java.util.Collections.emptyMap; |
36 | | -import static org.junit.Assert.assertEquals; |
| 32 | +import org.eclipse.lsp4j.jsonrpc.Endpoint; |
| 33 | +import org.eclipse.lsp4j.jsonrpc.JsonRpcException; |
| 34 | +import org.eclipse.lsp4j.jsonrpc.MessageConsumer; |
| 35 | +import org.eclipse.lsp4j.jsonrpc.MessageIssueException; |
| 36 | +import org.eclipse.lsp4j.jsonrpc.RemoteEndpoint; |
| 37 | +import org.eclipse.lsp4j.jsonrpc.TracingMessageConsumer; |
| 38 | +import org.eclipse.lsp4j.jsonrpc.TracingMessageConsumer.RequestMetadata; |
| 39 | +import org.eclipse.lsp4j.jsonrpc.json.MessageJsonHandler; |
| 40 | +import org.eclipse.lsp4j.jsonrpc.json.StreamMessageConsumer; |
| 41 | +import org.eclipse.lsp4j.jsonrpc.messages.Message; |
| 42 | +import org.eclipse.lsp4j.jsonrpc.messages.NotificationMessage; |
| 43 | +import org.eclipse.lsp4j.jsonrpc.messages.RequestMessage; |
| 44 | +import org.eclipse.lsp4j.jsonrpc.messages.ResponseError; |
| 45 | +import org.eclipse.lsp4j.jsonrpc.messages.ResponseMessage; |
| 46 | +import org.junit.Test; |
37 | 47 |
|
38 | 48 | public class TracingMessageConsumerTest { |
39 | 49 | private static final RemoteEndpoint TEST_REMOTE_ENDPOINT = new EmptyRemoteEndpoint(); |
@@ -299,6 +309,72 @@ public void testSendingNotificationWithCustomAdapter() { |
299 | 309 |
|
300 | 310 | assertEquals(expectedTrace, actualTrace); |
301 | 311 | } |
| 312 | + |
| 313 | + @Test |
| 314 | + public void testNoUnmatchedResponseWhenOutgoingIsNotStreamConsumer() { |
| 315 | + // Simulate an outgoing transport that is not StreamMessageConsumer (e.g., websocket) |
| 316 | + var outgoingTrace = new StringWriter(); |
| 317 | + var outgoingPrintWriter = new PrintWriter(outgoingTrace); |
| 318 | + |
| 319 | + var incomingTrace = new StringWriter(); |
| 320 | + var incomingPrintWriter = new PrintWriter(incomingTrace); |
| 321 | + |
| 322 | + var sentRequests = new HashMap<String, RequestMetadata>(); |
| 323 | + var receivedRequests = new HashMap<String, RequestMetadata>(); |
| 324 | + |
| 325 | + // Pass a non-RemoteEndpoint consumer so TracingMessageConsumer treats messages as outgoing ("Sending") |
| 326 | + var outgoingTracing = new TracingMessageConsumer(new EmptyMessageConsumer(), sentRequests, receivedRequests, outgoingPrintWriter, TEST_CLOCK_1, Locale.US); |
| 327 | + |
| 328 | + // Send a request |
| 329 | + var req = new RequestMessage(); |
| 330 | + req.setId("1"); |
| 331 | + req.setMethod("foo"); |
| 332 | + outgoingTracing.consume(req); |
| 333 | + |
| 334 | + // Prepare to capture warnings from TracingMessageConsumer |
| 335 | + var logger = java.util.logging.Logger.getLogger(TracingMessageConsumer.class.getName()); |
| 336 | + var warnings = new ArrayList<String>(); |
| 337 | + var handler = new java.util.logging.Handler() { |
| 338 | + @Override |
| 339 | + public void publish(java.util.logging.LogRecord record) { |
| 340 | + if (record.getLevel() == java.util.logging.Level.WARNING) |
| 341 | + warnings.add(record.getMessage()); |
| 342 | + } |
| 343 | + |
| 344 | + @Override |
| 345 | + public void flush() { |
| 346 | + } |
| 347 | + |
| 348 | + @Override |
| 349 | + public void close() throws SecurityException { |
| 350 | + } |
| 351 | + }; |
| 352 | + logger.addHandler(handler); |
| 353 | + try { |
| 354 | + // Now receive a response on the RemoteEndpoint path. Expected behavior (desired): |
| 355 | + // no warnings and a proper response trace even when the outgoing transport |
| 356 | + // is not a StreamMessageConsumer (e.g., websockets). |
| 357 | + var incomingTracing = new TracingMessageConsumer(TEST_REMOTE_ENDPOINT, sentRequests, receivedRequests, incomingPrintWriter, TEST_CLOCK_2, Locale.US); |
| 358 | + |
| 359 | + var resp = new ResponseMessage(); |
| 360 | + resp.setId("1"); |
| 361 | + resp.setResult("ok"); |
| 362 | + incomingTracing.consume(resp); |
| 363 | + |
| 364 | + // Assert NO warning and a proper trace line for the response |
| 365 | + boolean sawUnmatched = warnings.stream().anyMatch(m -> m.contains("Unmatched response message")); |
| 366 | + assertFalse("Did not expect unmatched response warning", sawUnmatched); |
| 367 | + String expectedTrace = "" + |
| 368 | + "[Trace - 06:07:30 PM] Received response 'foo - (1)' in 100ms\n" + |
| 369 | + "Result: \"ok\"\n" + |
| 370 | + "Error: null\n" + |
| 371 | + "\n" + |
| 372 | + "\n"; |
| 373 | + assertEquals(expectedTrace, incomingTrace.toString()); |
| 374 | + } finally { |
| 375 | + logger.removeHandler(handler); |
| 376 | + } |
| 377 | + } |
302 | 378 | } |
303 | 379 |
|
304 | 380 | class EmptyRemoteEndpoint extends RemoteEndpoint { |
|
0 commit comments