/*
* Copyright 2013 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.compression;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.CompositeByteBuf;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
import org.junit.Test;
import java.util.Random;
import static io.netty.buffer.Unpooled.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
public class SnappyIntegrationTest {
/**
* The number of random regression tests run by testRandom() runs. Whenever testRandom() finds the case that
* the snappy codec can't encode/decode, it will print the generated source code of the offending test case.
* You can always reproduce the problem using it rather than relying on testRandom().
*
* The default is 1, but you can increase it to increase the chance of finding any unusual cases.
**/
private static final int RANDOM_RUNS = 1;
@Test
public void testText() throws Exception {
testIdentity(copiedBuffer(
"Netty has been designed carefully with the experiences earned from the implementation of a lot of " +
"protocols such as FTP, SMTP, HTTP, and various binary and text-based legacy protocols",
CharsetUtil.US_ASCII));
}
@Test
public void test1002() throws Throwable {
// Data from https://github.com/netty/netty/issues/1002
testIdentity(wrappedBuffer(new byte[] {
11, 0, 0, 0, 0, 0, 16, 65, 96, 119, -22, 79, -43, 76, -75, -93,
11, 104, 96, -99, 126, -98, 27, -36, 40, 117, -65, -3, -57, -83, -58, 7,
114, -14, 68, -122, 124, 88, 118, 54, 45, -26, 117, 13, -45, -9, 60, -73,
-53, -44, 53, 68, -77, -71, 109, 43, -38, 59, 100, -12, -87, 44, -106, 123,
-107, 38, 13, -117, -23, -49, 29, 21, 26, 66, 1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 66, 0, -104, -49,
16, -120, 22, 8, -52, -54, -102, -52, -119, -124, -92, -71, 101, -120, -52, -48,
45, -26, -24, 26, 41, -13, 36, 64, -47, 15, -124, -7, -16, 91, 96, 0,
-93, -42, 101, 20, -74, 39, -124, 35, 43, -49, -21, -92, -20, -41, 79, 41,
110, -105, 42, -96, 90, -9, -100, -22, -62, 91, 2, 35, 113, 117, -71, 66,
1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1
}));
}
// These tests were found using testRandom() with large RANDOM_RUNS.
// Tests that copies do not attempt to overrun into a previous frame chunk
@Test
public void test5323211032315942961() {
testWithSeed(5323211032315942961L);
}
// Tests that when generating the hash lookup table for finding copies, we
// do not exceed the length of the input when there are no copies
@Test
public void test7088170877360183401() {
testWithSeed(7088170877360183401L);
}
@Test
public void testRandom() throws Throwable {
Random rnd = new Random();
for (int i = 0; i < RANDOM_RUNS; i++) {
long seed = rnd.nextLong();
if (seed < 0) {
// Use only positive seed to get prettier test name. :-)
continue;
}
try {
testWithSeed(seed);
} catch (Throwable t) {
System.out.println("Failed with random seed " + seed + ". Here is a test for it:\n");
printSeedAsTest(seed);
//throw t;
}
}
}
private static void testWithSeed(long seed) {
byte[] data = new byte[16 * 1048576];
new Random(seed).nextBytes(data);
testIdentity(data);
}
private static void testIdentity(byte[] data) {
testIdentity(wrappedBuffer(data));
}
private static void testIdentity(ByteBuf in) {
EmbeddedChannel encoder = new EmbeddedChannel(new SnappyFramedEncoder());
EmbeddedChannel decoder = new EmbeddedChannel(new SnappyFramedDecoder());
try {
encoder.writeOutbound(in.copy());
ByteBuf compressed = (ByteBuf) encoder.readOutbound();
assertThat(compressed, is(notNullValue()));
assertThat(compressed, is(not(in)));
decoder.writeInbound(compressed.retain());
assertFalse(compressed.isReadable());
compressed.release();
CompositeByteBuf decompressed = compositeBuffer();
for (;;) {
Object o = decoder.readInbound();
if (o == null) {
break;
}
decompressed.addComponent((ByteBuf) o);
decompressed.writerIndex(decompressed.writerIndex() + ((ByteBuf) o).readableBytes());
}
assertEquals(in, decompressed);
decompressed.release();
in.release();
} finally {
// Avoids memory leak through AbstractChannel.allChannels
encoder.close();
decoder.close();
for (;;) {
Object msg = encoder.readOutbound();
if (msg == null) {
break;
}
ReferenceCountUtil.release(msg);
}
for (;;) {
Object msg = decoder.readInbound();
if (msg == null) {
break;
}
ReferenceCountUtil.release(msg);
}
}
}
private static void printSeedAsTest(long l) {
System.out.println("@Test");
System.out.println("@Ignore");
System.out.println("public void test" + l + "(){");
System.out.println(" testWithSeed(" + l + "L);");
System.out.println("}");
}
}