b57d9f307f
- write() now accepts a ChannelPromise and returns ChannelFuture as most users expected. It makes the user's life much easier because it is now much easier to get notified when a specific message has been written. - flush() does not create a ChannelPromise nor returns ChannelFuture. It is now similar to what read() looks like.
211 lines
6.4 KiB
Java
211 lines
6.4 KiB
Java
/*
|
|
* Copyright 2012 The Netty Project
|
|
*
|
|
* The Netty Project licenses this file to you under the Apache License,
|
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at:
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
package io.netty.handler.stream;
|
|
|
|
import io.netty.buffer.ByteBuf;
|
|
import io.netty.buffer.Unpooled;
|
|
import io.netty.channel.ChannelFuture;
|
|
import io.netty.channel.ChannelFutureListener;
|
|
import io.netty.channel.ChannelHandlerContext;
|
|
import io.netty.channel.embedded.EmbeddedChannel;
|
|
import io.netty.util.CharsetUtil;
|
|
import org.junit.Test;
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.File;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.nio.channels.Channels;
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
|
import static org.junit.Assert.*;
|
|
|
|
public class ChunkedWriteHandlerTest {
|
|
private static final byte[] BYTES = new byte[1024 * 64];
|
|
private static final File TMP;
|
|
|
|
static {
|
|
for (int i = 0; i < BYTES.length; i++) {
|
|
BYTES[i] = (byte) i;
|
|
}
|
|
|
|
FileOutputStream out = null;
|
|
try {
|
|
TMP = File.createTempFile("netty-chunk-", ".tmp");
|
|
TMP.deleteOnExit();
|
|
out = new FileOutputStream(TMP);
|
|
out.write(BYTES);
|
|
out.flush();
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
} finally {
|
|
if (out != null) {
|
|
try {
|
|
out.close();
|
|
} catch (IOException e) {
|
|
// ignore
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// See #310
|
|
@Test
|
|
public void testChunkedStream() {
|
|
check(new ChunkedStream(new ByteArrayInputStream(BYTES)));
|
|
|
|
check(new ChunkedStream(new ByteArrayInputStream(BYTES)),
|
|
new ChunkedStream(new ByteArrayInputStream(BYTES)),
|
|
new ChunkedStream(new ByteArrayInputStream(BYTES)));
|
|
}
|
|
|
|
@Test
|
|
public void testChunkedNioStream() {
|
|
check(new ChunkedNioStream(Channels.newChannel(new ByteArrayInputStream(BYTES))));
|
|
|
|
check(new ChunkedNioStream(Channels.newChannel(new ByteArrayInputStream(BYTES))),
|
|
new ChunkedNioStream(Channels.newChannel(new ByteArrayInputStream(BYTES))),
|
|
new ChunkedNioStream(Channels.newChannel(new ByteArrayInputStream(BYTES))));
|
|
}
|
|
|
|
@Test
|
|
public void testChunkedFile() throws IOException {
|
|
check(new ChunkedFile(TMP));
|
|
|
|
check(new ChunkedFile(TMP), new ChunkedFile(TMP), new ChunkedFile(TMP));
|
|
}
|
|
|
|
@Test
|
|
public void testChunkedNioFile() throws IOException {
|
|
check(new ChunkedNioFile(TMP));
|
|
|
|
check(new ChunkedNioFile(TMP), new ChunkedNioFile(TMP), new ChunkedNioFile(TMP));
|
|
}
|
|
|
|
// Test case which shows that there is not a bug like stated here:
|
|
// http://stackoverflow.com/a/10426305
|
|
@Test
|
|
public void testListenerNotifiedWhenIsEnd() {
|
|
ByteBuf buffer = Unpooled.copiedBuffer("Test", CharsetUtil.ISO_8859_1);
|
|
|
|
ChunkedInput<ByteBuf> input = new ChunkedInput<ByteBuf>() {
|
|
private boolean done;
|
|
private final ByteBuf buffer = Unpooled.copiedBuffer("Test", CharsetUtil.ISO_8859_1);
|
|
|
|
@Override
|
|
public boolean isEndOfInput() throws Exception {
|
|
return done;
|
|
}
|
|
|
|
@Override
|
|
public void close() throws Exception {
|
|
// NOOP
|
|
}
|
|
|
|
@Override
|
|
public ByteBuf readChunk(ChannelHandlerContext ctx) throws Exception {
|
|
if (done) {
|
|
return null;
|
|
}
|
|
done = true;
|
|
return buffer.duplicate().retain();
|
|
}
|
|
};
|
|
|
|
final AtomicBoolean listenerNotified = new AtomicBoolean(false);
|
|
final ChannelFutureListener listener = new ChannelFutureListener() {
|
|
|
|
@Override
|
|
public void operationComplete(ChannelFuture future) throws Exception {
|
|
listenerNotified.set(true);
|
|
}
|
|
};
|
|
|
|
EmbeddedChannel ch = new EmbeddedChannel(new ChunkedWriteHandler());
|
|
ch.writeAndFlush(input).addListener(listener).syncUninterruptibly();
|
|
ch.checkException();
|
|
ch.finish();
|
|
|
|
// the listener should have been notified
|
|
assertTrue(listenerNotified.get());
|
|
|
|
assertEquals(buffer, ch.readOutbound());
|
|
assertNull(ch.readOutbound());
|
|
}
|
|
|
|
@Test
|
|
public void testChunkedMessageInput() {
|
|
|
|
ChunkedInput<Object> input = new ChunkedInput<Object>() {
|
|
private boolean done;
|
|
|
|
@Override
|
|
public boolean isEndOfInput() throws Exception {
|
|
return done;
|
|
}
|
|
|
|
@Override
|
|
public void close() throws Exception {
|
|
// NOOP
|
|
}
|
|
|
|
@Override
|
|
public Object readChunk(ChannelHandlerContext ctx) throws Exception {
|
|
if (done) {
|
|
return false;
|
|
}
|
|
done = true;
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
EmbeddedChannel ch = new EmbeddedChannel(new ChunkedWriteHandler());
|
|
ch.writeAndFlush(input).syncUninterruptibly();
|
|
ch.checkException();
|
|
assertTrue(ch.finish());
|
|
|
|
assertEquals(0, ch.readOutbound());
|
|
assertNull(ch.readOutbound());
|
|
}
|
|
|
|
private static void check(ChunkedInput<?>... inputs) {
|
|
EmbeddedChannel ch = new EmbeddedChannel(new ChunkedWriteHandler());
|
|
|
|
for (ChunkedInput<?> input: inputs) {
|
|
ch.writeOutbound(input);
|
|
}
|
|
|
|
assertTrue(ch.finish());
|
|
|
|
int i = 0;
|
|
int read = 0;
|
|
for (;;) {
|
|
ByteBuf buffer = (ByteBuf) ch.readOutbound();
|
|
if (buffer == null) {
|
|
break;
|
|
}
|
|
while (buffer.isReadable()) {
|
|
assertEquals(BYTES[i++], buffer.readByte());
|
|
read++;
|
|
if (i == BYTES.length) {
|
|
i = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
assertEquals(BYTES.length * inputs.length, read);
|
|
}
|
|
}
|