Skip to content

Commit 0790678

Browse files
committed
Updating HTTP/2 tests to not retain buffers for validation
Motivation: To eliminate the tests as being a cause of leaks, removing the automatic retaining of ByteBufs in Http2TestUtil. Modifications: Each test that relied on retaining buffers for validation has been modified to copy the buffer into a list of Strings that are manually validated after the message is received. Result: The HTTP/2 tests should (hopefully) no longer be reporting erroneous leaks due to the testing code, itself.
1 parent 3807f9f commit 0790678

File tree

6 files changed

+146
-97
lines changed

6 files changed

+146
-97
lines changed

codec-http2/src/test/java/io/netty/handler/codec/http2/DataCompressionHttp2Test.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ protected void initChannel(Channel ch) throws Exception {
108108
ChannelPipeline p = ch.pipeline();
109109
serverAdapter = new Http2TestUtil.FrameAdapter(serverConnection,
110110
new DelegatingDecompressorFrameListener(serverConnection, serverListener),
111-
serverLatch, false);
111+
serverLatch);
112112
p.addLast("reader", serverAdapter);
113113
p.addLast(Http2CodecUtil.ignoreSettingsHandler());
114114
serverConnectedChannel = ch;
@@ -121,7 +121,7 @@ protected void initChannel(Channel ch) throws Exception {
121121
@Override
122122
protected void initChannel(Channel ch) throws Exception {
123123
ChannelPipeline p = ch.pipeline();
124-
clientAdapter = new Http2TestUtil.FrameAdapter(clientListener, clientLatch, false);
124+
clientAdapter = new Http2TestUtil.FrameAdapter(clientListener, clientLatch);
125125
p.addLast("reader", clientAdapter);
126126
p.addLast(Http2CodecUtil.ignoreSettingsHandler());
127127
}

codec-http2/src/test/java/io/netty/handler/codec/http2/DelegatingHttp2HttpConnectionHandlerTest.java

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import static org.mockito.Matchers.anyInt;
2929
import static org.mockito.Matchers.anyShort;
3030
import static org.mockito.Matchers.eq;
31+
import static org.mockito.Mockito.doAnswer;
3132
import static org.mockito.Mockito.never;
3233
import static org.mockito.Mockito.verify;
3334
import io.netty.bootstrap.Bootstrap;
@@ -51,25 +52,25 @@
5152
import io.netty.util.concurrent.Future;
5253

5354
import java.net.InetSocketAddress;
55+
import java.util.ArrayList;
5456
import java.util.List;
5557
import java.util.concurrent.CountDownLatch;
5658
import java.util.concurrent.TimeUnit;
5759

5860
import org.junit.After;
5961
import org.junit.Before;
6062
import org.junit.Test;
61-
import org.mockito.ArgumentCaptor;
6263
import org.mockito.Mock;
6364
import org.mockito.MockitoAnnotations;
65+
import org.mockito.invocation.InvocationOnMock;
66+
import org.mockito.stubbing.Answer;
6467

6568
/**
6669
* Testing the {@link DelegatingHttp2HttpConnectionHandler} for {@link FullHttpRequest} objects into HTTP/2 frames
6770
*/
6871
public class DelegatingHttp2HttpConnectionHandlerTest {
6972
private static final int CONNECTION_SETUP_READ_COUNT = 2;
7073

71-
private List<ByteBuf> capturedData;
72-
7374
@Mock
7475
private Http2FrameListener clientListener;
7576

@@ -125,12 +126,6 @@ protected void initChannel(Channel ch) throws Exception {
125126

126127
@After
127128
public void teardown() throws Exception {
128-
if (capturedData != null) {
129-
for (int i = 0; i < capturedData.size(); ++i) {
130-
capturedData.get(i).release();
131-
}
132-
capturedData = null;
133-
}
134129
serverChannel.close().sync();
135130
Future<?> serverGroup = sb.group().shutdownGracefully(0, 0, TimeUnit.MILLISECONDS);
136131
Future<?> serverChildGroup = sb.childGroup().shutdownGracefully(0, 0, TimeUnit.MILLISECONDS);
@@ -180,6 +175,15 @@ public void testRequestWithBody() throws Exception {
180175
requestLatch(new CountDownLatch(CONNECTION_SETUP_READ_COUNT + 2));
181176
final String text = "foooooogoooo";
182177
final ByteBuf data = Unpooled.copiedBuffer(text, UTF_8);
178+
final List<String> receivedBuffers = new ArrayList<String>();
179+
doAnswer(new Answer<Void>() {
180+
@Override
181+
public Void answer(InvocationOnMock in) throws Throwable {
182+
receivedBuffers.add(((ByteBuf) in.getArguments()[2]).toString(UTF_8));
183+
return null;
184+
}
185+
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
186+
any(ByteBuf.class), eq(0), eq(true));
183187
try {
184188
final HttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, POST, "/example", data.retain());
185189
final HttpHeaders httpHeaders = request.headers();
@@ -200,13 +204,12 @@ public void testRequestWithBody() throws Exception {
200204
writeFuture.awaitUninterruptibly(2, SECONDS);
201205
assertTrue(writeFuture.isSuccess());
202206
awaitRequests();
203-
final ArgumentCaptor<ByteBuf> dataCaptor = ArgumentCaptor.forClass(ByteBuf.class);
204207
verify(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(3), eq(http2Headers), eq(0),
205208
anyShort(), anyBoolean(), eq(0), eq(false));
206-
verify(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3), dataCaptor.capture(), eq(0),
209+
verify(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3), any(ByteBuf.class), eq(0),
207210
eq(true));
208-
capturedData = dataCaptor.getAllValues();
209-
assertEquals(data, capturedData.get(0));
211+
assertEquals(1, receivedBuffers.size());
212+
assertEquals(text, receivedBuffers.get(0));
210213
} finally {
211214
data.release();
212215
}

codec-http2/src/test/java/io/netty/handler/codec/http2/Http2ConnectionRoundtripTest.java

Lines changed: 52 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@
2020
import static io.netty.handler.codec.http2.Http2TestUtil.runInChannel;
2121
import static io.netty.util.CharsetUtil.UTF_8;
2222
import static java.util.concurrent.TimeUnit.SECONDS;
23+
import static org.junit.Assert.assertArrayEquals;
2324
import static org.junit.Assert.assertEquals;
2425
import static org.junit.Assert.assertTrue;
2526
import static org.mockito.Matchers.any;
2627
import static org.mockito.Matchers.anyInt;
2728
import static org.mockito.Matchers.eq;
29+
import static org.mockito.Mockito.doAnswer;
2830
import static org.mockito.Mockito.times;
2931
import static org.mockito.Mockito.verify;
3032
import io.netty.bootstrap.Bootstrap;
@@ -41,11 +43,12 @@
4143
import io.netty.channel.socket.nio.NioServerSocketChannel;
4244
import io.netty.channel.socket.nio.NioSocketChannel;
4345
import io.netty.handler.codec.http2.Http2TestUtil.Http2Runnable;
44-
import io.netty.util.CharsetUtil;
4546
import io.netty.util.NetUtil;
4647
import io.netty.util.concurrent.Future;
4748

49+
import java.io.ByteArrayOutputStream;
4850
import java.net.InetSocketAddress;
51+
import java.util.ArrayList;
4952
import java.util.List;
5053
import java.util.Random;
5154
import java.util.concurrent.CountDownLatch;
@@ -54,9 +57,11 @@
5457
import org.junit.After;
5558
import org.junit.Before;
5659
import org.junit.Test;
57-
import org.mockito.ArgumentCaptor;
5860
import org.mockito.Mock;
61+
import org.mockito.Mockito;
5962
import org.mockito.MockitoAnnotations;
63+
import org.mockito.invocation.InvocationOnMock;
64+
import org.mockito.stubbing.Answer;
6065

6166
/**
6267
* Tests the full HTTP/2 framing stack including the connection and preface handlers.
@@ -144,7 +149,16 @@ public void flowControlProperlyChunksLargeMessage() throws Exception {
144149
final byte[] bytes = new byte[length];
145150
new Random().nextBytes(bytes);
146151
final ByteBuf data = Unpooled.wrappedBuffer(bytes);
147-
List<ByteBuf> capturedData = null;
152+
final ByteArrayOutputStream out = new ByteArrayOutputStream(length);
153+
doAnswer(new Answer<Void>() {
154+
@Override
155+
public Void answer(InvocationOnMock in) throws Throwable {
156+
ByteBuf buf = (ByteBuf) in.getArguments()[2];
157+
buf.readBytes(out, buf.readableBytes());
158+
return null;
159+
}
160+
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3),
161+
any(ByteBuf.class), eq(0), Mockito.anyBoolean());
148162
try {
149163
// Initialize the data latch based on the number of bytes expected.
150164
requestLatch(new CountDownLatch(2));
@@ -163,18 +177,18 @@ public void run() {
163177
assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
164178

165179
// Verify that headers were received and only one DATA frame was received with endStream set.
166-
final ArgumentCaptor<ByteBuf> dataCaptor = ArgumentCaptor.forClass(ByteBuf.class);
167180
verify(serverListener).onHeadersRead(any(ChannelHandlerContext.class), eq(3), eq(headers), eq(0),
168181
eq((short) 16), eq(false), eq(0), eq(false));
169-
verify(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3), dataCaptor.capture(), eq(0),
182+
verify(serverListener).onDataRead(any(ChannelHandlerContext.class), eq(3), any(ByteBuf.class), eq(0),
170183
eq(true));
171184

172185
// Verify we received all the bytes.
173-
capturedData = dataCaptor.getAllValues();
174-
assertEquals(data, capturedData.get(0));
186+
out.flush();
187+
byte[] received = out.toByteArray();
188+
assertArrayEquals(bytes, received);
175189
} finally {
176190
data.release();
177-
release(capturedData);
191+
out.close();
178192
}
179193
}
180194

@@ -183,48 +197,56 @@ public void stressTest() throws Exception {
183197
final Http2Headers headers = dummyHeaders();
184198
final String text = "hello world";
185199
final String pingMsg = "12345678";
186-
final ByteBuf data = Unpooled.copiedBuffer(text.getBytes());
187-
final ByteBuf pingData = Unpooled.copiedBuffer(pingMsg.getBytes());
188-
List<ByteBuf> capturedData = null;
189-
List<ByteBuf> capturedPingData = null;
200+
final ByteBuf data = Unpooled.copiedBuffer(text, UTF_8);
201+
final ByteBuf pingData = Unpooled.copiedBuffer(pingMsg, UTF_8);
202+
final List<String> receivedPingBuffers = new ArrayList<String>(NUM_STREAMS);
203+
doAnswer(new Answer<Void>() {
204+
@Override
205+
public Void answer(InvocationOnMock in) throws Throwable {
206+
receivedPingBuffers.add(((ByteBuf) in.getArguments()[1]).toString(UTF_8));
207+
return null;
208+
}
209+
}).when(serverListener).onPingRead(any(ChannelHandlerContext.class), eq(pingData));
210+
final List<String> receivedDataBuffers = new ArrayList<String>();
211+
doAnswer(new Answer<Void>() {
212+
@Override
213+
public Void answer(InvocationOnMock in) throws Throwable {
214+
receivedDataBuffers.add(((ByteBuf) in.getArguments()[2]).toString(UTF_8));
215+
return null;
216+
}
217+
}).when(serverListener).onDataRead(any(ChannelHandlerContext.class), anyInt(), eq(data),
218+
eq(0), eq(true));
190219
try {
191220
runInChannel(clientChannel, new Http2Runnable() {
192221
@Override
193222
public void run() {
194223
for (int i = 0, nextStream = 3; i < NUM_STREAMS; ++i, nextStream += 2) {
195224
http2Client.writeHeaders(ctx(), nextStream, headers, 0, (short) 16, false, 0, false,
196225
newPromise());
197-
http2Client.writePing(ctx(), pingData.retain(), newPromise());
198-
http2Client.writeData(ctx(), nextStream, data.retain(), 0, true, newPromise());
226+
http2Client.writePing(ctx(), pingData.slice().retain(), newPromise());
227+
http2Client.writeData(ctx(), nextStream, data.slice().retain(), 0, true, newPromise());
199228
}
200229
}
201230
});
202231
// Wait for all frames to be received.
203232
assertTrue(requestLatch.await(STRESS_TIMEOUT_SECONDS, SECONDS));
204233
verify(serverListener, times(NUM_STREAMS)).onHeadersRead(any(ChannelHandlerContext.class), anyInt(),
205234
eq(headers), eq(0), eq((short) 16), eq(false), eq(0), eq(false));
206-
final ArgumentCaptor<ByteBuf> dataCaptor = ArgumentCaptor.forClass(ByteBuf.class);
207-
final ArgumentCaptor<ByteBuf> pingDataCaptor = ArgumentCaptor.forClass(ByteBuf.class);
208235
verify(serverListener, times(NUM_STREAMS)).onPingRead(any(ChannelHandlerContext.class),
209-
pingDataCaptor.capture());
210-
capturedPingData = pingDataCaptor.getAllValues();
211-
verify(serverListener, times(NUM_STREAMS)).onDataRead(any(ChannelHandlerContext.class), anyInt(),
212-
dataCaptor.capture(), eq(0), eq(true));
213-
capturedData = dataCaptor.getAllValues();
214-
data.resetReaderIndex();
215-
pingData.resetReaderIndex();
216-
int i;
217-
for (i = 0; i < capturedPingData.size(); ++i) {
218-
assertEquals(pingData, capturedPingData.get(i));
236+
any(ByteBuf.class));
237+
verify(serverListener, times(NUM_STREAMS)).onDataRead(any(ChannelHandlerContext.class),
238+
anyInt(), any(ByteBuf.class), eq(0), eq(true));
239+
assertEquals(NUM_STREAMS, receivedPingBuffers.size());
240+
assertEquals(NUM_STREAMS, receivedDataBuffers.size());
241+
for (String receivedData : receivedDataBuffers) {
242+
assertEquals(text, receivedData);
219243
}
220-
for (i = 0; i < capturedData.size(); ++i) {
221-
assertEquals(capturedData.get(i).toString(CharsetUtil.UTF_8), data, capturedData.get(i));
244+
for (String receivedPing : receivedPingBuffers) {
245+
assertEquals(pingMsg, receivedPing);
222246
}
223247
} finally {
224248
data.release();
225249
pingData.release();
226-
release(capturedData);
227-
release(capturedPingData);
228250
}
229251
}
230252

@@ -250,14 +272,6 @@ private ChannelPromise newPromise() {
250272
return ctx().newPromise();
251273
}
252274

253-
private static void release(List<ByteBuf> capturedData) {
254-
if (capturedData != null) {
255-
for (int i = 0; i < capturedData.size(); ++i) {
256-
capturedData.get(i).release();
257-
}
258-
}
259-
}
260-
261275
private Http2Headers dummyHeaders() {
262276
return new DefaultHttp2Headers().method(as("GET")).scheme(as("https"))
263277
.authority(as("example.org")).path(as("/some/path/resource2")).add(randomString(), randomString());

0 commit comments

Comments
 (0)