diff --git a/pom.xml b/pom.xml index 293d6fe..f99b583 100644 --- a/pom.xml +++ b/pom.xml @@ -46,6 +46,7 @@ **/TransformerTest.java + **/AgentMainTest.java -javaagent:"${project.build.directory}/file-leak-detector-${project.version}-jar-with-dependencies.jar" @@ -60,9 +61,8 @@ - - **/TransformerTest.java - + **/TransformerTest.java + **/AgentMainTest.java **/instrumented/*.java @@ -142,6 +142,12 @@ 4.13.1 test + + org.mockito + mockito-core + 3.2.4 + test + diff --git a/src/test/java/org/kohsuke/file_leak_detector/AgentMainTest.java b/src/test/java/org/kohsuke/file_leak_detector/AgentMainTest.java new file mode 100644 index 0000000..cdaf1a3 --- /dev/null +++ b/src/test/java/org/kohsuke/file_leak_detector/AgentMainTest.java @@ -0,0 +1,74 @@ +package org.kohsuke.file_leak_detector; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.Instrumentation; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.junit.Test; +import org.kohsuke.file_leak_detector.transform.ClassTransformSpec; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +public class AgentMainTest { + @Test + public void noDuplicateSpecs() { + final List specs = AgentMain.createSpec(); + + Set seenClasses = new HashSet<>(); + for (ClassTransformSpec spec : specs) { + assertTrue("Did have duplicate spec for class " + spec.name, seenClasses.add(spec.name)); + } + } + + @Test + public void testPreMain() throws Exception { + final List specs = AgentMain.createSpec(); + + final Set seenClasses = new HashSet<>(); + for (ClassTransformSpec spec : specs) { + seenClasses.add(spec.name); + } + + Instrumentation instrumentation = mock(Instrumentation.class); + Mockito.doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocationOnMock) throws Throwable { + for (Object obj : invocationOnMock.getArguments()) { + Class clazz = (Class) obj; + String name = clazz.getName().replace(".", "/"); + assertTrue( + "Tried to transform a class wihch is not contained in the specs: " + + name + + " (" + + clazz + + "), having remaining classes: " + + seenClasses, + seenClasses.remove(name)); + } + return null; + } + }).when(instrumentation).retransformClasses((Class) any()); + + AgentMain.premain(null, instrumentation); + + verify(instrumentation, times(1)).addTransformer((ClassFileTransformer) any(), anyBoolean()); + verify(instrumentation, times(1)).retransformClasses((Class) any()); + + // the following are not available in all JVMs + seenClasses.remove("sun/nio/ch/SocketChannelImpl"); + seenClasses.remove("java/net/AbstractPlainSocketImpl"); + + assertTrue( + "Had classes in the spec which were not instrumented: " + seenClasses, + seenClasses.isEmpty()); + } +}