Compress the heap dump after tests are finished

Motivation:

Tests sometimes time out because it took too long to compress the
generated heap dump.

Modifications:

- Move the compression logic to a new method 'compressHeapDumps()'
- Call TestUtils.compressHeapDumps() at the end of the tests, so that
  the tests do not fail because of timeout

Result:

JUnit reports the real cause of the test failure instead of timeout
exception.
This commit is contained in:
Trustin Lee 2014-12-16 16:13:08 +09:00
parent 9ee75126eb
commit c7b407e288
3 changed files with 99 additions and 50 deletions

View File

@ -26,7 +26,10 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.testsuite.util.TestUtils; import io.netty.testsuite.util.TestUtils;
import io.netty.util.internal.StringUtil; import io.netty.util.internal.StringUtil;
import org.junit.AfterClass;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.Timeout;
import java.io.IOException; import java.io.IOException;
import java.util.Random; import java.util.Random;
@ -36,6 +39,9 @@ import static org.junit.Assert.*;
public class SocketGatheringWriteTest extends AbstractSocketTest { public class SocketGatheringWriteTest extends AbstractSocketTest {
@Rule
public final Timeout globalTimeout = new Timeout(60000);
private static final Random random = new Random(); private static final Random random = new Random();
static final byte[] data = new byte[1048576]; static final byte[] data = new byte[1048576];
@ -43,7 +49,12 @@ public class SocketGatheringWriteTest extends AbstractSocketTest {
random.nextBytes(data); random.nextBytes(data);
} }
@Test(timeout = 60000) @AfterClass
public static void compressHeapDumps() throws Exception {
TestUtils.compressHeapDumps();
}
@Test
public void testGatheringWrite() throws Throwable { public void testGatheringWrite() throws Throwable {
run(); run();
} }
@ -52,7 +63,7 @@ public class SocketGatheringWriteTest extends AbstractSocketTest {
testGatheringWrite0(sb, cb, data, false, true); testGatheringWrite0(sb, cb, data, false, true);
} }
@Test(timeout = 60000) @Test
public void testGatheringWriteNotAutoRead() throws Throwable { public void testGatheringWriteNotAutoRead() throws Throwable {
run(); run();
} }
@ -61,7 +72,7 @@ public class SocketGatheringWriteTest extends AbstractSocketTest {
testGatheringWrite0(sb, cb, data, false, false); testGatheringWrite0(sb, cb, data, false, false);
} }
@Test(timeout = 60000) @Test
public void testGatheringWriteWithComposite() throws Throwable { public void testGatheringWriteWithComposite() throws Throwable {
run(); run();
} }
@ -70,7 +81,7 @@ public class SocketGatheringWriteTest extends AbstractSocketTest {
testGatheringWrite0(sb, cb, data, true, false); testGatheringWrite0(sb, cb, data, true, false);
} }
@Test(timeout = 60000) @Test
public void testGatheringWriteWithCompositeNotAutoRead() throws Throwable { public void testGatheringWriteWithCompositeNotAutoRead() throws Throwable {
run(); run();
} }
@ -80,7 +91,7 @@ public class SocketGatheringWriteTest extends AbstractSocketTest {
} }
// Test for https://github.com/netty/netty/issues/2647 // Test for https://github.com/netty/netty/issues/2647
@Test(timeout = 60000) @Test
public void testGatheringWriteBig() throws Throwable { public void testGatheringWriteBig() throws Throwable {
run(); run();
} }

View File

@ -39,6 +39,7 @@ import io.netty.util.concurrent.Future;
import io.netty.util.internal.StringUtil; import io.netty.util.internal.StringUtil;
import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory; import io.netty.util.internal.logging.InternalLoggerFactory;
import org.junit.AfterClass;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Parameterized; import org.junit.runners.Parameterized;
@ -189,6 +190,11 @@ public class SocketSslEchoTest extends AbstractSocketTest {
run(); run();
} }
@AfterClass
public static void compressHeapDumps() throws Exception {
TestUtils.compressHeapDumps();
}
public void testSslEcho(ServerBootstrap sb, Bootstrap cb) throws Throwable { public void testSslEcho(ServerBootstrap sb, Bootstrap cb) throws Throwable {
final ExecutorService delegatedTaskExecutor = Executors.newCachedThreadPool(); final ExecutorService delegatedTaskExecutor = Executors.newCachedThreadPool();
final EchoHandler sh = new EchoHandler(true); final EchoHandler sh = new EchoHandler(true);

View File

@ -27,6 +27,7 @@ import javax.management.MBeanServer;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@ -44,6 +45,7 @@ import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.concurrent.TimeUnit;
public final class TestUtils { public final class TestUtils {
@ -59,6 +61,8 @@ public final class TestUtils {
private static final Method hotspotMXBeanDumpHeap; private static final Method hotspotMXBeanDumpHeap;
private static final Object hotspotMXBean; private static final Object hotspotMXBean;
private static final long DUMP_PROGRESS_LOGGING_INTERVAL = TimeUnit.SECONDS.toNanos(5);
static { static {
// Populate the list of random ports. // Populate the list of random ports.
for (int i = START_PORT; i < END_PORT; i ++) { for (int i = START_PORT; i < END_PORT; i ++) {
@ -226,6 +230,79 @@ public final class TestUtils {
dumpThreads(threadDumpFile); dumpThreads(threadDumpFile);
} }
public static void compressHeapDumps() throws IOException {
final File[] files = new File(System.getProperty("user.dir")).listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".hprof");
}
});
final byte[] buf = new byte[65536];
final LZMA2Options options = new LZMA2Options(9);
for (File file: files) {
final String filename = file.toString();
final String xzFilename = filename + ".xz";
final long fileLength = file.length();
logger.info("Compressing the heap dump: {}", xzFilename);
long lastLogTime = System.nanoTime();
long counter = 0;
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(filename);
out = new XZOutputStream(new FileOutputStream(xzFilename), options);
for (;;) {
int readBytes = in.read(buf);
if (readBytes < 0) {
break;
}
if (readBytes == 0) {
continue;
}
out.write(buf, 0, readBytes);
counter += readBytes;
long currentTime = System.nanoTime();
if (currentTime - lastLogTime > DUMP_PROGRESS_LOGGING_INTERVAL) {
logger.info("Compressing the heap dump: {} ({}%)",
xzFilename, counter * 100 / fileLength);
lastLogTime = currentTime;
}
}
out.close();
in.close();
} catch (Exception e) {
logger.warn("Failed to compress the heap dump: {}", xzFilename, e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ignored) {
// Ignore.
}
}
if (out != null) {
try {
out.close();
} catch (IOException ignored) {
// Ignore.
}
}
}
// Delete the uncompressed dump in favor of the compressed one.
if (!file.delete()) {
logger.warn("Failed to delete the uncompressed heap dump: {}", filename);
}
}
}
private static String timestamp() { private static String timestamp() {
return new SimpleDateFormat("HHmmss.SSS").format(new Date()); return new SimpleDateFormat("HHmmss.SSS").format(new Date());
} }
@ -242,51 +319,6 @@ public final class TestUtils {
hotspotMXBeanDumpHeap.invoke(hotspotMXBean, filename, true); hotspotMXBeanDumpHeap.invoke(hotspotMXBean, filename, true);
} catch (Exception e) { } catch (Exception e) {
logger.warn("Failed to dump heap: {}", filename, e); logger.warn("Failed to dump heap: {}", filename, e);
return;
}
final String xzFilename = filename + ".xz";
logger.info("Compressing the heap dump: {}", xzFilename);
final byte[] buf = new byte[65536];
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(filename);
out = new XZOutputStream(new FileOutputStream(xzFilename), new LZMA2Options(9));
for (;;) {
int readBytes = in.read(buf);
if (readBytes < 0) {
break;
}
if (readBytes == 0) {
continue;
}
out.write(buf, 0, readBytes);
}
out.close();
in.close();
} catch (Exception e) {
logger.warn("Failed to compress the heap dump: {}", xzFilename, e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException ignored) {
// Ignore.
}
}
if (out != null) {
try {
out.close();
} catch (IOException ignored) {
// Ignore.
}
}
}
// Delete the uncompressed dump in favor of the compressed one.
if (!file.delete()) {
logger.warn("Failed to delete the uncompressed heap dump: {}", filename);
} }
} }