/*
* Copyright 2014 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.codec.http.websocketx;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedChannel;
import org.junit.Assert;
import org.junit.Test;
/**
* Tests the WebSocket08FrameEncoder and Decoder implementation.<br>
* Checks whether the combination of encoding and decoding yields the original data.<br>
* Thereby also the masking behavior is checked.
*/
public class WebSocket08EncoderDecoderTest {
private ByteBuf binTestData;
private String strTestData;
private static final int MAX_TESTDATA_LENGTH = 100 * 1024;
private void initTestData() {
binTestData = Unpooled.buffer(MAX_TESTDATA_LENGTH);
byte j = 0;
for (int i = 0; i < MAX_TESTDATA_LENGTH; i++) {
binTestData.array()[i] = j;
j++;
}
StringBuilder s = new StringBuilder();
char c = 'A';
for (int i = 0; i < MAX_TESTDATA_LENGTH; i++) {
s.append(c);
c++;
if (c == 'Z') {
c = 'A';
}
}
strTestData = s.toString();
}
@Test
public void testWebSocketEncodingAndDecoding() {
initTestData();
// Test without masking
EmbeddedChannel outChannel = new EmbeddedChannel(new WebSocket08FrameEncoder(false));
EmbeddedChannel inChannel = new EmbeddedChannel(new WebSocket08FrameDecoder(false, false, 1024 * 1024));
executeTests(outChannel, inChannel);
// Test with activated masking
outChannel = new EmbeddedChannel(new WebSocket08FrameEncoder(true));
inChannel = new EmbeddedChannel(new WebSocket08FrameDecoder(true, false, 1024 * 1024));
executeTests(outChannel, inChannel);
// Release test data
binTestData.release();
}
private void executeTests(EmbeddedChannel outChannel, EmbeddedChannel inChannel) {
// Test at the boundaries of each message type, because this shifts the position of the mask field
// Test min. 4 lengths to check for problems related to an uneven frame length
executeTests(outChannel, inChannel, 0);
executeTests(outChannel, inChannel, 1);
executeTests(outChannel, inChannel, 2);
executeTests(outChannel, inChannel, 3);
executeTests(outChannel, inChannel, 4);
executeTests(outChannel, inChannel, 5);
executeTests(outChannel, inChannel, 125);
executeTests(outChannel, inChannel, 126);
executeTests(outChannel, inChannel, 127);
executeTests(outChannel, inChannel, 128);
executeTests(outChannel, inChannel, 129);
executeTests(outChannel, inChannel, 65535);
executeTests(outChannel, inChannel, 65536);
executeTests(outChannel, inChannel, 65537);
executeTests(outChannel, inChannel, 65538);
executeTests(outChannel, inChannel, 65539);
}
private void executeTests(EmbeddedChannel outChannel, EmbeddedChannel inChannel, int testDataLength) {
testTextWithLen(outChannel, inChannel, testDataLength);
testBinaryWithLen(outChannel, inChannel, testDataLength);
}
private void testTextWithLen(EmbeddedChannel outChannel, EmbeddedChannel inChannel, int testDataLength) {
String testStr = strTestData.substring(0, testDataLength);
outChannel.writeOutbound(new TextWebSocketFrame(testStr));
// Transfer encoded data into decoder
// Loop because there might be multiple frames (gathering write)
while (true) {
ByteBuf encoded = (ByteBuf) outChannel.readOutbound();
if (encoded != null) {
inChannel.writeInbound(encoded);
} else {
break;
}
}
Object decoded = inChannel.readInbound();
Assert.assertNotNull(decoded);
Assert.assertTrue(decoded instanceof TextWebSocketFrame);
TextWebSocketFrame txt = (TextWebSocketFrame) decoded;
Assert.assertEquals(txt.text(), testStr);
txt.release();
}
private void testBinaryWithLen(EmbeddedChannel outChannel, EmbeddedChannel inChannel, int testDataLength) {
binTestData.retain(); // need to retain for sending and still keeping it
binTestData.setIndex(0, testDataLength); // Send only len bytes
outChannel.writeOutbound(new BinaryWebSocketFrame(binTestData));
// Transfer encoded data into decoder
// Loop because there might be multiple frames (gathering write)
while (true) {
ByteBuf encoded = (ByteBuf) outChannel.readOutbound();
if (encoded != null) {
inChannel.writeInbound(encoded);
} else {
break;
}
}
Object decoded = inChannel.readInbound();
Assert.assertNotNull(decoded);
Assert.assertTrue(decoded instanceof BinaryWebSocketFrame);
BinaryWebSocketFrame binFrame = (BinaryWebSocketFrame) decoded;
int readable = binFrame.content().readableBytes();
Assert.assertEquals(readable, testDataLength);
for (int i = 0; i < testDataLength; i++) {
Assert.assertEquals(binTestData.getByte(i), binFrame.content().getByte(i));
}
binFrame.release();
}
}