/* * JCarder -- cards Java programs to keep threads disentangled * * Copyright (C) 2006-2007 Enea AB * Copyright (C) 2007 Ulrik Svensson * Copyright (C) 2007 Joel Rosdahl * * This program is made available under the GNU GPL version 2, with a special * exception for linking with JUnit. See the accompanying file LICENSE.txt for * details. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. */ package com.enea.jcarder.agent.instrument; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import java.io.File; import java.util.ArrayList; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.enea.jcarder.agent.EventListenerIfc; import com.enea.jcarder.agent.StaticEventListener; import com.enea.jcarder.common.LockingContext; import com.enea.jcarder.testclasses.instrumentation.SynchronizationTestIfc; import com.enea.jcarder.testclasses.instrumentation.SynchronizedArray; import com.enea.jcarder.testclasses.instrumentation.SynchronizedClass; import com.enea.jcarder.testclasses.instrumentation.SynchronizedExpression; import com.enea.jcarder.testclasses.instrumentation.SynchronizedField; import com.enea.jcarder.testclasses.instrumentation.SynchronizedFromLocalVariable; import com.enea.jcarder.testclasses.instrumentation.SynchronizedFromMethod; import com.enea.jcarder.testclasses.instrumentation.SynchronizedFromPrivateMethod; import com.enea.jcarder.testclasses.instrumentation.SynchronizedFromStaticMethod; import com.enea.jcarder.testclasses.instrumentation.SynchronizedInBlock; import com.enea.jcarder.testclasses.instrumentation.SynchronizedInStaticBlock; import com.enea.jcarder.testclasses.instrumentation.SynchronizedMethod; import com.enea.jcarder.testclasses.instrumentation.SynchronizedMethodWithDoubleReturn; import com.enea.jcarder.testclasses.instrumentation.SynchronizedMethodWithException; import com.enea.jcarder.testclasses.instrumentation.SynchronizedMethodWithLongReturn; import com.enea.jcarder.testclasses.instrumentation.SynchronizedMethodWithMultipleFloatReturns; import com.enea.jcarder.testclasses.instrumentation.SynchronizedMethodWithObjectReturn; import com.enea.jcarder.testclasses.instrumentation.SynchronizedNewObject; import com.enea.jcarder.testclasses.instrumentation.SynchronizedNull; import com.enea.jcarder.testclasses.instrumentation.SynchronizedStaticField; import com.enea.jcarder.testclasses.instrumentation.SynchronizedStaticMethod; import com.enea.jcarder.testclasses.instrumentation.SynchronizedStaticMethodWithException; import com.enea.jcarder.testclasses.instrumentation.SynchronizedStaticMethodWithMultipleIntReturns; import com.enea.jcarder.testclasses.instrumentation.SynchronizedThis; import com.enea.jcarder.util.logging.Logger; /* * The purpose of this junit class is to test the classes: * - MonitorClassAdapter * - MonitorMethodAdapter * - StackAnalyzeMethodVisitor * * TODO StackAnalyzeMethodVisitor is not fully tested by this junit class. */ public final class TestDeadLockInstrumentation implements EventListenerIfc { private final ArrayList<MonitorWithContext> mEnteredMonitors; private final TransformClassLoader mClassLoader; public TestDeadLockInstrumentation() { ClassTransformer classTransformer = new ClassTransformer(new Logger(null), new File("."), new InstrumentConfig()); mClassLoader = new TransformClassLoader(classTransformer); StaticEventListener.setListener(this); mEnteredMonitors = new ArrayList<MonitorWithContext>(); } private SynchronizationTestIfc transformAsSynchronizationTest(Class clazz) throws Exception { Class c = mClassLoader.transform(clazz); return (SynchronizationTestIfc) c.newInstance(); } private void testClass(Class clazz) throws Exception { SynchronizationTestIfc test = transformAsSynchronizationTest(clazz); test.go(); assertEquals(test.getExpectedMonitorEnterings(), mEnteredMonitors.toArray()); } public void beforeMonitorEnter(Object monitor, LockingContext context) { // onMonitorEnter shall be invoked BEFORE the look is taken // in order to be able to generate the event even if the // lock can never be taken and the thread is blocked forever. // Otherwise we would only be able to generate lock graphs // for possible deadlocks and not for deadlocks that acctually // occured. if (monitor != null) { assertFalse(Thread.holdsLock(monitor)); mEnteredMonitors.add(new MonitorWithContext(monitor, context)); } } @Before public void setUp() throws Exception { mEnteredMonitors.clear(); } @After public void tearDown() throws Exception { } @Test public void testSynchronizedField() throws Exception { testClass(SynchronizedField.class); } @Test public void testSynchronizedArray() throws Exception { testClass(SynchronizedArray.class); } @Test public void testSynchronizedClass() throws Exception { testClass(SynchronizedClass.class); } @Test public void testSynchronizedExpression() throws Exception { testClass(SynchronizedExpression.class); } @Test public void testSynchronizedFromLocalVariable() throws Exception { testClass(SynchronizedFromLocalVariable.class); } @Test public void testSynchronizedFromMethod() throws Exception { testClass(SynchronizedFromMethod.class); } @Test public void testSynchronizedFromPrivateMethod() throws Exception { testClass(SynchronizedFromPrivateMethod.class); } @Test public void testSynchronizedFromStaticMethod() throws Exception { testClass(SynchronizedFromStaticMethod.class); } @Test public void testSynchronizedMethod() throws Exception { testClass(SynchronizedMethod.class); } @Test public void testSynchronizedNull() throws Exception { testClass(SynchronizedNull.class); } @Test public void testSynchronizedStaticField() throws Exception { testClass(SynchronizedStaticField.class); } @Test public void testSynchronizedStaticMethod() throws Exception { testClass(SynchronizedStaticMethod.class); } @Test public void testSynchronizedThis() throws Exception { testClass(SynchronizedThis.class); } @Test public void testSynchronizedInStaticBlock() throws Exception { testClass(SynchronizedInStaticBlock.class); } @Test public void testSynchronizedInBlock() throws Exception { testClass(SynchronizedInBlock.class); } @Test public void testSynchronizedStaticMethodWithMultipleIntReturns() throws Exception { testClass(SynchronizedStaticMethodWithMultipleIntReturns.class); } @Test public void testSynchronizedMethodWithMultipleFloatReturns() throws Exception { testClass(SynchronizedMethodWithMultipleFloatReturns.class); } @Test public void testSynchronizedMethodWithDoubleReturn() throws Exception { testClass(SynchronizedMethodWithDoubleReturn.class); } @Test public void testSynchronizedMethodWithLongReturn() throws Exception { testClass(SynchronizedMethodWithLongReturn.class); } @Test public void testSynchronizedMethodWithObjectReturn() throws Exception { testClass(SynchronizedMethodWithObjectReturn.class); } @Test public void testSynchronizedStaticMethodWithException() throws Exception { testClass(SynchronizedStaticMethodWithException.class); } @Test public void testSynchronizedMethodWithException() throws Exception { testClass(SynchronizedMethodWithException.class); } @Test public void testSynchronizedNewObject() throws Exception { SynchronizationTestIfc test = transformAsSynchronizationTest(SynchronizedNewObject.class); test.go(); assertEquals(1, mEnteredMonitors.size()); MonitorWithContext acctual = mEnteredMonitors.get(0); MonitorWithContext expected = test.getExpectedMonitorEnterings()[0]; assertEquals(expected.getContext(), acctual.getContext()); } public void accessField(Object owner, int fieldId, boolean isVolatile, boolean writeAccess) { // TODO Auto-generated method stub } public void accessStaticField(Class owner, int fieldId, boolean isVolatile, boolean writeAccess) { // TODO Auto-generated method stub } public void afterMonitorEnter(Object monitor, boolean foo) { // TODO Auto-generated method stub } public void beforeMonitorExit(Object monitor, boolean foo) { // TODO Auto-generated method stub } public void classInitialized(Class clazz) { // TODO Auto-generated method stub } // TODO Add test case for instrumenting a non-anonymous inner class. // TODO Add test case for instrumenting a non-anonymous static inner class. // TODO Add test case for instrumenting an anonymous inner class // TODO Add test case for instrumenting an anonymous method. // TODO Add test case for instrumenting a class file version < 49 // (before Java 1.5) with a static synchronized method. // TODO Add test case for instrumenting a synchronized block in // constructor. // TODO Add test case for what's happening with native methods. }