Skip to content

Commit c9adb41

Browse files
idelpivnitskiynormanmaurer
authored andcommitted
Refactor tests for compression codecs
Motivation: Too many duplicated code of tests for different compression codecs. Modifications: - Added abstract classes AbstractCompressionTest, AbstractDecoderTest and AbstractEncoderTest which contains common variables and tests for any compression codec. - Removed common tests which are implemented in AbstractDecoderTest and AbstractEncoderTest from current tests for compression codecs. - Implemented abstract methods of AbstractDecoderTest and AbstractEncoderTest in current tests for compression codecs. - Added additional checks for current tests. - Renamed abstract class IntegrationTest to AbstractIntegrationTest. - Used Theories to run tests with head and direct buffers. - Removed code duplicates. Result: Removed duplicated code of tests for compression codecs and simplified an addition of tests for new compression codecs.
1 parent 6496d2d commit c9adb41

20 files changed

Lines changed: 529 additions & 763 deletions

codec/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777
<scope>test</scope>
7878
</dependency>
7979

80-
<!-- Test dependency for Bzip2Decoder -->
80+
<!-- Test dependency for Bzip2 compression codec -->
8181
<dependency>
8282
<groupId>org.apache.commons</groupId>
8383
<artifactId>commons-compress</artifactId>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2015 The Netty Project
3+
*
4+
* The Netty Project licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
package io.netty.handler.codec.compression;
17+
18+
import io.netty.util.internal.ThreadLocalRandom;
19+
20+
public abstract class AbstractCompressionTest {
21+
22+
protected static final ThreadLocalRandom rand;
23+
24+
protected static final byte[] BYTES_SMALL = new byte[256];
25+
protected static final byte[] BYTES_LARGE = new byte[256 * 1024];
26+
27+
static {
28+
rand = ThreadLocalRandom.current();
29+
fillArrayWithCompressibleData(BYTES_SMALL);
30+
fillArrayWithCompressibleData(BYTES_LARGE);
31+
}
32+
33+
private static void fillArrayWithCompressibleData(byte[] array) {
34+
for (int i = 0; i < array.length; i++) {
35+
array[i] = i % 4 != 0 ? 0 : (byte) rand.nextInt();
36+
}
37+
}
38+
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
* Copyright 2014 The Netty Project
3+
*
4+
* The Netty Project licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
package io.netty.handler.codec.compression;
17+
18+
import io.netty.buffer.ByteBuf;
19+
import io.netty.buffer.CompositeByteBuf;
20+
import io.netty.buffer.Unpooled;
21+
import io.netty.channel.embedded.EmbeddedChannel;
22+
import org.junit.Before;
23+
import org.junit.Rule;
24+
import org.junit.experimental.theories.DataPoints;
25+
import org.junit.experimental.theories.FromDataPoints;
26+
import org.junit.experimental.theories.Theories;
27+
import org.junit.experimental.theories.Theory;
28+
import org.junit.rules.ExpectedException;
29+
import org.junit.runner.RunWith;
30+
31+
import static org.junit.Assert.*;
32+
33+
@RunWith(Theories.class)
34+
public abstract class AbstractDecoderTest extends AbstractCompressionTest {
35+
36+
protected static final ByteBuf WRAPPED_BYTES_SMALL;
37+
protected static final ByteBuf WRAPPED_BYTES_LARGE;
38+
39+
static {
40+
WRAPPED_BYTES_SMALL = Unpooled.wrappedBuffer(BYTES_SMALL);
41+
WRAPPED_BYTES_LARGE = Unpooled.wrappedBuffer(BYTES_LARGE);
42+
}
43+
44+
@Rule
45+
public final ExpectedException expected = ExpectedException.none();
46+
47+
protected EmbeddedChannel channel;
48+
49+
protected static byte[] compressedBytesSmall;
50+
protected static byte[] compressedBytesLarge;
51+
52+
protected AbstractDecoderTest() throws Exception {
53+
compressedBytesSmall = compress(BYTES_SMALL);
54+
compressedBytesLarge = compress(BYTES_LARGE);
55+
}
56+
57+
/**
58+
* Compresses data with some external library.
59+
*/
60+
protected abstract byte[] compress(byte[] data) throws Exception;
61+
62+
@Before
63+
public abstract void initChannel();
64+
65+
@DataPoints("smallData")
66+
public static ByteBuf[] smallData() {
67+
ByteBuf heap = Unpooled.wrappedBuffer(compressedBytesSmall);
68+
ByteBuf direct = Unpooled.directBuffer(compressedBytesSmall.length);
69+
direct.writeBytes(compressedBytesSmall);
70+
return new ByteBuf[] {heap, direct};
71+
}
72+
73+
@DataPoints("largeData")
74+
public static ByteBuf[] largeData() {
75+
ByteBuf heap = Unpooled.wrappedBuffer(compressedBytesLarge);
76+
ByteBuf direct = Unpooled.directBuffer(compressedBytesLarge.length);
77+
direct.writeBytes(compressedBytesLarge);
78+
return new ByteBuf[] {heap, direct};
79+
}
80+
81+
@Theory
82+
public void testDecompressionOfSmallChunkOfData(@FromDataPoints("smallData") ByteBuf data) throws Exception {
83+
testDecompression(WRAPPED_BYTES_SMALL, data);
84+
}
85+
86+
@Theory
87+
public void testDecompressionOfLargeChunkOfData(@FromDataPoints("largeData") ByteBuf data) throws Exception {
88+
testDecompression(WRAPPED_BYTES_LARGE, data);
89+
}
90+
91+
@Theory
92+
public void testDecompressionOfBatchedFlowOfData(@FromDataPoints("largeData") ByteBuf data) throws Exception {
93+
testDecompressionOfBatchedFlow(WRAPPED_BYTES_LARGE, data);
94+
}
95+
96+
protected void testDecompression(final ByteBuf expected, final ByteBuf data) throws Exception {
97+
assertTrue(channel.writeInbound(data));
98+
99+
ByteBuf decompressed = readDecompressed(channel);
100+
assertEquals(expected, decompressed);
101+
102+
decompressed.release();
103+
}
104+
105+
protected void testDecompressionOfBatchedFlow(final ByteBuf expected, final ByteBuf data) throws Exception {
106+
final int compressedLength = data.readableBytes();
107+
int written = 0, length = rand.nextInt(100);
108+
while (written + length < compressedLength) {
109+
ByteBuf compressedBuf = data.slice(written, length);
110+
channel.writeInbound(compressedBuf.retain());
111+
written += length;
112+
length = rand.nextInt(100);
113+
}
114+
ByteBuf compressedBuf = data.slice(written, compressedLength - written);
115+
assertTrue(channel.writeInbound(compressedBuf.retain()));
116+
117+
ByteBuf decompressedBuf = readDecompressed(channel);
118+
assertEquals(expected, decompressedBuf);
119+
120+
decompressedBuf.release();
121+
data.release();
122+
}
123+
124+
protected static ByteBuf readDecompressed(final EmbeddedChannel channel) {
125+
CompositeByteBuf decompressed = Unpooled.compositeBuffer();
126+
ByteBuf msg;
127+
while ((msg = channel.readInbound()) != null) {
128+
decompressed.addComponent(msg);
129+
decompressed.writerIndex(decompressed.writerIndex() + msg.readableBytes());
130+
}
131+
return decompressed;
132+
}
133+
134+
protected static void tryDecodeAndCatchBufLeaks(final EmbeddedChannel channel, final ByteBuf data) {
135+
try {
136+
channel.writeInbound(data);
137+
} finally {
138+
for (;;) {
139+
ByteBuf inflated = channel.readInbound();
140+
if (inflated == null) {
141+
break;
142+
}
143+
inflated.release();
144+
}
145+
channel.finish();
146+
}
147+
}
148+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
* Copyright 2014 The Netty Project
3+
*
4+
* The Netty Project licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
package io.netty.handler.codec.compression;
17+
18+
import io.netty.buffer.ByteBuf;
19+
import io.netty.buffer.CompositeByteBuf;
20+
import io.netty.buffer.Unpooled;
21+
import io.netty.channel.embedded.EmbeddedChannel;
22+
import org.junit.Before;
23+
import org.junit.experimental.theories.DataPoints;
24+
import org.junit.experimental.theories.FromDataPoints;
25+
import org.junit.experimental.theories.Theories;
26+
import org.junit.experimental.theories.Theory;
27+
import org.junit.runner.RunWith;
28+
29+
import static org.junit.Assert.*;
30+
31+
@RunWith(Theories.class)
32+
public abstract class AbstractEncoderTest extends AbstractCompressionTest {
33+
34+
protected EmbeddedChannel channel;
35+
36+
/**
37+
* Decompresses data with some external library.
38+
*/
39+
protected abstract ByteBuf decompress(ByteBuf compressed, int originalLength) throws Exception;
40+
41+
@Before
42+
public abstract void initChannel();
43+
44+
@DataPoints("smallData")
45+
public static ByteBuf[] smallData() {
46+
ByteBuf heap = Unpooled.wrappedBuffer(BYTES_SMALL);
47+
ByteBuf direct = Unpooled.directBuffer(BYTES_SMALL.length);
48+
direct.writeBytes(BYTES_SMALL);
49+
return new ByteBuf[] {heap, direct};
50+
}
51+
52+
@DataPoints("largeData")
53+
public static ByteBuf[] largeData() {
54+
ByteBuf heap = Unpooled.wrappedBuffer(BYTES_LARGE);
55+
ByteBuf direct = Unpooled.directBuffer(BYTES_LARGE.length);
56+
direct.writeBytes(BYTES_LARGE);
57+
return new ByteBuf[] {heap, direct};
58+
}
59+
60+
@Theory
61+
public void testCompressionOfSmallChunkOfData(@FromDataPoints("smallData") ByteBuf data) throws Exception {
62+
testCompression(data);
63+
}
64+
65+
@Theory
66+
public void testCompressionOfLargeChunkOfData(@FromDataPoints("largeData") ByteBuf data) throws Exception {
67+
testCompression(data);
68+
}
69+
70+
@Theory
71+
public void testCompressionOfBatchedFlowOfData(@FromDataPoints("largeData") ByteBuf data) throws Exception {
72+
testCompressionOfBatchedFlow(data);
73+
}
74+
75+
protected void testCompression(final ByteBuf data) throws Exception {
76+
final int dataLength = data.readableBytes();
77+
assertTrue(channel.writeOutbound(data.retain()));
78+
assertTrue(channel.finish());
79+
80+
ByteBuf decompressed = readDecompressed(dataLength);
81+
assertEquals(data.resetReaderIndex(), decompressed);
82+
83+
decompressed.release();
84+
data.release();
85+
}
86+
87+
protected void testCompressionOfBatchedFlow(final ByteBuf data) throws Exception {
88+
final int dataLength = data.readableBytes();
89+
int written = 0, length = rand.nextInt(100);
90+
while (written + length < dataLength) {
91+
ByteBuf in = data.slice(written, length);
92+
assertTrue(channel.writeOutbound(in.retain()));
93+
written += length;
94+
length = rand.nextInt(100);
95+
}
96+
ByteBuf in = data.slice(written, dataLength - written);
97+
assertTrue(channel.writeOutbound(in.retain()));
98+
assertTrue(channel.finish());
99+
100+
ByteBuf decompressed = readDecompressed(dataLength);
101+
assertEquals(data, decompressed);
102+
103+
decompressed.release();
104+
data.release();
105+
}
106+
107+
protected ByteBuf readDecompressed(final int dataLength) throws Exception {
108+
CompositeByteBuf compressed = Unpooled.compositeBuffer();
109+
ByteBuf msg;
110+
while ((msg = channel.readOutbound()) != null) {
111+
compressed.addComponent(msg);
112+
compressed.writerIndex(compressed.writerIndex() + msg.readableBytes());
113+
}
114+
ByteBuf decompressed = decompress(compressed, dataLength);
115+
compressed.release();
116+
return decompressed;
117+
}
118+
}

0 commit comments

Comments
 (0)