Skip to content

Commit e83f84c

Browse files
committed
added test for client side web socket re-connection logic
1 parent 9f339ce commit e83f84c

File tree

4 files changed

+57
-21
lines changed

4 files changed

+57
-21
lines changed

mockserver-client-java/src/test/java/org/mockserver/client/MockServerClientIntegrationTest.java

+30-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package org.mockserver.client;
22

33
import com.google.common.util.concurrent.SettableFuture;
4+
import io.netty.channel.Channel;
5+
import io.netty.channel.ChannelOutboundInvoker;
6+
import org.hamcrest.core.IsNot;
47
import org.junit.*;
58
import org.junit.rules.ExpectedException;
69
import org.mockserver.echo.http.EchoServer;
@@ -17,6 +20,7 @@
1720
import org.mockserver.verify.VerificationSequence;
1821
import org.mockserver.verify.VerificationTimes;
1922

23+
import java.net.SocketAddress;
2024
import java.util.ArrayList;
2125
import java.util.Arrays;
2226
import java.util.List;
@@ -27,6 +31,7 @@
2731
import static org.hamcrest.core.Is.is;
2832
import static org.hamcrest.core.IsCollectionContaining.hasItems;
2933
import static org.junit.Assert.fail;
34+
import static org.mockito.Matchers.same;
3035
import static org.mockserver.character.Character.NEW_LINE;
3136
import static org.mockserver.matchers.Times.exactly;
3237
import static org.mockserver.matchers.Times.unlimited;
@@ -294,9 +299,7 @@ public void shouldSetupExpectationWithResponseObjectCallback() {
294299
.withPath("/some_path")
295300
.withBody(new StringBody("some_request_body"))
296301
)
297-
.respond(httpRequest -> {
298-
return response();
299-
});
302+
.respond(httpRequest -> response());
300303

301304
// then
302305
assertThat(retrieveRequests(request()).size(), is(1));
@@ -334,6 +337,30 @@ public void shouldSetupExpectationWithResponseObjectCallback() {
334337
}
335338
}
336339

340+
@Test
341+
public void shouldReconnectWebSocketIfClosed() {
342+
// given
343+
echoServerOne.withNextResponse(response().withStatusCode(201));
344+
echoServerOne.getRegisteredClients().clear();
345+
mockServerClientOne
346+
.when(
347+
request()
348+
.withPath("/some_path")
349+
.withBody(new StringBody("some_request_body"))
350+
)
351+
.respond(httpRequest -> response());
352+
353+
// when
354+
assertThat(echoServerOne.getWebsocketChannels().size(), is(1));
355+
Channel initialChannel = echoServerOne.getWebsocketChannels().get(0);
356+
echoServerOne.getWebsocketChannels().forEach(ChannelOutboundInvoker::close);
357+
358+
// then
359+
assertThat(retrieveRequests(request()).size(), is(1));
360+
assertThat(echoServerOne.getWebsocketChannels().size(), is(1));
361+
assertThat(echoServerOne.getWebsocketChannels().get(0), IsNot.not(same(initialChannel)));
362+
}
363+
337364
@Test
338365
public void shouldCloseWebsocketAfterStop() {
339366
// given

mockserver-core/src/main/java/org/mockserver/echo/http/EchoServer.java

+13-9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.google.common.util.concurrent.SettableFuture;
44
import io.netty.bootstrap.ServerBootstrap;
5+
import io.netty.channel.Channel;
56
import io.netty.channel.ChannelFutureListener;
67
import io.netty.channel.ChannelOption;
78
import io.netty.channel.EventLoopGroup;
@@ -19,10 +20,7 @@
1920
import org.slf4j.event.Level;
2021

2122
import java.net.InetSocketAddress;
22-
import java.util.ArrayList;
23-
import java.util.Arrays;
24-
import java.util.LinkedList;
25-
import java.util.Queue;
23+
import java.util.*;
2624
import java.util.concurrent.TimeUnit;
2725

2826

@@ -39,8 +37,9 @@ public class EchoServer implements Stoppable {
3937
private final OnlyResponse onlyResponse = new OnlyResponse();
4038
private final NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
4139
private final SettableFuture<Integer> boundPort = SettableFuture.create();
42-
private final ArrayList<String> registeredClients;
43-
private final ArrayList<TextWebSocketFrame> textWebSocketFrames;
40+
private final List<String> registeredClients;
41+
private final List<Channel> websocketChannels;
42+
private final List<TextWebSocketFrame> textWebSocketFrames;
4443
private EventLoopGroup bossGroup;
4544
private EventLoopGroup workerGroup;
4645

@@ -50,6 +49,7 @@ public EchoServer(final boolean secure) {
5049

5150
public EchoServer(final boolean secure, final Error error) {
5251
registeredClients = new ArrayList<>();
52+
websocketChannels = new ArrayList<>();
5353
textWebSocketFrames = new ArrayList<>();
5454
new Thread(() -> {
5555
bossGroup = new NioEventLoopGroup(1);
@@ -58,7 +58,7 @@ public EchoServer(final boolean secure, final Error error) {
5858
.channel(NioServerSocketChannel.class)
5959
.option(ChannelOption.SO_BACKLOG, 100)
6060
.handler(new LoggingHandler(EchoServer.class))
61-
.childHandler(new EchoServerInitializer(mockServerLogger, secure, error, registeredClients, textWebSocketFrames))
61+
.childHandler(new EchoServerInitializer(mockServerLogger, secure, error, registeredClients, websocketChannels, textWebSocketFrames))
6262
.childAttr(LOG_FILTER, logFilter)
6363
.childAttr(NEXT_RESPONSE, nextResponse)
6464
.childAttr(ONLY_RESPONSE, onlyResponse)
@@ -124,11 +124,15 @@ public EchoServer withOnlyResponse(HttpResponse httpResponse) {
124124
return this;
125125
}
126126

127-
public ArrayList<String> getRegisteredClients() {
127+
public List<String> getRegisteredClients() {
128128
return registeredClients;
129129
}
130130

131-
public ArrayList<TextWebSocketFrame> getTextWebSocketFrames() {
131+
public List<Channel> getWebsocketChannels() {
132+
return websocketChannels;
133+
}
134+
135+
public List<TextWebSocketFrame> getTextWebSocketFrames() {
132136
return textWebSocketFrames;
133137
}
134138

mockserver-core/src/main/java/org/mockserver/echo/http/EchoServerInitializer.java

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.mockserver.echo.http;
22

3+
import io.netty.channel.Channel;
34
import io.netty.channel.ChannelInitializer;
45
import io.netty.channel.ChannelPipeline;
56
import io.netty.channel.socket.SocketChannel;
@@ -13,6 +14,7 @@
1314
import org.mockserver.socket.tls.NettySslContextFactory;
1415

1516
import java.util.ArrayList;
17+
import java.util.List;
1618

1719
import static org.mockserver.echo.http.EchoServer.*;
1820
import static org.slf4j.event.Level.TRACE;
@@ -25,17 +27,19 @@ public class EchoServerInitializer extends ChannelInitializer<SocketChannel> {
2527
private final MockServerLogger mockServerLogger;
2628
private final boolean secure;
2729
private final EchoServer.Error error;
28-
private final ArrayList<TextWebSocketFrame> textWebSocketFrames;
29-
private final ArrayList<String> registeredClients;
30+
private final List<TextWebSocketFrame> textWebSocketFrames;
31+
private final List<Channel> websocketChannels;
32+
private final List<String> registeredClients;
3033

31-
EchoServerInitializer(MockServerLogger mockServerLogger, boolean secure, EchoServer.Error error, ArrayList<String> registeredClients, ArrayList<TextWebSocketFrame> textWebSocketFrames) {
34+
EchoServerInitializer(MockServerLogger mockServerLogger, boolean secure, EchoServer.Error error, List<String> registeredClients, List<Channel> websocketChannels, List<TextWebSocketFrame> textWebSocketFrames) {
3235
if (!secure && error == EchoServer.Error.CLOSE_CONNECTION) {
3336
throw new IllegalArgumentException("Error type CLOSE_CONNECTION is not supported in non-secure mode");
3437
}
3538
this.mockServerLogger = mockServerLogger;
3639
this.secure = secure;
3740
this.error = error;
3841
this.registeredClients = registeredClients;
42+
this.websocketChannels = websocketChannels;
3943
this.textWebSocketFrames = textWebSocketFrames;
4044
}
4145

@@ -60,7 +64,7 @@ public void initChannel(SocketChannel channel) {
6064

6165
pipeline.addLast(new HttpObjectAggregator(Integer.MAX_VALUE));
6266

63-
pipeline.addLast(new WebSocketServerHandler(mockServerLogger, registeredClients, textWebSocketFrames));
67+
pipeline.addLast(new WebSocketServerHandler(mockServerLogger, registeredClients, websocketChannels, textWebSocketFrames));
6468

6569
pipeline.addLast(new MockServerServerCodec(mockServerLogger, secure));
6670

mockserver-core/src/main/java/org/mockserver/echo/http/WebSocketServerHandler.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11

22
package org.mockserver.echo.http;
33

4-
import io.netty.channel.ChannelFutureListener;
5-
import io.netty.channel.ChannelHandler;
6-
import io.netty.channel.ChannelHandlerContext;
7-
import io.netty.channel.ChannelInboundHandlerAdapter;
4+
import io.netty.channel.*;
85
import io.netty.handler.codec.http.DefaultHttpHeaders;
96
import io.netty.handler.codec.http.FullHttpRequest;
107
import io.netty.handler.codec.http.websocketx.*;
@@ -30,12 +27,14 @@ public class WebSocketServerHandler extends ChannelInboundHandlerAdapter {
3027
private static final String UPGRADE_CHANNEL_FOR_CALLBACK_WEB_SOCKET_URI = "/_mockserver_callback_websocket";
3128
private final MockServerLogger mockServerLogger;
3229
private final List<String> registeredClients;
30+
private final List<Channel> websocketChannels;
3331
private final List<TextWebSocketFrame> textWebSocketFrames;
3432
private WebSocketServerHandshaker handshaker;
3533

36-
WebSocketServerHandler(MockServerLogger mockServerLogger, List<String> registeredClients, List<TextWebSocketFrame> textWebSocketFrames) {
34+
WebSocketServerHandler(MockServerLogger mockServerLogger, List<String> registeredClients, List<Channel> websocketChannels, List<TextWebSocketFrame> textWebSocketFrames) {
3735
this.mockServerLogger = mockServerLogger;
3836
this.registeredClients = registeredClients;
37+
this.websocketChannels = websocketChannels;
3938
this.textWebSocketFrames = textWebSocketFrames;
4039
}
4140

@@ -93,6 +92,7 @@ private void upgradeChannel(final ChannelHandlerContext ctx, FullHttpRequest htt
9392
.setMessageFormat("Registering client " + clientId)
9493
);
9594
registeredClients.add(clientId);
95+
websocketChannels.add(future.channel());
9696
future.channel().closeFuture().addListener((ChannelFutureListener) future1 -> {
9797
mockServerLogger.logEvent(
9898
new LogEntry()
@@ -101,6 +101,7 @@ private void upgradeChannel(final ChannelHandlerContext ctx, FullHttpRequest htt
101101
.setMessageFormat("Unregistering callback for client " + clientId)
102102
);
103103
registeredClients.remove(clientId);
104+
websocketChannels.remove(future.channel());
104105
});
105106
});
106107
}

0 commit comments

Comments
 (0)