/*
* The MIT License
*
* Copyright (c) 2014 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.github.olivergondza.dumpling.factory;
import static com.github.olivergondza.dumpling.Util.only;
import static com.github.olivergondza.dumpling.Util.pause;
import static com.github.olivergondza.dumpling.model.ProcessThread.nameIs;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.iterableWithSize;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.spy;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.Nonnull;
import com.github.olivergondza.dumpling.DisposeRule;
import com.github.olivergondza.dumpling.model.jvm.JvmRuntime;
import com.github.olivergondza.dumpling.model.jvm.JvmThread;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.hamcrest.TypeSafeMatcher;
import org.hamcrest.collection.IsEmptyCollection;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mockito;
import com.github.olivergondza.dumpling.Util;
import com.github.olivergondza.dumpling.model.ModelObject.Mode;
import com.github.olivergondza.dumpling.model.ProcessRuntime;
import com.github.olivergondza.dumpling.model.StackTrace;
import com.github.olivergondza.dumpling.model.ThreadLock;
import com.github.olivergondza.dumpling.model.ThreadStatus;
import com.github.olivergondza.dumpling.model.dump.ThreadDumpRuntime;
import com.github.olivergondza.dumpling.model.dump.ThreadDumpThread;
import com.github.olivergondza.dumpling.model.dump.ThreadDumpThreadSet;
public class ThreadDumpFactoryTest {
private static final ThreadDumpFactory FACTORY = new ThreadDumpFactory().failOnErrors(true);
public @Rule DisposeRule cleaner = new DisposeRule();
@Test
public void openJdk7_60() throws Exception {
ThreadDumpThreadSet threads = runtimeFrom("openjdk-1.7.0_60.log").getThreads();
assertEquals(35, threads.size());
ThreadDumpThread main = threads.where(nameIs("main")).onlyThread();
assertEquals(ThreadStatus.RUNNABLE, main.getStatus());
assertEquals(Thread.State.RUNNABLE, main.getState());
assertThat(139675222183936L, equalTo(main.getTid()));
assertThat(24597L, equalTo(main.getNid()));
assertEquals(10, main.getPriority().intValue());
StackTrace trace = main.getStackTrace();
assertEquals(27, trace.size());
assertEquals("org.eclipse.swt.internal.gtk.OS", trace.getElement(0).getClassName());
assertEquals("Call", trace.getElement(0).getMethodName());
assertEquals(null, trace.getElement(0).getFileName());
assertEquals(-2, trace.getElement(0).getLineNumber());
assertEquals("org.eclipse.swt.widgets.Display", trace.getElement(1).getClassName());
assertEquals("sleep", trace.getElement(1).getMethodName());
assertEquals("Display.java", trace.getElement(1).getFileName());
assertEquals(4233, trace.getElement(1).getLineNumber());
}
@Test
public void oracleJdk7_51() throws Exception {
ThreadDumpThreadSet threads = runtimeFrom("oraclejdk-1.7.0_51.log").getThreads();
assertEquals(143, threads.size());
ThreadDumpThread thread = threads.where(nameIs("Channel reader thread: jenkins_slave_02")).onlyThread();
assertEquals(ThreadStatus.RUNNABLE, thread.getStatus());
StackTrace trace = thread.getStackTrace();
assertEquals(13, trace.size());
assertEquals("java.io.FileInputStream", trace.getElement(0).getClassName());
assertEquals("readBytes", trace.getElement(0).getMethodName());
assertEquals(null, trace.getElement(0).getFileName());
assertEquals(-2, trace.getElement(0).getLineNumber());
StackTraceElement lastTrace = trace.getElement(trace.size() - 1);
assertEquals("hudson.remoting.SynchronousCommandTransport$ReaderThread", lastTrace.getClassName());
assertEquals("run", lastTrace.getMethodName());
assertEquals("SynchronousCommandTransport.java", lastTrace.getFileName());
assertEquals(48, lastTrace.getLineNumber());
}
@Test @Ignore
public void oracleJdk6() throws Exception {
ThreadDumpThreadSet threads = runtimeFrom("oraclejdk-1.6.log").getThreads();
assertEquals(15, threads.size());
}
@Test
public void oracleJdk7() throws Exception {
ThreadDumpRuntime expected = runtime(
daemon("Attach Listener").setTid(194867200).setNid(18909).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10),
thread("GC task thread#0 (ParallelGC)").setTid(191416320).setNid(18882).setPriority(10),
thread("GC task thread#1 (ParallelGC)").setTid(191424512).setNid(18883).setPriority(10),
thread("GC task thread#2 (ParallelGC)").setTid(191430656).setNid(18884).setPriority(10),
thread("GC task thread#3 (ParallelGC)").setTid(191438848).setNid(18885).setPriority(10),
thread("VM Periodic Task Thread").setTid(192006144).setNid(18893).setPriority(10),
daemon("Signal Dispatcher").setTid(191895552).setNid(18889).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10),
daemon("process reaper").setTid(47867348480000L).setNid(18895).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10),
daemon("C2 CompilerThread0").setTid(191905792).setNid(18890).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10),
daemon("C2 CompilerThread1").setTid(191952896).setNid(18891).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10),
thread("VM Thread").setTid(191717376).setNid(18886).setPriority(10),
daemon("Service Thread").setTid(191963136).setNid(18892).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10),
daemon("Finalizer").setTid(191744000).setNid(18888).setThreadStatus(ThreadStatus.IN_OBJECT_WAIT).setPriority(10)
.setWaitingOnLock(lock("java.lang.ref.ReferenceQueue$Lock", 33678346384L))
,
daemon("Reference Handler").setTid(191727616).setNid(18887).setThreadStatus(ThreadStatus.IN_OBJECT_WAIT).setPriority(10)
.setWaitingOnLock(lock("java.lang.ref.Reference$Lock", 33678167272L))
,
thread("main").setTid(191326208).setNid(18881).setThreadStatus(ThreadStatus.IN_OBJECT_WAIT).setPriority(10)
.setWaitingOnLock(lock("java.lang.UNIXProcess", 33649075520L))
);
ThreadDumpRuntime actual = runtimeFrom("oraclejdk-1.7.log");
assertThat(actual, sameThreadsAs(expected));
StackTrace expectedStackTrace = new StackTrace(
StackTrace.nativeElement("java.lang.Object", "wait"),
StackTrace.element("java.lang.Object", "wait", "Object.java", 503),
StackTrace.element("java.lang.UNIXProcess", "waitFor", "UNIXProcess.java", 210),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 57),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 606),
StackTrace.element("org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSiteNoUnwrapNoCoerce", "invoke", "PojoMetaMethodSite.java", 230),
StackTrace.element("org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite", "call", "PojoMetaMethodSite.java", 53),
StackTrace.element("org.codehaus.groovy.runtime.callsite.CallSiteArray", "defaultCall", "CallSiteArray.java", 45),
StackTrace.element("org.codehaus.groovy.runtime.callsite.AbstractCallSite", "call", "AbstractCallSite.java", 108),
StackTrace.element("org.codehaus.groovy.runtime.callsite.AbstractCallSite", "call", "AbstractCallSite.java", 112),
StackTrace.element("hudson5336955934972498423", "run", "hudson5336955934972498423.groovy", 9),
StackTrace.element("groovy.lang.GroovyShell", "runScriptOrMainOrTestOrRunnable", "GroovyShell.java", 257),
StackTrace.element("groovy.lang.GroovyShell", "run", "GroovyShell.java", 220),
StackTrace.element("groovy.lang.GroovyShell", "run", "GroovyShell.java", 150),
StackTrace.element("groovy.ui.GroovyMain", "processOnce", "GroovyMain.java", 588),
StackTrace.element("groovy.ui.GroovyMain", "run", "GroovyMain.java", 375),
StackTrace.element("groovy.ui.GroovyMain", "process", "GroovyMain.java", 361),
StackTrace.element("groovy.ui.GroovyMain", "processArgs", "GroovyMain.java", 120),
StackTrace.element("groovy.ui.GroovyMain", "main", "GroovyMain.java", 100),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 57),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 606),
StackTrace.element("org.codehaus.groovy.tools.GroovyStarter", "rootLoader", "GroovyStarter.java", 106),
StackTrace.element("org.codehaus.groovy.tools.GroovyStarter", "main", "GroovyStarter.java", 128)
);
assertThat(actual, stacktraceEquals(expectedStackTrace, "main"));
}
@Test
public void oracleJdk8() throws Exception {
ThreadDumpRuntime expected = runtime(
daemon("Attach Listener").setTid(1716535296).setNid(8144).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9).setId(11),
thread("GC task thread#0 (ParallelGC)").setTid(3059810304L).setNid(8115),
thread("GC task thread#1 (ParallelGC)").setTid(3059815424L).setNid(8116),
thread("GC task thread#2 (ParallelGC)").setTid(3059820544L).setNid(8117),
thread("GC task thread#3 (ParallelGC)").setTid(3059825664L).setNid(8118),
thread("VM Periodic Task Thread").setTid(1718347776).setNid(8127),
daemon("Signal Dispatcher").setTid(1718240256).setNid(8122).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9).setId(4),
daemon("process reaper").setTid(1697889280).setNid(8129).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10).setId(10),
daemon("C2 CompilerThread0").setTid(1718247424).setNid(8123).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9).setId(5),
daemon("C2 CompilerThread1").setTid(1718254592).setNid(8124).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9).setId(6),
daemon("C1 CompilerThread2").setTid(1718260736).setNid(8125).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9).setId(7),
thread("VM Thread").setTid(1718094848).setNid(8119),
daemon("Service Thread").setTid(1718273024).setNid(8126).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9).setId(8),
daemon("Finalizer").setTid(1718118400).setNid(8121).setThreadStatus(ThreadStatus.IN_OBJECT_WAIT).setPriority(8).setId(3)
.setWaitingOnLock(lock("java.lang.ref.ReferenceQueue$Lock", 2495908272L))
,
daemon("Reference Handler").setTid(1718108160).setNid(8120).setThreadStatus(ThreadStatus.IN_OBJECT_WAIT).setPriority(10).setId(2)
.setWaitingOnLock(lock("java.lang.ref.Reference$Lock", 2495922552L))
,
thread("main").setTid(3059771392L).setNid(8114).setThreadStatus(ThreadStatus.IN_OBJECT_WAIT).setPriority(5).setId(1)
.setWaitingOnLock(lock("java.lang.UNIXProcess", 2468857072L))
);
ThreadDumpRuntime actual = runtimeFrom("oraclejdk-1.8.log");
assertThat(actual, sameThreadsAs(expected));
StackTrace expectedStackTrace = new StackTrace(
StackTrace.nativeElement("java.lang.Object", "wait"),
StackTrace.element("java.lang.Object", "wait", "Object.java", 502),
StackTrace.element("java.lang.UNIXProcess", "waitFor", "UNIXProcess.java", 264),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 62),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 483),
StackTrace.element("org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSiteNoUnwrapNoCoerce", "invoke", "PojoMetaMethodSite.java", 230),
StackTrace.element("org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite", "call", "PojoMetaMethodSite.java", 53),
StackTrace.element("org.codehaus.groovy.runtime.callsite.CallSiteArray", "defaultCall", "CallSiteArray.java", 45),
StackTrace.element("org.codehaus.groovy.runtime.callsite.AbstractCallSite", "call", "AbstractCallSite.java", 108),
StackTrace.element("org.codehaus.groovy.runtime.callsite.AbstractCallSite", "call", "AbstractCallSite.java", 112),
StackTrace.element("hudson8109898462652879487", "run", "hudson8109898462652879487.groovy", 9),
StackTrace.element("groovy.lang.GroovyShell", "runScriptOrMainOrTestOrRunnable", "GroovyShell.java", 257),
StackTrace.element("groovy.lang.GroovyShell", "run", "GroovyShell.java", 220),
StackTrace.element("groovy.lang.GroovyShell", "run", "GroovyShell.java", 150),
StackTrace.element("groovy.ui.GroovyMain", "processOnce", "GroovyMain.java", 588),
StackTrace.element("groovy.ui.GroovyMain", "run", "GroovyMain.java", 375),
StackTrace.element("groovy.ui.GroovyMain", "process", "GroovyMain.java", 361),
StackTrace.element("groovy.ui.GroovyMain", "processArgs", "GroovyMain.java", 120),
StackTrace.element("groovy.ui.GroovyMain", "main", "GroovyMain.java", 100),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 62),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 483),
StackTrace.element("org.codehaus.groovy.tools.GroovyStarter", "rootLoader", "GroovyStarter.java", 106),
StackTrace.element("org.codehaus.groovy.tools.GroovyStarter", "main", "GroovyStarter.java", 128)
);
assertThat(actual, stacktraceEquals(expectedStackTrace, "main"));
}
@Test
public void oracleJdk9() throws Exception {
ThreadDumpRuntime expected = runtime(
daemon("Attach Listener").setTid(0x7fb8f8001000L).setNid(12525).setId(14).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9),
thread("GC Thread#0").setTid(0x7fb980028000L).setNid(12396),
thread("GC Thread#1").setTid(0x7fb980029800L).setNid(12397),
thread("GC Thread#2").setTid(0x7fb98002b000L).setNid(12398),
thread("GC Thread#3").setTid(0x7fb98002c800L).setNid(12399),
thread("GC Thread#4").setTid(0x7fb98002e800L).setNid(12400),
thread("GC Thread#5").setTid(0x7fb980030000L).setNid(12401),
thread("GC Thread#6").setTid(0x7fb980032000L).setNid(12402),
thread("GC Thread#7").setTid(0x7fb980033800L).setNid(12403),
thread("G1 Main Marker").setTid(0x7fb980089000L).setNid(12413),
thread("G1 Marker#0").setTid(0x7fb98008b000L).setNid(12414),
thread("G1 Marker#1").setTid(0x7fb98008c800L).setNid(12415),
thread("G1 Refine#0").setTid(0x7fb980042000L).setNid(12411),
thread("G1 Refine#1").setTid(0x7fb980040800L).setNid(12410),
thread("G1 Refine#2").setTid(0x7fb98003e800L).setNid(12409),
thread("G1 Refine#3").setTid(0x7fb98003d000L).setNid(12408),
thread("G1 Refine#4").setTid(0x7fb98003b000L).setNid(12407),
thread("G1 Refine#5").setTid(0x7fb980039800L).setNid(12406),
thread("G1 Refine#6").setTid(0x7fb980037800L).setNid(12405),
thread("G1 Refine#7").setTid(0x7fb980036000L).setNid(12404),
thread("G1 Young RemSet Sampling").setTid(0x7fb980044000L).setNid(0x307c),
thread("Common-Cleaner").setTid(0x7fb98022c800L).setNid(12426).setId(11).setThreadStatus(ThreadStatus.IN_OBJECT_WAIT_TIMED).setPriority(8).setDaemon(true)
.setWaitingOnLock(lock("java.lang.ref.ReferenceQueue$Lock", 0x6d8b47ea0L))
,
thread("VM Periodic Task Thread").setTid(0x7fb9802d2000L).setNid(12428),
daemon("Signal Dispatcher").setTid(0x7fb9801ff000L).setNid(12420).setId(5).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9),
daemon("C2 CompilerThread0").setTid(0x7fb980201800L).setNid(12421).setId(6).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9),
daemon("C2 CompilerThread1").setTid(0x7fb980203800L).setNid(12422).setId(7).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9),
daemon("C2 CompilerThread2").setTid(0x7fb980205800L).setNid(12423).setId(8).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9),
//daemon("C2 CompilerThread3").setTid(0x7fb980207800L).setNid(12424).setId(9).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9),
daemon("C1 CompilerThread3").setTid(0x7fb980207800L).setNid(12424).setId(9).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9),
thread("VM Thread").setTid(0x7fb9801c7000L).setNid(12416),
daemon("Service Thread").setTid(0x7fb9802cf000L).setNid(12427).setId(12).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9),
daemon("Sweeper thread").setTid(0x7fb980211000L).setNid(12425).setId(10).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9),
daemon("Reference Pending List Locker").setTid(0x7fb9801fd800L).setNid(12419).setId(4).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9),
daemon("Finalizer").setTid(0x7fb9801d7000L).setNid(12418).setId(3).setThreadStatus(ThreadStatus.IN_OBJECT_WAIT).setPriority(8)
.setWaitingOnLock(lock("java.lang.ref.ReferenceQueue$Lock", 0x6d8b47e90L))
,
daemon("Reference Handler").setTid(0x7fb9801d3000L).setNid(12417).setId(2).setThreadStatus(ThreadStatus.IN_OBJECT_WAIT).setPriority(10)
.setWaitingOnLock(lock("java.lang.ref.Reference$Lock", 0x6d8b47e80L))
,
thread("main").setTid(0x7fb980010800L).setNid(12395).setId(1).setThreadStatus(ThreadStatus.SLEEPING).setPriority(5)
);
ThreadDumpRuntime actual = runtimeFrom("oraclejdk-1.9.log");
assertThat(actual, sameThreadsAs(expected));
StackTrace expectedStackTrace = new StackTrace(
StackTrace.nativeElement("java.lang.Thread", "sleep"),
StackTrace.nativeElement("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 62),
StackTrace.element("jdk.internal.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 535),
StackTrace.element("org.codehaus.groovy.reflection.CachedMethod", "invoke", "CachedMethod.java", 93),
StackTrace.element("groovy.lang.MetaMethod", "doMethodInvoke", "MetaMethod.java", 325),
StackTrace.element("org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite$StaticMetaMethodSiteNoUnwrap", "invoke", "StaticMetaMethodSite.java", 133),
StackTrace.element("org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite", "call", "StaticMetaMethodSite.java", 91),
StackTrace.element("org.codehaus.groovy.runtime.callsite.CallSiteArray", "defaultCall", "CallSiteArray.java", 48),
StackTrace.element("org.codehaus.groovy.runtime.callsite.AbstractCallSite", "call", "AbstractCallSite.java", 113),
StackTrace.element("org.codehaus.groovy.runtime.callsite.AbstractCallSite", "call", "AbstractCallSite.java", 125),
StackTrace.element("script_from_command_line", "run", "script_from_command_line", 1),
StackTrace.element("groovy.lang.GroovyShell", "runScriptOrMainOrTestOrRunnable", "GroovyShell.java", 263),
StackTrace.element("groovy.lang.GroovyShell", "run", "GroovyShell.java", 518),
StackTrace.element("groovy.lang.GroovyShell", "run", "GroovyShell.java", 507),
StackTrace.element("groovy.ui.GroovyMain", "processOnce", "GroovyMain.java", 653),
StackTrace.element("groovy.ui.GroovyMain", "run", "GroovyMain.java", 384),
StackTrace.element("groovy.ui.GroovyMain", "process", "GroovyMain.java", 370),
StackTrace.element("groovy.ui.GroovyMain", "processArgs", "GroovyMain.java", 129),
StackTrace.element("groovy.ui.GroovyMain", "main", "GroovyMain.java", 109),
StackTrace.nativeElement("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("jdk.internal.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 62),
StackTrace.element("jdk.internal.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 535),
StackTrace.element("org.codehaus.groovy.tools.GroovyStarter", "rootLoader", "GroovyStarter.java", 109),
StackTrace.element("org.codehaus.groovy.tools.GroovyStarter", "main", "GroovyStarter.java", 131)
);
assertThat(actual, stacktraceEquals(expectedStackTrace, "main"));
}
@Test
public void openjdk6() throws Exception {
ThreadDumpRuntime expected = runtime(
daemon("Attach Listener").setTid(507363328).setNid(28597).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10),
thread("GC task thread#0 (ParallelGC)").setTid(504647680).setNid(28568).setPriority(10),
thread("GC task thread#1 (ParallelGC)").setTid(504655872).setNid(28569).setPriority(10),
thread("GC task thread#2 (ParallelGC)").setTid(504662016).setNid(28570).setPriority(10),
thread("GC task thread#3 (ParallelGC)").setTid(504670208).setNid(28571).setPriority(10),
thread("VM Periodic Task Thread").setTid(505618432).setNid(28579).setPriority(10),
daemon("Signal Dispatcher").setTid(505575424).setNid(28575).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10),
daemon("process reaper").setTid(47702392721408L).setNid(28582).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10),
daemon("C2 CompilerThread0").setTid(505583616).setNid(28576).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10),
daemon("C2 CompilerThread1").setTid(505595904).setNid(28577).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10),
thread("VM Thread").setTid(505159680).setNid(28572).setPriority(10),
daemon("Low Memory Detector").setTid(505606144).setNid(28578).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10),
daemon("Finalizer").setTid(505229312).setNid(28574).setThreadStatus(ThreadStatus.IN_OBJECT_WAIT).setPriority(10)
.setWaitingOnLock(lock("java.lang.ref.ReferenceQueue$Lock", 3773522592L))
,
daemon("Reference Handler").setTid(505221120).setNid(28573).setThreadStatus(ThreadStatus.IN_OBJECT_WAIT).setPriority(10)
.setWaitingOnLock(lock("java.lang.ref.Reference$Lock", 3773521872L))
,
thread("main").setTid(504590336).setNid(28567).setThreadStatus(ThreadStatus.IN_OBJECT_WAIT).setPriority(10)
.setWaitingOnLock(lock("java.lang.UNIXProcess", 3791474536L))
);
ThreadDumpRuntime actual = runtimeFrom("openjdk-1.6.log");
assertThat(actual, sameThreadsAs(expected));
StackTrace expectedStackTrace = new StackTrace(
StackTrace.nativeElement("java.lang.Object", "wait"),
StackTrace.element("java.lang.Object", "wait", "Object.java", 502),
StackTrace.element("java.lang.UNIXProcess", "waitFor", "UNIXProcess.java", 181),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 57),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 622),
StackTrace.element("org.codehaus.groovy.reflection.CachedMethod", "invoke", "CachedMethod.java", 86),
StackTrace.element("groovy.lang.MetaMethod", "doMethodInvoke", "MetaMethod.java", 226),
StackTrace.element("groovy.lang.MetaClassImpl", "invokeMethod", "MetaClassImpl.java", 899),
StackTrace.element("groovy.lang.MetaClassImpl", "invokeMethod", "MetaClassImpl.java", 740),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "invokePojoMethod", "InvokerHelper.java", 765),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "invokeMethod", "InvokerHelper.java", 753),
StackTrace.element("org.codehaus.groovy.runtime.ScriptBytecodeAdapter", "invokeMethodN", "ScriptBytecodeAdapter.java", 167),
StackTrace.element("org.codehaus.groovy.runtime.ScriptBytecodeAdapter", "invokeMethod0", "ScriptBytecodeAdapter.java", 195),
StackTrace.element("hudson2995743014782811370", "run", "hudson2995743014782811370.groovy", 11),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 57),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 622),
StackTrace.element("org.codehaus.groovy.reflection.CachedMethod", "invoke", "CachedMethod.java", 86),
StackTrace.element("groovy.lang.MetaMethod", "doMethodInvoke", "MetaMethod.java", 226),
StackTrace.element("groovy.lang.MetaClassImpl", "invokeMethod", "MetaClassImpl.java", 899),
StackTrace.element("groovy.lang.MetaClassImpl", "invokeMethod", "MetaClassImpl.java", 740),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "invokePogoMethod", "InvokerHelper.java", 777),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "invokeMethod", "InvokerHelper.java", 757),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "runScript", "InvokerHelper.java", 402),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 57),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 622),
StackTrace.element("org.codehaus.groovy.reflection.CachedMethod", "invoke", "CachedMethod.java", 86),
StackTrace.element("groovy.lang.MetaMethod", "doMethodInvoke", "MetaMethod.java", 226),
StackTrace.element("groovy.lang.MetaClassImpl", "invokeStaticMethod", "MetaClassImpl.java", 1094),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "invokeMethod", "InvokerHelper.java", 748),
StackTrace.element("org.codehaus.groovy.runtime.ScriptBytecodeAdapter", "invokeMethodN", "ScriptBytecodeAdapter.java", 167),
StackTrace.element("hudson2995743014782811370", "main", "hudson2995743014782811370.groovy"),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 57),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 622),
StackTrace.element("org.codehaus.groovy.reflection.CachedMethod", "invoke", "CachedMethod.java", 86),
StackTrace.element("groovy.lang.MetaMethod", "doMethodInvoke", "MetaMethod.java", 226),
StackTrace.element("groovy.lang.MetaClassImpl", "invokeStaticMethod", "MetaClassImpl.java", 1094),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "invokeMethod", "InvokerHelper.java", 748),
StackTrace.element("groovy.lang.GroovyShell", "runMainOrTestOrRunnable", "GroovyShell.java", 244),
StackTrace.element("groovy.lang.GroovyShell", "run", "GroovyShell.java", 218),
StackTrace.element("groovy.lang.GroovyShell", "run", "GroovyShell.java", 147),
StackTrace.element("groovy.ui.GroovyMain", "processOnce", "GroovyMain.java", 493),
StackTrace.element("groovy.ui.GroovyMain", "run", "GroovyMain.java", 308),
StackTrace.element("groovy.ui.GroovyMain", "process", "GroovyMain.java", 294),
StackTrace.element("groovy.ui.GroovyMain", "processArgs", "GroovyMain.java", 111),
StackTrace.element("groovy.ui.GroovyMain", "main", "GroovyMain.java", 92),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 57),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 622),
StackTrace.element("org.codehaus.groovy.tools.GroovyStarter", "rootLoader", "GroovyStarter.java", 101),
StackTrace.element("org.codehaus.groovy.tools.GroovyStarter", "main", "GroovyStarter.java", 130)
);
assertThat(actual, stacktraceEquals(expectedStackTrace, "main"));
}
@Test
public void openjdk7() throws Exception {
ThreadDumpRuntime expected = runtime(
daemon("Attach Listener").setTid(1740638208).setNid(32404).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10),
thread("GC task thread#0 (ParallelGC)").setTid(3075542016L).setNid(32366).setPriority(10),
thread("GC task thread#1 (ParallelGC)").setTid(3075547136L).setNid(32367).setPriority(10),
thread("GC task thread#2 (ParallelGC)").setTid(3075553280L).setNid(32368).setPriority(10),
thread("GC task thread#3 (ParallelGC)").setTid(3075559424L).setNid(32369).setPriority(10),
thread("GC task thread#4 (ParallelGC)").setTid(3075564544L).setNid(32370).setPriority(10),
thread("GC task thread#5 (ParallelGC)").setTid(3075570688L).setNid(32371).setPriority(10),
thread("GC task thread#6 (ParallelGC)").setTid(3075576832L).setNid(32372).setPriority(10),
thread("GC task thread#7 (ParallelGC)").setTid(3075581952L).setNid(32373).setPriority(10),
thread("VM Periodic Task Thread").setTid(1748556800).setNid(32381).setPriority(10),
daemon("Signal Dispatcher").setTid(1748527104).setNid(32377).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10),
daemon("process reaper").setTid(1734433792).setNid(32385).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10),
daemon("C2 CompilerThread0").setTid(1748534272).setNid(32378).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10),
daemon("C2 CompilerThread1").setTid(1748542464).setNid(32379).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10),
thread("VM Thread").setTid(1748436992).setNid(32374).setPriority(10),
daemon("Service Thread").setTid(1748549632).setNid(32380).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10),
daemon("Finalizer").setTid(1748454400).setNid(32376).setThreadStatus(ThreadStatus.IN_OBJECT_WAIT).setPriority(10)
.setWaitingOnLock(lock("java.lang.ref.ReferenceQueue$Lock", 2683571272L))
,
daemon("Reference Handler").setTid(1748448256).setNid(32375).setThreadStatus(ThreadStatus.IN_OBJECT_WAIT).setPriority(10)
.setWaitingOnLock(lock("java.lang.ref.Reference$Lock", 2683601000L))
,
thread("main").setTid(3075500032L).setNid(32365).setThreadStatus(ThreadStatus.IN_OBJECT_WAIT).setPriority(10)
.setWaitingOnLock(lock("java.lang.UNIXProcess", 2672107728L))
);
ThreadDumpRuntime actual = runtimeFrom("openjdk-1.7.log");
assertThat(actual, sameThreadsAs(expected));
StackTrace expectedStackTrace = new StackTrace(
StackTrace.nativeElement("java.lang.Object", "wait"),
StackTrace.element("java.lang.Object", "wait", "Object.java", 503),
StackTrace.element("java.lang.UNIXProcess", "waitFor", "UNIXProcess.java", 210),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 57),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 606),
StackTrace.element("org.codehaus.groovy.reflection.CachedMethod", "invoke", "CachedMethod.java", 86),
StackTrace.element("groovy.lang.MetaMethod", "doMethodInvoke", "MetaMethod.java", 226),
StackTrace.element("groovy.lang.MetaClassImpl", "invokeMethod", "MetaClassImpl.java", 899),
StackTrace.element("groovy.lang.MetaClassImpl", "invokeMethod", "MetaClassImpl.java", 740),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "invokePojoMethod", "InvokerHelper.java", 765),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "invokeMethod", "InvokerHelper.java", 753),
StackTrace.element("org.codehaus.groovy.runtime.ScriptBytecodeAdapter", "invokeMethodN", "ScriptBytecodeAdapter.java", 167),
StackTrace.element("org.codehaus.groovy.runtime.ScriptBytecodeAdapter", "invokeMethod0", "ScriptBytecodeAdapter.java", 195),
StackTrace.element("hudson3357812930655452714", "run", "hudson3357812930655452714.groovy", 11),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 57),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 606),
StackTrace.element("org.codehaus.groovy.reflection.CachedMethod", "invoke", "CachedMethod.java", 86),
StackTrace.element("groovy.lang.MetaMethod", "doMethodInvoke", "MetaMethod.java", 226),
StackTrace.element("groovy.lang.MetaClassImpl", "invokeMethod", "MetaClassImpl.java", 899),
StackTrace.element("groovy.lang.MetaClassImpl", "invokeMethod", "MetaClassImpl.java", 740),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "invokePogoMethod", "InvokerHelper.java", 777),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "invokeMethod", "InvokerHelper.java", 757),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "runScript", "InvokerHelper.java", 402),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 57),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 606),
StackTrace.element("org.codehaus.groovy.reflection.CachedMethod", "invoke", "CachedMethod.java", 86),
StackTrace.element("groovy.lang.MetaMethod", "doMethodInvoke", "MetaMethod.java", 226),
StackTrace.element("groovy.lang.MetaClassImpl", "invokeStaticMethod", "MetaClassImpl.java", 1094),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "invokeMethod", "InvokerHelper.java", 748),
StackTrace.element("org.codehaus.groovy.runtime.ScriptBytecodeAdapter", "invokeMethodN", "ScriptBytecodeAdapter.java", 167),
StackTrace.element("hudson3357812930655452714", "main", "hudson3357812930655452714.groovy"),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 57),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 606),
StackTrace.element("org.codehaus.groovy.reflection.CachedMethod", "invoke", "CachedMethod.java", 86),
StackTrace.element("groovy.lang.MetaMethod", "doMethodInvoke", "MetaMethod.java", 226),
StackTrace.element("groovy.lang.MetaClassImpl", "invokeStaticMethod", "MetaClassImpl.java", 1094),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "invokeMethod", "InvokerHelper.java", 748),
StackTrace.element("groovy.lang.GroovyShell", "runMainOrTestOrRunnable", "GroovyShell.java", 244),
StackTrace.element("groovy.lang.GroovyShell", "run", "GroovyShell.java", 218),
StackTrace.element("groovy.lang.GroovyShell", "run", "GroovyShell.java", 147),
StackTrace.element("groovy.ui.GroovyMain", "processOnce", "GroovyMain.java", 493),
StackTrace.element("groovy.ui.GroovyMain", "run", "GroovyMain.java", 308),
StackTrace.element("groovy.ui.GroovyMain", "process", "GroovyMain.java", 294),
StackTrace.element("groovy.ui.GroovyMain", "processArgs", "GroovyMain.java", 111),
StackTrace.element("groovy.ui.GroovyMain", "main", "GroovyMain.java", 92),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 57),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 606),
StackTrace.element("org.codehaus.groovy.tools.GroovyStarter", "rootLoader", "GroovyStarter.java", 101),
StackTrace.element("org.codehaus.groovy.tools.GroovyStarter", "main", "GroovyStarter.java", 130)
);
assertThat(actual, stacktraceEquals(expectedStackTrace, "main"));
}
@Test
public void openjdk8() throws Exception {
ThreadDumpRuntime expected = runtime(
daemon("Attach Listener").setTid(1733312512).setNid(7829).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9).setId(11),
thread("GC task thread#0 (ParallelGC)").setTid(3076587520L).setNid(7798),
thread("GC task thread#1 (ParallelGC)").setTid(3076592640L).setNid(7799),
thread("GC task thread#2 (ParallelGC)").setTid(3076597760L).setNid(7800),
thread("GC task thread#3 (ParallelGC)").setTid(3076602880L).setNid(7801),
thread("VM Periodic Task Thread").setTid(1735156736).setNid(7811),
daemon("Signal Dispatcher").setTid(1735017472).setNid(7806).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9).setId(4),
daemon("process reaper").setTid(1724858368).setNid(7813).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(10).setId(10),
daemon("C2 CompilerThread0").setTid(1735023616).setNid(7807).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9).setId(5),
daemon("C2 CompilerThread1").setTid(1735031808).setNid(7808).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9).setId(6),
daemon("C1 CompilerThread2").setTid(1735036928).setNid(7809).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9).setId(7),
thread("VM Thread").setTid(1734872064).setNid(7802),
daemon("Service Thread").setTid(1735050240).setNid(7810).setThreadStatus(ThreadStatus.RUNNABLE).setPriority(9).setId(8),
daemon("Finalizer").setTid(1734894592).setNid(7804).setThreadStatus(ThreadStatus.IN_OBJECT_WAIT).setPriority(8).setId(3)
.setWaitingOnLock(lock("java.lang.ref.ReferenceQueue$Lock", 2493779712L))
,
daemon("Reference Handler").setTid(1734884352).setNid(7803).setThreadStatus(ThreadStatus.IN_OBJECT_WAIT).setPriority(10).setId(2)
.setWaitingOnLock(lock("java.lang.ref.Reference$Lock", 2493780128L))
,
thread("main").setTid(3076548608L).setNid(7797).setThreadStatus(ThreadStatus.IN_OBJECT_WAIT).setPriority(5).setId(1)
.setWaitingOnLock(lock("java.lang.UNIXProcess", 2485805968L))
);
ThreadDumpRuntime actual = runtimeFrom("openjdk-1.8.log");
assertThat(actual, sameThreadsAs(expected));
StackTrace expectedStackTrace = new StackTrace(
StackTrace.nativeElement("java.lang.Object", "wait"),
StackTrace.element("java.lang.Object", "wait", "Object.java", 502),
StackTrace.element("java.lang.UNIXProcess", "waitFor", "UNIXProcess.java", 264),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 62),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 483),
StackTrace.element("org.codehaus.groovy.reflection.CachedMethod", "invoke", "CachedMethod.java", 86),
StackTrace.element("groovy.lang.MetaMethod", "doMethodInvoke", "MetaMethod.java", 226),
StackTrace.element("groovy.lang.MetaClassImpl", "invokeMethod", "MetaClassImpl.java", 899),
StackTrace.element("groovy.lang.MetaClassImpl", "invokeMethod", "MetaClassImpl.java", 740),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "invokePojoMethod", "InvokerHelper.java", 765),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "invokeMethod", "InvokerHelper.java", 753),
StackTrace.element("org.codehaus.groovy.runtime.ScriptBytecodeAdapter", "invokeMethodN", "ScriptBytecodeAdapter.java", 167),
StackTrace.element("org.codehaus.groovy.runtime.ScriptBytecodeAdapter", "invokeMethod0", "ScriptBytecodeAdapter.java", 195),
StackTrace.element("hudson2530543046334227738", "run", "hudson2530543046334227738.groovy", 11),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 62),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 483),
StackTrace.element("org.codehaus.groovy.reflection.CachedMethod", "invoke", "CachedMethod.java", 86),
StackTrace.element("groovy.lang.MetaMethod", "doMethodInvoke", "MetaMethod.java", 226),
StackTrace.element("groovy.lang.MetaClassImpl", "invokeMethod", "MetaClassImpl.java", 899),
StackTrace.element("groovy.lang.MetaClassImpl", "invokeMethod", "MetaClassImpl.java", 740),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "invokePogoMethod", "InvokerHelper.java", 777),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "invokeMethod", "InvokerHelper.java", 757),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "runScript", "InvokerHelper.java", 402),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 62),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 483),
StackTrace.element("org.codehaus.groovy.reflection.CachedMethod", "invoke", "CachedMethod.java", 86),
StackTrace.element("groovy.lang.MetaMethod", "doMethodInvoke", "MetaMethod.java", 226),
StackTrace.element("groovy.lang.MetaClassImpl", "invokeStaticMethod", "MetaClassImpl.java", 1094),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "invokeMethod", "InvokerHelper.java", 748),
StackTrace.element("org.codehaus.groovy.runtime.ScriptBytecodeAdapter", "invokeMethodN", "ScriptBytecodeAdapter.java", 167),
StackTrace.element("hudson2530543046334227738", "main", "hudson2530543046334227738.groovy"),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 62),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 483),
StackTrace.element("org.codehaus.groovy.reflection.CachedMethod", "invoke", "CachedMethod.java", 86),
StackTrace.element("groovy.lang.MetaMethod", "doMethodInvoke", "MetaMethod.java", 226),
StackTrace.element("groovy.lang.MetaClassImpl", "invokeStaticMethod", "MetaClassImpl.java", 1094),
StackTrace.element("org.codehaus.groovy.runtime.InvokerHelper", "invokeMethod", "InvokerHelper.java", 748),
StackTrace.element("groovy.lang.GroovyShell", "runMainOrTestOrRunnable", "GroovyShell.java", 244),
StackTrace.element("groovy.lang.GroovyShell", "run", "GroovyShell.java", 218),
StackTrace.element("groovy.lang.GroovyShell", "run", "GroovyShell.java", 147),
StackTrace.element("groovy.ui.GroovyMain", "processOnce", "GroovyMain.java", 493),
StackTrace.element("groovy.ui.GroovyMain", "run", "GroovyMain.java", 308),
StackTrace.element("groovy.ui.GroovyMain", "process", "GroovyMain.java", 294),
StackTrace.element("groovy.ui.GroovyMain", "processArgs", "GroovyMain.java", 111),
StackTrace.element("groovy.ui.GroovyMain", "main", "GroovyMain.java", 92),
StackTrace.nativeElement("sun.reflect.NativeMethodAccessorImpl", "invoke0"),
StackTrace.element("sun.reflect.NativeMethodAccessorImpl", "invoke", "NativeMethodAccessorImpl.java", 62),
StackTrace.element("sun.reflect.DelegatingMethodAccessorImpl", "invoke", "DelegatingMethodAccessorImpl.java", 43),
StackTrace.element("java.lang.reflect.Method", "invoke", "Method.java", 483),
StackTrace.element("org.codehaus.groovy.tools.GroovyStarter", "rootLoader", "GroovyStarter.java", 101),
StackTrace.element("org.codehaus.groovy.tools.GroovyStarter", "main", "GroovyStarter.java", 130)
);
assertThat(actual, stacktraceEquals(expectedStackTrace, "main"));
}
@Test @Ignore
public void jrockit6() throws Exception {
ThreadDumpThreadSet threads = runtimeFrom("jrockit-1.6.log").getThreads();
assertEquals(15, threads.size());
}
@Test @Ignore
public void jrockit5() throws Exception {
ThreadDumpThreadSet threads = runtimeFrom("jrockit-1.5.log").getThreads();
assertEquals(15, threads.size());
}
@Test
public void preserveThreadOrder() throws Exception {
ThreadDumpThreadSet threads = FACTORY.fromStream(Util.resource(getClass(), "self-lock.log")).getThreads();
List<String> expectedNames = Arrays.asList(
"Service Thread",
"C2 CompilerThread1",
"C2 CompilerThread0",
"Signal Dispatcher",
"Finalizer",
"Reference Handler",
"VM Thread",
"GC task thread#0 (ParallelGC)",
"GC task thread#1 (ParallelGC)",
"GC task thread#2 (ParallelGC)",
"GC task thread#3 (ParallelGC)",
"VM Periodic Task Thread"
);
List<String> actualNames = new ArrayList<String>();
for (ThreadDumpThread thread: threads) {
actualNames.add(thread.getName());
}
assertThat(actualNames, equalTo(expectedNames));
}
@Test
public void parseStacktraceContaining$() throws Exception {
ThreadDumpThreadSet threads = runtimeFrom("oraclejdk-1.7.0_51.log").getThreads();
StackTrace actual = threads.where(nameIs("process reaper")).iterator().next().getStackTrace();
StackTrace expected = new StackTrace(
StackTrace.nativeElement("java.lang.UNIXProcess", "waitForProcessExit"),
StackTrace.element("java.lang.UNIXProcess", "access$200", "UNIXProcess.java", 54),
StackTrace.element("java.lang.UNIXProcess$3", "run", "UNIXProcess.java", 174),
StackTrace.element("java.util.concurrent.ThreadPoolExecutor", "runWorker", "ThreadPoolExecutor.java", 1145),
StackTrace.element("java.util.concurrent.ThreadPoolExecutor$Worker", "run", "ThreadPoolExecutor.java", 615),
StackTrace.element("java.lang.Thread", "run", "Thread.java", 744)
);
assertEquals(actual, expected);
}
// Thread state and locks might not be consistent with each other.
// Can not assume that, for instance, thread waiting to acquire lock is not runnable
@Test
@Ignore // Dumpling now rejects inconsistent models not to fail later or provide confusing results
public void inconsistentThreadStateAndLockInformation() throws Exception {
ThreadDumpThreadSet threads = runtimeFrom("inconsistent-locks-and-state.log").getThreads();
ThreadDumpThread parking = threads.where(nameIs("runnable-parking-to-wait")).onlyThread();
assertThat(parking.getStatus(), equalTo(ThreadStatus.RUNNABLE));
assertThat(parking.getWaitingToLock(), equalTo(new ThreadLock(
"java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject", 21032260640L
)));
// Based on stacktrace - not thread status
assertThat(parking.toString(), containsString("parking to wait for"));
threads.where(nameIs("blocked-without-monitor")).onlyThread();
}
@Test
public void runnableInObjectWait() throws Exception {
ThreadDumpThread runnable = runtimeFrom("runnable-in-object-wait.log").getThreads().onlyThread();
assertThat(runnable.getStatus(), equalTo(ThreadStatus.RUNNABLE));
assertThat(only(runnable.getAcquiredLocks()), equalTo(new ThreadLock(
"hudson.remoting.UserRequest", 22040315832L
)));
}
@Test
public void ownableSynchronizers() throws Exception {
ThreadDumpRuntime threads = runtimeFrom("ownable-synchronizers.log");
checkOwnableSynchronizers(threads);
checkOwnableSynchronizers(reparse(threads, Mode.MACHINE));
checkOwnableSynchronizers(reparse(threads, Mode.HUMAN));
}
private void checkOwnableSynchronizers(ThreadDumpRuntime runtime) {
ThreadDumpThreadSet threads = runtime.getThreads();
ThreadDumpThread waiting = threads.where(nameIs("blockedThread")).onlyThread();
ThreadDumpThread owning = threads.where(nameIs("main")).onlyThread();
final ThreadLock lock = new ThreadLock("java.util.concurrent.locks.ReentrantLock$NonfairSync", 32296902960L);
final Set<ThreadLock> locks = new HashSet<ThreadLock>(Collections.singletonList(lock));
assertThat(owning.getAcquiredLocks(), equalTo(locks));
assertThat(owning.getWaitingToLock(), equalTo(null));
assertThat(waiting.getStatus(), equalTo(ThreadStatus.PARKED));
assertThat(waiting.getWaitingOnLock(), equalTo(lock));
assertThat(waiting.getWaitingToLock(), nullValue());
assertThat(waiting.getAcquiredLocks(), IsEmptyCollection.<ThreadLock>empty());
}
@Test
public void crlf() throws Exception {
ThreadDumpThreadSet threads = runtimeFrom("crlf.log").getThreads();
assertThat(threads.size(), equalTo(2));
}
@Test
public void parseOutputProducedByJvmRuntimeFactory() {
cleaner.register(new Thread("parseOutputProducedByJvmRuntimeFactory") {
@Override
public void run() {
synchronized (ThreadDumpFactoryTest.this) {
pause(1000);
}
}
}).start();
pause(100);
JvmRuntime current = new JvmRuntimeFactory().currentRuntime();
ThreadDumpThread t = reparse(current, Mode.MACHINE).getThreads().where(
nameIs("parseOutputProducedByJvmRuntimeFactory")
).onlyThread();
assertThat(only(t.getAcquiredLocks()), equalTo(ThreadLock.fromInstance(this)));
t = reparse(current, Mode.HUMAN).getThreads().where(
nameIs("parseOutputProducedByJvmRuntimeFactory")
).onlyThread();
assertThat(only(t.getAcquiredLocks()), equalTo(ThreadLock.fromInstance(this)));
}
// Presumably this is a bug in certain java 6 versions from Oracle
@Test
public void parseThreadInObjectWaitThatDoesNotDeclareDesiredMonitor() throws Exception {
ThreadDumpThreadSet threads = runtimeFrom("in_wait_without_monitor.log").getThreads();
ThreadDumpThread blocked = threads.where(nameIs("blocked_without_lock")).onlyThread();
ThreadDumpThread waiting = threads.where(nameIs("waiting_without_lock")).onlyThread();
ThreadDumpThread timedWaiting = threads.where(nameIs("timed_waiting_without_lock")).onlyThread();
assertThat(blocked.getWaitingToLock(), equalTo(new ThreadLock("hudson.model.Queue", 17233414264L)));
assertThat(waiting.getWaitingToLock(), equalTo(null));
assertThat(timedWaiting.getWaitingToLock(), equalTo(null));
assertThat(blocked.getAcquiredLocks(), Matchers.<ThreadLock>empty());
assertThat(waiting.getAcquiredLocks(), Matchers.<ThreadLock>empty());
assertThat(timedWaiting.getAcquiredLocks(), Matchers.<ThreadLock>empty());
}
// Presumably this is a bug in certain java 6 versions from Oracle
@Test
public void parseBlockedThreadWithoutMonitor() throws Exception {
ThreadDumpThread blocked = runtimeFrom("blocked-without-monitor.log").getThreads().onlyThread();
assertThat(blocked.getAcquiredMonitors(), Matchers.<ThreadLock>empty());
assertThat(blocked.getStatus(), equalTo(ThreadStatus.RUNNABLE));
}
// Presumably this is a bug in certain java 6 versions from Oracle
@Test
public void runnableThreadInUnsafePark() throws Exception {
ThreadDumpThreadSet threads = runtimeFrom("runnable_in_unsafe_park.log").getThreads();
ThreadDumpThread runnable = threads.where(nameIs("runnable")).onlyThread();
assertThat(runnable.getStatus(), equalTo(ThreadStatus.RUNNABLE));
assertThat(runnable.getAcquiredLocks(), Matchers.<ThreadLock>empty());
assertThat(runnable.getWaitingOnLock(), nullValue());
assertThat(runnable.getWaitingToLock(), nullValue());
}
@Test
public void runtimeHeader() throws Exception {
ThreadDumpRuntime runtime = runtimeFrom("crlf.log");
String expected = String.format("%s%n%s%n",
"2014-08-23 15:51:50", "Full thread dump OpenJDK 64-Bit Server VM (24.65-b04 mixed mode):"
);
ByteArrayOutputStream out = new ByteArrayOutputStream();
runtime.toString(new PrintStream(out), Mode.HUMAN);
assertThat(out.toString(), startsWith(expected));
runtime.toString(new PrintStream(out), Mode.MACHINE);
assertThat(out.toString(), startsWith(expected));
}
@Test // HotSpot seems to produce threaddump without blank lines between threads in case of deadlock
public void noBlankLines() throws Exception {
ThreadDumpRuntime runtime = runtimeFrom("no_blank_lines.log");
String expected = String.format("%s%n%s%n",
"2015-05-13 03:27:18", "Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.65-b04 mixed mode):"
);
ByteArrayOutputStream out = new ByteArrayOutputStream();
runtime.toString(new PrintStream(out), Mode.HUMAN);
assertThat(out.toString(), startsWith(expected));
assertThat(runtime.getThreads().size(), equalTo(9));
}
@Test
public void inObjectWait() throws Exception {
ThreadDumpRuntime runtime = runtimeFrom("in-object-wait.log");
ThreadDumpThread blockedWaitingOn = runtime.getThreads().where(nameIs("blockedReacquiringWaitingOn")).onlyThread();
ThreadDumpThread blockedLocked = runtime.getThreads().where(nameIs("blockedReacquiringLocked")).onlyThread();
ThreadLock expected = new ThreadLock("java.lang.Object", 33677620560L);
assertThat(blockedWaitingOn.getStatus(), equalTo(ThreadStatus.BLOCKED));
assertTrue(blockedWaitingOn.getAcquiredLocks().isEmpty());
assertThat(blockedWaitingOn.getWaitingToLock(), equalTo(expected));
assertThat(blockedLocked.getStatus(), equalTo(ThreadStatus.BLOCKED));
assertTrue(blockedLocked.getAcquiredLocks().isEmpty());
assertThat(blockedLocked.getWaitingToLock(), equalTo(expected));
}
@Test // Do not require tab indented stacktraces
public void doNotRequireTabs() throws Exception {
ThreadDumpRuntime runtime = runtimeFrom("no-tabs.log");
ThreadDumpThread thread = runtime.getThreads().where(nameIs("main")).onlyThread();
assertThat(thread.getStackTrace().getElements().size(), equalTo(3));
}
@Test
public void isStreamClosed() throws Exception {
InputStream stream = Util.resource(getClass(), "in-object-wait.log");
InputStream mock = spy(stream);
FACTORY.fromStream(mock);
Mockito.verify(mock).close();
}
@Test
public void fixupHotspotUpdatingThreadStateInNonAtomicWay() throws Exception {
ThreadDumpRuntime runtime = runtimeFrom("issue-46.log");
ThreadDumpThread thread = runtime.getThreads().where(nameIs("Jenkins-cron-thread-8")).onlyThread();
assertTrue(thread.getStatus().isBlocked());
assertEquals(null, thread.getWaitingOnLock());
assertEquals("hudson.model.Queue", thread.getWaitingToLock().getClassName());
assertEquals(0, thread.getAcquiredMonitors().size());
assertEquals(1, thread.getAcquiredSynchronizers().size());
}
@Test
public void hexadecimalThreadIdsMightNotHavePrefix() throws Exception {
ThreadDumpRuntime runtime = runtimeFrom("issue-59.log");
ThreadDumpThread thread = runtime.getThreads().where(nameIs("process reaper")).onlyThread();
assertEquals(140685595015168L, (long) thread.getTid());
assertEquals(5199638528L, (long) thread.getNid());
}
@Test // Observed on OS X with oracle JDK6. Fixed in later versions.
public void lockIdsMightNotHavePrefix() throws Exception {
ThreadDumpThread thread = runtimeFrom("unprefixed-synchronizers.log").getThreads().onlyThread();
Set<ThreadLock> locks = thread.getAcquiredSynchronizers();
assertThat(locks, Matchers.<ThreadLock>iterableWithSize(1));
assertThat(locks.iterator().next().getId(), equalTo(34151939696L));
}
@Test
public void failToParseWhatIsNotAThreaddump() throws IOException, URISyntaxException {
try {
runtimeFrom("unknown-chunks.log");
fail();
} catch (IllegalRuntimeStateException e) {
assertThat(e.getMessage(), startsWith("Skipping unrecognized chunk: "));
}
try {
runtimeFrom("no-threads.log");
fail();
} catch (IllegalRuntimeStateException e) {
assertThat(e.getMessage(), startsWith("No threads found in threaddump"));
}
try {
runtimeFrom("broken-synchronizers.log");
fail();
} catch (IllegalRuntimeStateException e) {
assertThat(e.getMessage(), startsWith("Unable to parse ownable synchronizer: "));
}
// Should work if we ignore failures
new ThreadDumpFactory().fromStream(Util.resource(getClass(), "unknown-chunks.log"));
}
@Test
public void numberInUpperLongRange() throws Exception {
ThreadDumpRuntime runtime = runtimeFrom("issue-71.log");
ThreadDumpThread sut = runtime.getThreads().where(nameIs("SUT")).onlyThread();
assertEquals(-494445558, (long) sut.getTid());
assertEquals(-494445557, sut.getWaitingToLock().getId());
assertEquals(-494445556, only(sut.getAcquiredSynchronizers()).getId());
assertEquals(-494445555, (long) sut.getNid());
// Decadic NID
String human = new JvmThread.Builder(Thread.currentThread()).setName("Fake").setId(42).setTid(42).setNid(Short.MIN_VALUE).toString();
assertThat(human, containsString("nid=-32768"));
sut = FACTORY.fromString(human).getThreads().where(nameIs("Fake")).onlyThread();
assertEquals(Short.MIN_VALUE, (long) sut.getNid());
}
@Test
public void parseLong() throws Exception {
String top = "0xffffffffffffffff";
assertEquals(Long.toHexString(ThreadDumpFactory.parseLong(top)), -1, ThreadDumpFactory.parseLong(top));
top = "0xfffffffffffffffe";
assertEquals(Long.toHexString(ThreadDumpFactory.parseLong(top)), -2, ThreadDumpFactory.parseLong(top));
top = "0x00000000000000f";
assertEquals(Long.toHexString(ThreadDumpFactory.parseLong(top)), 15, ThreadDumpFactory.parseLong(top));
top = "0xf0000000000000";
assertEquals(Long.toHexString(ThreadDumpFactory.parseLong(top)), 67553994410557440L, ThreadDumpFactory.parseLong(top));
top = "0xe0000000000000";
assertEquals(Long.toHexString(ThreadDumpFactory.parseLong(top)), 63050394783186944L, ThreadDumpFactory.parseLong(top));
top = "0x7fffffffffffffff";
assertEquals(Long.toHexString(ThreadDumpFactory.parseLong(top)), 9223372036854775807L, ThreadDumpFactory.parseLong(top));
top = "0x8000000000000000";
assertEquals(Long.toHexString(ThreadDumpFactory.parseLong(top)), -9223372036854775808L, ThreadDumpFactory.parseLong(top));
top = "ffffffffe2875c0a";
assertEquals(Long.toHexString(ThreadDumpFactory.parseLong(top)), -494445558, ThreadDumpFactory.parseLong(top));
}
private ThreadDumpRuntime runtimeFrom(String resource) throws IOException, URISyntaxException {
return FACTORY.fromStream(Util.resource(getClass(), resource));
}
private ThreadDumpRuntime runtime(ThreadDumpThread.Builder... builders) {
return new ThreadDumpRuntime(
new LinkedHashSet<ThreadDumpThread.Builder>(Arrays.asList(builders)),
Collections.singletonList("Expected threaddump")
);
}
private static volatile int syntheticId = 42;
private ThreadDumpThread.Builder thread(@Nonnull String name) {
return new ThreadDumpThread.Builder().setName(name)
// Preset unique id for purposes of the test as we can not rely
// that SUT will correctly initialize IDs. Threads with the
// same Ids will otherwise be collapsed into one by java.util.Set.
// Correct factory implementation will always overwrite this.
.setTid(syntheticId++)
;
}
private ThreadDumpThread.Builder daemon(@Nonnull String name) {
return thread(name).setDaemon(true);
}
private ThreadLock lock(@Nonnull String classname, long address) {
return new ThreadLock(classname, address);
}
private TypeSafeMatcher<ThreadDumpRuntime> stacktraceEquals(final StackTrace expected, final @Nonnull String threadName) {
return new TypeSafeMatcher<ThreadDumpRuntime>() {
// The first StackTrace variant that failed
private StackTrace failed;
@Override
public void describeTo(Description description) {
description.appendText("Runtime with same threads");
}
@Override
protected boolean matchesSafely(ThreadDumpRuntime actual) {
if (!doesMatch(expected, failed = trace(actual, threadName))) return false;
if (!doesMatch(expected, failed = trace(reparse(actual, Mode.MACHINE), threadName))) return false;
if (!doesMatch(expected, failed = trace(reparse(actual, Mode.HUMAN), threadName))) return false;
return true;
}
@Override
protected void describeMismatchSafely(ThreadDumpRuntime actual, Description mismatch) {
doDescribe(expected, failed, mismatch);
}
private boolean doesMatch(StackTrace expected, StackTrace actual) {
return expected.equals(actual);
}
private void doDescribe(StackTrace expected, StackTrace actual, Description mismatch) {
int length = expected.size();
if (actual.size() != length) mismatch.appendText(String.format(
"Stack depth differes, %d != %d", length, actual.size()
));
for (int i = 0; i < length; i++) {
StackTraceElement exp = expected.getElement(i);
StackTraceElement act = actual.getElement(i);
if (!exp.equals(act)) {
mismatch.appendText(String.format("%s != %s", exp, act));
return;
}
}
}
private StackTrace trace(ThreadDumpRuntime runtime, @Nonnull String threadName) {
return runtime.getThreads().where(nameIs(threadName)).onlyThread().getStackTrace();
}
};
}
private TypeSafeMatcher<ThreadDumpRuntime> sameThreadsAs(final ThreadDumpRuntime expectedRuntime) {
return new TypeSafeMatcher<ThreadDumpRuntime>() {
// The first threaddump variant that failed
private ThreadDumpRuntime failed;
@Override
public void describeTo(Description description) {
description.appendText("Runtime with same threads");
}
@Override
protected boolean matchesSafely(ThreadDumpRuntime actual) {
if (!doesMatch(expectedRuntime, failed = actual)) return false;
if (!doesMatch(expectedRuntime, failed = reparse(actual, Mode.MACHINE))) return false;
if (!doesMatch(expectedRuntime, failed = reparse(actual, Mode.HUMAN))) return false;
failed = null;
return true;
}
private boolean doesMatch(ThreadDumpRuntime expectedRuntime, ThreadDumpRuntime actual) {
if (expectedRuntime.getThreads().size() != actual.getThreads().size()) return false;
for (ThreadDumpThread actualThread: actual.getThreads()) {
final ThreadDumpThreadSet matching = expectedRuntime.getThreads().where(nameIs(actualThread.getName()));
if (matching.size() != 1) return false;
ThreadDumpThread expectedThread = matching.onlyThread();
if (difference(expectedThread, actualThread) != null) return false;
}
return true;
}
@Override
protected void describeMismatchSafely(ThreadDumpRuntime actualRuntime, Description mismatch) {
doDescribe(expectedRuntime, failed, mismatch);
}
private void doDescribe(
ThreadDumpRuntime expectedRuntime, ThreadDumpRuntime actualRuntime, Description mismatch
) throws AssertionError {
final ThreadDumpThreadSet expectedThreads = expectedRuntime.getThreads();
final ThreadDumpThreadSet actualThreads = actualRuntime.getThreads();
for (ThreadDumpThread actual: actualThreads) {
final ThreadDumpThreadSet named = expectedThreads.where(nameIs(actual.getName()));
if (named.size() > 1) throw new AssertionError("Several threads named: " + actual.getName());
if (named.size() == 0) {
mismatch.appendText("Unexpected Thread:\n").appendText(actual.toString());
return;
}
ThreadDumpThread expected = named.onlyThread();
String difference = difference(expected, actual);
if (difference == null) continue; // Equal
mismatch.appendText(expected.toString())
.appendText("\nDiffers in: ").appendText(difference).appendText("\n")
.appendText(actual.toString())
;
return;
}
if (expectedThreads.size() == actualThreads.size()) return;
ThreadDumpThreadSet missing = expectedThreads.ignoring(actualThreads);
mismatch.appendText("Missing Threads:\n").appendText(missing.toString());
}
};
}
private ThreadDumpRuntime reparse(ProcessRuntime<?, ?, ?> actual) {
return reparse(actual, Mode.MACHINE);
}
private ThreadDumpRuntime reparse(ProcessRuntime<?, ?, ?> actual, Mode mode) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
actual.getThreads().toString(new PrintStream(baos), mode);
ByteArrayInputStream stream = new ByteArrayInputStream(baos.toByteArray());
return FACTORY.fromStream(stream);
}
// Deep equality for test purposes
private String difference(ThreadDumpThread lhs, ThreadDumpThread rhs) {
if (!equals(lhs.getId(), rhs.getId())) return "id";
if (!equals(lhs.getTid(), rhs.getTid())) return "tid";
if (!equals(lhs.getNid(), rhs.getNid())) return "nid";
if (!equals(lhs.getName(), rhs.getName())) return "name";
if (lhs.getPriority() != rhs.getPriority()) return "priority";
if (lhs.isDaemon() != rhs.isDaemon()) return "daemon";
if (!equals(lhs.getStatus(), rhs.getStatus())) return "thread status";
if (!equals(lhs.getWaitingToLock(), rhs.getWaitingToLock())) return String.format(
"waiting to lock (%s!=%s)", lhs.getWaitingToLock(), rhs.getWaitingToLock()
);
if (!equals(lhs.getWaitingOnLock(), rhs.getWaitingOnLock())) return String.format(
"waiting on lock (%s!=%s)", lhs.getWaitingOnLock(), rhs.getWaitingOnLock()
);
if (!lhs.getAcquiredLocks().equals(rhs.getAcquiredLocks())) return "acquired locks";
// if (!Arrays.equals(lhs.getStackTrace(), rhs.getStackTrace())) return "stack trace";
return null;
}
private boolean equals(Object lhs, Object rhs) {
if (lhs == null) return rhs == null;
return lhs.equals(rhs);
}
}