From daed55be365e8c9f3e474e50e251f32159d8ce39 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Wed, 25 Jul 2018 16:23:25 -0700 Subject: [PATCH] Parse HandshakeResponse (#2656) --- .../DefaultJsonProtocolHandShakeMessage.java | 15 -- .../src/main/java/HandshakeProtocol.java | 18 ++ .../main/java/HandshakeRequestMessage.java | 12 ++ .../main/java/HandshakeResponseMessage.java | 14 ++ .../signalr/src/main/java/HubConnection.java | 26 ++- .../signalr/src/main/java/HubProtocol.java | 2 +- .../src/main/java/JsonHubProtocol.java | 8 +- .../src/main/java/WebSocketTransport.java | 1 - .../src/test/java/HandshakeProtocolTest.java | 31 ++++ .../src/test/java/HubConnectionTest.java | 162 ++++++++++++++---- .../src/test/java/JsonHubProtocolTest.java | 14 -- 11 files changed, 226 insertions(+), 77 deletions(-) delete mode 100644 clients/java/signalr/src/main/java/DefaultJsonProtocolHandShakeMessage.java create mode 100644 clients/java/signalr/src/main/java/HandshakeProtocol.java create mode 100644 clients/java/signalr/src/main/java/HandshakeRequestMessage.java create mode 100644 clients/java/signalr/src/main/java/HandshakeResponseMessage.java create mode 100644 clients/java/signalr/src/test/java/HandshakeProtocolTest.java diff --git a/clients/java/signalr/src/main/java/DefaultJsonProtocolHandShakeMessage.java b/clients/java/signalr/src/main/java/DefaultJsonProtocolHandShakeMessage.java deleted file mode 100644 index 7027e0d637..0000000000 --- a/clients/java/signalr/src/main/java/DefaultJsonProtocolHandShakeMessage.java +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -import com.google.gson.Gson; - -public class DefaultJsonProtocolHandShakeMessage { - private String protocol = "json"; - private int version = 1; - private static final String RECORD_SEPARATOR = "\u001e"; - - public String createHandshakeMessage() { - Gson gson = new Gson(); - return gson.toJson(this) + RECORD_SEPARATOR; - } -} diff --git a/clients/java/signalr/src/main/java/HandshakeProtocol.java b/clients/java/signalr/src/main/java/HandshakeProtocol.java new file mode 100644 index 0000000000..322625ce9e --- /dev/null +++ b/clients/java/signalr/src/main/java/HandshakeProtocol.java @@ -0,0 +1,18 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +import com.google.gson.Gson; + +public class HandshakeProtocol { + public static Gson gson = new Gson(); + private static final String RECORD_SEPARATOR = "\u001e"; + + public static String createHandshakeRequestMessage(HandshakeRequestMessage message){ + // The handshake request is always in the JSON format + return gson.toJson(message) + RECORD_SEPARATOR; + } + + public static HandshakeResponseMessage parseHandshakeResponse(String message){ + return gson.fromJson(message, HandshakeResponseMessage.class); + } +} diff --git a/clients/java/signalr/src/main/java/HandshakeRequestMessage.java b/clients/java/signalr/src/main/java/HandshakeRequestMessage.java new file mode 100644 index 0000000000..370de4e513 --- /dev/null +++ b/clients/java/signalr/src/main/java/HandshakeRequestMessage.java @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +public class HandshakeRequestMessage { + String protocol; + int version; + + public HandshakeRequestMessage(String protocol, int version) { + this.protocol = protocol; + this.version = version; + } +} diff --git a/clients/java/signalr/src/main/java/HandshakeResponseMessage.java b/clients/java/signalr/src/main/java/HandshakeResponseMessage.java new file mode 100644 index 0000000000..8b40a79283 --- /dev/null +++ b/clients/java/signalr/src/main/java/HandshakeResponseMessage.java @@ -0,0 +1,14 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +public class HandshakeResponseMessage { + public String error; + + public HandshakeResponseMessage() { + this(null); + } + + public HandshakeResponseMessage(String error) { + this.error = error; + } +} diff --git a/clients/java/signalr/src/main/java/HubConnection.java b/clients/java/signalr/src/main/java/HubConnection.java index c1c80f322a..a310f23b1d 100644 --- a/clients/java/signalr/src/main/java/HubConnection.java +++ b/clients/java/signalr/src/main/java/HubConnection.java @@ -15,6 +15,8 @@ public class HubConnection { private CallbackMap handlers = new CallbackMap(); private HubProtocol protocol; private Gson gson = new Gson(); + private Boolean handshakeReceived = false; + private static final String RECORD_SEPARATOR = "\u001e"; private HubConnectionState connectionState = HubConnectionState.DISCONNECTED; public HubConnection(String url, Transport transport) { @@ -22,6 +24,22 @@ public class HubConnection { this.protocol = new JsonHubProtocol(); this.callback = (payload) -> { + if (!handshakeReceived) { + int handshakeLength = payload.indexOf(RECORD_SEPARATOR) + 1; + String handshakeResponseString = payload.substring(0, handshakeLength - 1); + HandshakeResponseMessage handshakeResponse = HandshakeProtocol.parseHandshakeResponse(handshakeResponseString); + if (handshakeResponse.error != null) { + throw new Exception("Error in handshake " + handshakeResponse.error); + } + handshakeReceived = true; + + payload = payload.substring(handshakeLength); + // The payload only contained the handshake response so we can return. + if (payload.length() == 0) { + return; + } + } + HubMessage[] messages = protocol.parseMessages(payload); for (HubMessage message : messages) { @@ -29,7 +47,7 @@ public class HubConnection { case INVOCATION: InvocationMessage invocationMessage = (InvocationMessage)message; if (message != null && handlers.containsKey(invocationMessage.target)) { - ArrayList args = gson.fromJson((JsonArray)invocationMessage.arguments[0], (new ArrayList()).getClass()); + ArrayList args = gson.fromJson((JsonArray)invocationMessage.arguments[0], (new ArrayList<>()).getClass()); List actions = handlers.get(invocationMessage.target); if (actions != null) { for (ActionBase action: actions) { @@ -40,10 +58,10 @@ public class HubConnection { break; case STREAM_INVOCATION: case STREAM_ITEM: - throw new UnsupportedOperationException("Streaming is not yet supported"); case CLOSE: case CANCEL_INVOCATION: case COMPLETION: + throw new UnsupportedOperationException("The message type " + message.getMessageType() + " is not supported yet."); case PING: // We don't need to do anything in the case of a ping message. // The other message types aren't supported @@ -71,9 +89,11 @@ public class HubConnection { return connectionState; } - public void start() throws InterruptedException { + public void start() throws Exception { transport.setOnReceive(this.callback); transport.start(); + String handshake = HandshakeProtocol.createHandshakeRequestMessage(new HandshakeRequestMessage(protocol.getName(), protocol.getVersion())); + transport.send(handshake); connectionState = HubConnectionState.CONNECTED; } diff --git a/clients/java/signalr/src/main/java/HubProtocol.java b/clients/java/signalr/src/main/java/HubProtocol.java index 39f184e84c..cdb1355758 100644 --- a/clients/java/signalr/src/main/java/HubProtocol.java +++ b/clients/java/signalr/src/main/java/HubProtocol.java @@ -6,6 +6,6 @@ public interface HubProtocol { int getVersion(); TransferFormat getTransferFormat(); HubMessage[] parseMessages(String message); - String writeMessage(InvocationMessage message); + String writeMessage(HubMessage message); } diff --git a/clients/java/signalr/src/main/java/JsonHubProtocol.java b/clients/java/signalr/src/main/java/JsonHubProtocol.java index fcc4b4a2e4..f80c57912b 100644 --- a/clients/java/signalr/src/main/java/JsonHubProtocol.java +++ b/clients/java/signalr/src/main/java/JsonHubProtocol.java @@ -34,10 +34,6 @@ public class JsonHubProtocol implements HubProtocol { String[] messages = payload.split(RECORD_SEPARATOR); List hubMessages = new ArrayList<>(); for (String splitMessage : messages) { - // Empty handshake response "{}". We can ignore it - if (splitMessage.equals("{}")) { - continue; - } JsonObject jsonMessage = jsonParser.parse(splitMessage).getAsJsonObject(); HubMessageType messageType = HubMessageType.values()[jsonMessage.get("type").getAsInt() -1]; @@ -72,7 +68,7 @@ public class JsonHubProtocol implements HubProtocol { } @Override - public String writeMessage(InvocationMessage invocationMessage) { - return gson.toJson(invocationMessage) + RECORD_SEPARATOR; + public String writeMessage(HubMessage hubMessage) { + return gson.toJson(hubMessage) + RECORD_SEPARATOR; } } diff --git a/clients/java/signalr/src/main/java/WebSocketTransport.java b/clients/java/signalr/src/main/java/WebSocketTransport.java index 7eb2edfe17..67378ceb8f 100644 --- a/clients/java/signalr/src/main/java/WebSocketTransport.java +++ b/clients/java/signalr/src/main/java/WebSocketTransport.java @@ -39,7 +39,6 @@ public class WebSocketTransport implements Transport { public void start() throws InterruptedException { webSocketClient = createWebSocket(); webSocketClient.connectBlocking(); - webSocketClient.send((new DefaultJsonProtocolHandShakeMessage()).createHandshakeMessage()); } @Override diff --git a/clients/java/signalr/src/test/java/HandshakeProtocolTest.java b/clients/java/signalr/src/test/java/HandshakeProtocolTest.java new file mode 100644 index 0000000000..ae8f960242 --- /dev/null +++ b/clients/java/signalr/src/test/java/HandshakeProtocolTest.java @@ -0,0 +1,31 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class HandshakeProtocolTest { + + @Test + public void VerifyCreateHandshakerequestMessage() { + HandshakeRequestMessage handshakeRequest = new HandshakeRequestMessage("json", 1); + String result = HandshakeProtocol.createHandshakeRequestMessage(handshakeRequest); + String expectedResult = "{\"protocol\":\"json\",\"version\":1}\u001E"; + assertEquals(expectedResult, result); + } + + @Test + public void VerifyParseEmptyHandshakeResponseMessage() { + String emptyHandshakeResponse = "{}"; + HandshakeResponseMessage hsr = HandshakeProtocol.parseHandshakeResponse(emptyHandshakeResponse); + assertNull(hsr.error); + } + + @Test + public void VerifyParseHandshakeResponseMessage() { + String handshakeResponseWithError = "{\"error\": \"Requested protocol \'messagepack\' is not available.\"}"; + HandshakeResponseMessage hsr = HandshakeProtocol.parseHandshakeResponse(handshakeResponseWithError); + assertEquals(hsr.error, "Requested protocol 'messagepack' is not available."); + } +} \ No newline at end of file diff --git a/clients/java/signalr/src/test/java/HubConnectionTest.java b/clients/java/signalr/src/test/java/HubConnectionTest.java index 5c2662e10e..91cbfef9a3 100644 --- a/clients/java/signalr/src/test/java/HubConnectionTest.java +++ b/clients/java/signalr/src/test/java/HubConnectionTest.java @@ -3,14 +3,17 @@ import org.junit.Test; +import java.util.ArrayList; import java.util.concurrent.atomic.AtomicReference; import static org.junit.Assert.*; public class HubConnectionTest { + private static final String RECORD_SEPARATOR = "\u001e"; + @Test - public void checkHubConnectionState() throws InterruptedException { - Transport mockTransport = new MockEchoTransport(); + public void checkHubConnectionState() throws Exception { + Transport mockTransport = new MockTransport(); HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); hubConnection.start(); assertEquals(HubConnectionState.CONNECTED, hubConnection.getConnectionState()); @@ -22,7 +25,7 @@ public class HubConnectionTest { @Test public void RegisteringMultipleHandlersAndBothGetTriggered() throws Exception { AtomicReference value = new AtomicReference<>(0.0); - Transport mockTransport = new MockEchoTransport(); + MockTransport mockTransport = new MockTransport(); HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); Action action = () -> value.getAndUpdate((val) -> val + 1); @@ -32,7 +35,14 @@ public class HubConnectionTest { assertEquals(0.0, value.get(), 0); hubConnection.start(); - hubConnection.send("inc"); + + String message = mockTransport.getSentMessages()[0]; + String expectedHanshakeRequest = "{\"protocol\":\"json\",\"version\":1}" + RECORD_SEPARATOR; + + assertEquals(expectedHanshakeRequest, message); + + mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); + mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR); // Confirming that our handler was called and that the counter property was incremented. assertEquals(2, value.get(), 0); @@ -41,7 +51,7 @@ public class HubConnectionTest { @Test public void RemoveHandlerByName() throws Exception { AtomicReference value = new AtomicReference<>(0.0); - Transport mockTransport = new MockEchoTransport(); + MockTransport mockTransport = new MockTransport(); HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); Action action = () -> value.getAndUpdate((val) -> val + 1); @@ -50,7 +60,13 @@ public class HubConnectionTest { assertEquals(0.0, value.get(), 0); hubConnection.start(); - hubConnection.send("inc"); + String message = mockTransport.getSentMessages()[0]; + String expectedHanshakeRequest = "{\"protocol\":\"json\",\"version\":1}" + RECORD_SEPARATOR; + + assertEquals(expectedHanshakeRequest, message); + + mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); + mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR); // Confirming that our handler was called and that the counter property was incremented. assertEquals(1, value.get(), 0); @@ -63,7 +79,7 @@ public class HubConnectionTest { @Test public void AddAndRemoveHandlerImmediately() throws Exception { AtomicReference value = new AtomicReference<>(0.0); - Transport mockTransport = new MockEchoTransport(); + MockTransport mockTransport = new MockTransport(); HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); Action action = () -> value.getAndUpdate((val) -> val + 1); @@ -73,7 +89,13 @@ public class HubConnectionTest { assertEquals(0.0, value.get(), 0); hubConnection.start(); - hubConnection.send("inc"); + String message = mockTransport.getSentMessages()[0]; + String expectedHanshakeRequest = "{\"protocol\":\"json\",\"version\":1}" + RECORD_SEPARATOR; + + assertEquals(expectedHanshakeRequest, message); + + mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); + mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR); // Confirming that the handler was removed. assertEquals(0, value.get(), 0); @@ -82,7 +104,7 @@ public class HubConnectionTest { @Test public void RemovingMultipleHandlersWithOneCallToRemove() throws Exception { AtomicReference value = new AtomicReference<>(0.0); - Transport mockTransport = new MockEchoTransport(); + MockTransport mockTransport = new MockTransport(); HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); Action action = () -> value.getAndUpdate((val) -> val + 1); Action secondAction = () -> value.getAndUpdate((val) -> val + 2); @@ -93,12 +115,19 @@ public class HubConnectionTest { assertEquals(0.0, value.get(), 0); hubConnection.start(); - hubConnection.send("inc"); + String message = mockTransport.getSentMessages()[0]; + String expectedHanshakeRequest = "{\"protocol\":\"json\",\"version\":1}" + RECORD_SEPARATOR; + + assertEquals(expectedHanshakeRequest, message); + + mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); + mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR); assertEquals(3, value.get(), 0); hubConnection.remove("inc"); - hubConnection.send("inc"); + + mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR); // Confirm that another invocation doesn't change anything because the handlers have been removed. assertEquals(3, value.get(), 0); @@ -107,7 +136,7 @@ public class HubConnectionTest { @Test public void RemoveHandlerWithUnsubscribe() throws Exception { AtomicReference value = new AtomicReference<>(0.0); - Transport mockTransport = new MockEchoTransport(); + MockTransport mockTransport = new MockTransport(); HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); Action action = () -> value.getAndUpdate((val) -> val + 1); @@ -116,20 +145,26 @@ public class HubConnectionTest { assertEquals(0.0, value.get(), 0); hubConnection.start(); - hubConnection.send("inc"); + String message = mockTransport.getSentMessages()[0]; + String expectedHanshakeRequest = "{\"protocol\":\"json\",\"version\":1}" + RECORD_SEPARATOR; + + assertEquals(expectedHanshakeRequest, message); + + mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); + mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR); // Confirming that our handler was called and that the counter property was incremented. assertEquals(1, value.get(), 0); subscription.unsubscribe(); - hubConnection.send("inc"); + mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR); assertEquals(1, value.get(), 0); } @Test public void UnsubscribeTwice() throws Exception { AtomicReference value = new AtomicReference<>(0.0); - Transport mockTransport = new MockEchoTransport(); + MockTransport mockTransport = new MockTransport(); HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); Action action = () -> value.getAndUpdate((val) -> val + 1); @@ -138,21 +173,27 @@ public class HubConnectionTest { assertEquals(0.0, value.get(), 0); hubConnection.start(); - hubConnection.send("inc"); + String message = mockTransport.getSentMessages()[0]; + String expectedHanshakeRequest = "{\"protocol\":\"json\",\"version\":1}" + RECORD_SEPARATOR; + + assertEquals(expectedHanshakeRequest, message); + + mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); + mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR); // Confirming that our handler was called and that the counter property was incremented. assertEquals(1, value.get(), 0); subscription.unsubscribe(); subscription.unsubscribe(); - hubConnection.send("inc"); + mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR); assertEquals(1, value.get(), 0); } @Test public void RemoveSingleHandlerWithUnsubscribe() throws Exception { AtomicReference value = new AtomicReference<>(0.0); - Transport mockTransport = new MockEchoTransport(); + MockTransport mockTransport = new MockTransport(); HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); Action action = () -> value.getAndUpdate((val) -> val + 1); Action secondAction = () -> value.getAndUpdate((val) -> val + 2); @@ -163,21 +204,26 @@ public class HubConnectionTest { assertEquals(0.0, value.get(), 0); hubConnection.start(); - hubConnection.send("inc"); + String message = mockTransport.getSentMessages()[0]; + String expectedHanshakeRequest = "{\"protocol\":\"json\",\"version\":1}" + RECORD_SEPARATOR; + assertEquals(expectedHanshakeRequest, message); + + mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); + mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR); // Confirming that our handler was called and that the counter property was incremented. assertEquals(3, value.get(), 0); // This removes the first handler so when "inc" is invoked secondAction should still run. subscription.unsubscribe(); - hubConnection.send("inc"); + mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR); assertEquals(5, value.get(), 0); } @Test public void AddAndRemoveHandlerImmediatelyWithSubscribe() throws Exception { AtomicReference value = new AtomicReference<>(0.0); - Transport mockTransport = new MockEchoTransport(); + MockTransport mockTransport = new MockTransport(); HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); Action action = () -> value.getAndUpdate((val) -> val + 1); @@ -187,8 +233,8 @@ public class HubConnectionTest { assertEquals(0.0, value.get(), 0); hubConnection.start(); - hubConnection.send("inc"); - + mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); + mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR); // Confirming that the handler was removed. assertEquals(0, value.get(), 0); } @@ -196,7 +242,7 @@ public class HubConnectionTest { @Test public void RegisteringMultipleHandlersThatTakeParamsAndBothGetTriggered() throws Exception { AtomicReference value = new AtomicReference<>(0.0); - Transport mockTransport = new MockEchoTransport(); + MockTransport mockTransport = new MockTransport(); HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); Action1 action = (number) -> value.getAndUpdate((val) -> val + number); @@ -206,6 +252,8 @@ public class HubConnectionTest { assertEquals(0, value.get(), 0); hubConnection.start(); + mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); + mockTransport.receiveMessage("{\"type\":1,\"target\":\"add\",\"arguments\":[12]}" + RECORD_SEPARATOR); hubConnection.send("add", 12); // Confirming that our handler was called and the correct message was passed in. @@ -216,7 +264,7 @@ public class HubConnectionTest { @Test public void SendWithNoParamsTriggersOnHandler() throws Exception { AtomicReference value = new AtomicReference(0.0); - Transport mockTransport = new MockEchoTransport(); + MockTransport mockTransport = new MockTransport(); HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); hubConnection.on("inc", () ->{ @@ -225,7 +273,8 @@ public class HubConnectionTest { }); hubConnection.start(); - hubConnection.send("inc"); + mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); + mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR); // Confirming that our handler was called and that the counter property was incremented. assertEquals(1, value.get(), 0); @@ -234,7 +283,7 @@ public class HubConnectionTest { @Test public void SendWithParamTriggersOnHandler() throws Exception { AtomicReference value = new AtomicReference<>(); - Transport mockTransport = new MockEchoTransport(); + MockTransport mockTransport = new MockTransport(); HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); hubConnection.on("inc", (param) ->{ @@ -243,6 +292,8 @@ public class HubConnectionTest { }, String.class); hubConnection.start(); + mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); + mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[\"Hello World\"]}" + RECORD_SEPARATOR); hubConnection.send("inc", "Hello World"); // Confirming that our handler was called and the correct message was passed in. @@ -254,7 +305,7 @@ public class HubConnectionTest { AtomicReference value1 = new AtomicReference<>(); AtomicReference value2 = new AtomicReference<>(); - Transport mockTransport = new MockEchoTransport(); + MockTransport mockTransport = new MockTransport(); HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); hubConnection.on("inc", (param1, param2) ->{ @@ -266,6 +317,8 @@ public class HubConnectionTest { }, String.class, Double.class); hubConnection.start(); + mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); + mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[\"Hello World\", 12]}" + RECORD_SEPARATOR); hubConnection.send("inc", "Hello World", 12); // Confirming that our handler was called and the correct message was passed in. @@ -279,7 +332,7 @@ public class HubConnectionTest { AtomicReference value2 = new AtomicReference<>(); AtomicReference value3 = new AtomicReference<>(); - Transport mockTransport = new MockEchoTransport(); + MockTransport mockTransport = new MockTransport(); HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); hubConnection.on("inc", (param1, param2, param3) ->{ @@ -293,6 +346,8 @@ public class HubConnectionTest { }, String.class, String.class, String.class); hubConnection.start(); + mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); + mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[\"A\", \"B\", \"C\"]}" + RECORD_SEPARATOR); hubConnection.send("inc", "A", "B", "C"); // Confirming that our handler was called and the correct message was passed in. @@ -308,7 +363,7 @@ public class HubConnectionTest { AtomicReference value3 = new AtomicReference<>(); AtomicReference value4 = new AtomicReference<>(); - Transport mockTransport = new MockEchoTransport(); + MockTransport mockTransport = new MockTransport(); HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); hubConnection.on("inc", (param1, param2, param3, param4) ->{ @@ -324,7 +379,8 @@ public class HubConnectionTest { }, String.class, String.class, String.class, String.class); hubConnection.start(); - hubConnection.send("inc", "A", "B", "C", "D"); + mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); + mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[\"A\", \"B\", \"C\", \"D\"]}" + RECORD_SEPARATOR); // Confirming that our handler was called and the correct message was passed in. assertEquals("A", value1.get()); @@ -341,7 +397,7 @@ public class HubConnectionTest { AtomicReference value4 = new AtomicReference<>(); AtomicReference value5 = new AtomicReference<>(); - Transport mockTransport = new MockEchoTransport(); + MockTransport mockTransport = new MockTransport(); HubConnection hubConnection = new HubConnection("http://example.com", mockTransport); hubConnection.on("inc", (param1, param2, param3, param4, param5) ->{ @@ -359,7 +415,8 @@ public class HubConnectionTest { }, String.class, String.class, String.class, Boolean.class, Double.class); hubConnection.start(); - hubConnection.send("inc", "A", "B", "C", true, 12.0); + mockTransport.receiveMessage("{}" + RECORD_SEPARATOR); + mockTransport.receiveMessage("{\"type\":1,\"target\":\"inc\",\"arguments\":[\"A\", \"B\", \"C\",true,12 ]}" + RECORD_SEPARATOR); // Confirming that our handler was called and the correct message was passed in. assertEquals("A", value1.get()); @@ -369,15 +426,38 @@ public class HubConnectionTest { assertEquals(12, value5.get(), 0); } - private class MockEchoTransport implements Transport { + @Test + public void ReceiveHandshakeResponseAndMessage() throws Exception { + AtomicReference value = new AtomicReference(0.0); + MockTransport transport = new MockTransport(); + HubConnection hubConnection = new HubConnection("http://example.com", transport); + + hubConnection.on("inc", () ->{ + assertEquals(0.0, value.get(), 0); + value.getAndUpdate((val) -> val + 1); + }); + + // On start we're going to receive the handshake response and also an invocation in the same payload. + hubConnection.start(); + String expectedSentMessage = "{\"protocol\":\"json\",\"version\":1}" + RECORD_SEPARATOR; + assertEquals(expectedSentMessage, transport.getSentMessages()[0]); + + transport.receiveMessage("{}" + RECORD_SEPARATOR + "{\"type\":1,\"target\":\"inc\",\"arguments\":[]}" + RECORD_SEPARATOR); + + // Confirming that our handler was called and that the counter property was incremented. + assertEquals(1, value.get(), 0); + } + + private class MockTransport implements Transport { private OnReceiveCallBack onReceiveCallBack; + private ArrayList sentMessages = new ArrayList<>(); @Override public void start() {} @Override - public void send(String message) throws Exception { - this.onReceive(message); + public void send(String message) { + sentMessages.add(message); } @Override @@ -391,6 +471,14 @@ public class HubConnectionTest { } @Override - public void stop() {return;} + public void stop() {} + + public void receiveMessage(String message) throws Exception { + this.onReceive(message); + } + + public String[] getSentMessages(){ + return sentMessages.toArray(new String[sentMessages.size()]); + } } } \ No newline at end of file diff --git a/clients/java/signalr/src/test/java/JsonHubProtocolTest.java b/clients/java/signalr/src/test/java/JsonHubProtocolTest.java index ce29d57c35..4d6e2fd6d1 100644 --- a/clients/java/signalr/src/test/java/JsonHubProtocolTest.java +++ b/clients/java/signalr/src/test/java/JsonHubProtocolTest.java @@ -10,7 +10,6 @@ import static org.junit.Assert.*; public class JsonHubProtocolTest { private JsonHubProtocol jsonHubProtocol = new JsonHubProtocol(); - private static final String RECORD_SEPARATOR = "\u001e"; @Test public void checkProtocolName() { @@ -84,19 +83,6 @@ public class JsonHubProtocolTest { HubMessage[] messages = jsonHubProtocol.parseMessages(stringifiedMessage); } - @Test - public void ParseHandshakeResponsePlusMessage() { - String twoMessages = "{}\u001E{\"type\":1,\"target\":\"test\",\"arguments\":[42]}\u001E"; - HubMessage[] messages = jsonHubProtocol.parseMessages(twoMessages); - assertEquals(HubMessageType.INVOCATION, messages[0].getMessageType()); - - //We ignore the Handshake response for now and we can cast because we know we have in invocation message. - InvocationMessage message = (InvocationMessage) messages[0]; - assertEquals("test", message.target); - JsonArray messageResult = (JsonArray) message.arguments[0]; - assertEquals(42, messageResult.getAsInt()); - } - @Test public void ParseTwoMessages() { String twoMessages = "{\"type\":1,\"target\":\"one\",\"arguments\":[42]}\u001E{\"type\":1,\"target\":\"two\",\"arguments\":[43]}\u001E";