4 Replies Latest reply on Jan 4, 2007 5:24 AM by Kabir Khan

    Update AOPTestDelegate to better integrate into eclipse

    Scott Stark Master

      Currently you cannot run the tests easily from within eclise using the run as junit... capability because the test harness does not locate the jboss-aop.xml based on the classpath. Something like this does this:

      package org.jboss.test.aop;
      
      import java.net.URL;
      import java.util.Properties;
      
      import org.jboss.aop.AspectXmlLoader;
      import org.jboss.test.AbstractTestDelegate;
      
      /**
       *
       * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
       * @version $Revision: 45977 $
       */
      public class AOPTestDelegate extends AbstractTestDelegate
      {
       /** The AOP URL used */
       private URL aopURL;
      
       Properties systemProps;
      
       public AOPTestDelegate(Class clazz)
       {
       // FIXME AOPTestDelegate constructor
       super(clazz);
       systemProps = (Properties)System.getProperties().clone();
       }
      
       public Properties getSystemProperties()
       {
       return systemProps;
       }
      
       /**
       * Look for a test specific aop descriptor based on the ctor
       * class first, and if none is found, the ManagedTest.class.
       */
       public void setUp() throws Exception
       {
       super.setUp();
       deployAOP(clazz);
       }
      
       /**
       * Undeployment any test specific aop descriptor deployed in setUp.
       */
       public void tearDown() throws Exception
       {
       super.tearDown();
       undeployAOP();
       }
      
       /**
       * Look for a test specific resource name by appending "-aop.xml"
       * to the referenceClass name as a resource. For example, a.b.SomeTest
       * would produce a a/b/SomeTest-aop.xml resource that is queried
       * for using clazz.getClassLoader().getResource("a/b/SomeTest-aop.xml");
       *
       * @param referenceClass - the class to use as the aop descriptor base name.
       * @return true if the aop descriptor was found and deployed,
       * false otherwise.
       * @throws Exception on failure to deploy the aop descriptor.
       */
       protected boolean deployAOP(Class referenceClass) throws Exception
       {
       String testName = referenceClass.getName();
       String pkg = referenceClass.getPackage().getName();
       int dot = pkg.lastIndexOf('.');
       if( dot > 0 )
       pkg = pkg.substring(dot+1);
       testName = pkg + "/jboss-aop.xml";
       URL url = clazz.getClassLoader().getResource(testName);
       if (url != null)
       {
       log.debug("Deploying " + url);
       aopURL = url;
       try
       {
       AspectXmlLoader.deployXML(aopURL);
       }
       catch (Throwable t)
       {
       throw new RuntimeException("Error deploying: " + url, t);
       }
       return true;
       }
       else
       {
       log.debug("No test specific deployment " + testName);
       return false;
       }
       }
      
       /**
       * Undeploy the aop descriptor deployed in deployAOP if
       * one was found.
       *
       */
       protected void undeployAOP()
       {
       if (aopURL == null)
       return;
       try
       {
       log.debug("Undeploying " + aopURL);
       AspectXmlLoader.undeployXML(aopURL);
       }
       catch (Exception e)
       {
       log.warn("Ignored error undeploying " + aopURL, e);
       }
       }
      
      }
      


      Although this does deploy the aspects, the test I tried this with (org.jboss.test.aop.precedence.PrecedenceTester) is still failing. Can you look into getting this working Kabir?


        • 1. Re: Update AOPTestDelegate to better integrate into eclipse
          Kabir Khan Master

          To set up for debug, you need to
          1) set the jboss.aop.path system property to point to the jboss-aop.xml file
          2) set -javaagent:%OUTPUT_LIB_FOLDER%\jboss-aop-jdk50.jar

          While the requirement for 1) could be optimized out by the mechanism you describe, it means rewriting all the tests since things like field, constructor and array interception need weaving of the testcase class, which in turn depends on the aop.xml file being deployed before the testcase class is loaded.

          • 2. Re: Update AOPTestDelegate to better integrate into eclipse
            Scott Stark Master

            Its not clear why the aop processing cannot be done before the test classes are loaded by expanding the AOPTestWithSetup/AOPTestDelegate. It should just require an aop aware class loader be installed at the proper level in the test harness. I assume this is what the javaagent is doing.

            • 3. Re: Update AOPTestDelegate to better integrate into eclipse
              Kabir Khan Master

              The initialization of the AOPSetup/TestDelegate results from the testcase setUp() method. Once that is called the class has already been loaded:

              Thread [main] (Suspended (breakpoint at line 39 in AOPTestDelegate))
               AOPTestDelegate.<init>(Class) line: 39
               AOPTestWithSetup.getDelegate(Class) line: 51
               NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
               NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
               DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
               Method.invoke(Object, Object...) line: 585
               AbstractTestDelegate.getDelegate(Class) line: 70
               AbstractTestSetup.setUp() line: 62
               AOPArrayTestCase(AbstractTestCaseWithSetup).setUp() line: 90
               AOPArrayTestCase(TestCase).runBare() line: 125
               TestResult$1.protect() line: 106
               TestResult.runProtected(Test, Protectable) line: 124
               TestResult.run(TestCase) line: 109
               AOPArrayTestCase(TestCase).run(TestResult) line: 118
               TestSuite.runTest(Test, TestResult) line: 208
               TestSuite.run(TestResult) line: 203
               TestSuite.runTest(Test, TestResult) line: 208
               TestSuite.run(TestResult) line: 203
               JUnit3TestReference.run(TestExecution) line: 128
               TestExecution.run(ITestReference[]) line: 38
               RemoteTestRunner.runTests(String[], String, TestExecution) line: 460
               RemoteTestRunner.runTests(TestExecution) line: 673
               RemoteTestRunner.run() line: 386
               RemoteTestRunner.main(String[]) line: 196
              


              The classloader uses whatever -aop.xml info has been deployed in AOP to determine if the class should be woven, in other words having this deployed by the Setup/Delegate is too late.

              2 possible solutions:
              1) Refactor all existing xxxTestCase classes to xxxTestCaseDelegate and create new xxxTestCase classes delegating to the xxxTestCaseDelegate

              2) Create a new javaagent that delegates to the exisiting transformer. This transformer should be able to leverage the existing transformer for it's work and deploy use the info about the testcase to

              1) is a pain, and 2) while conceptually straight-forward is complicated by the fact that there doesn't seem to be a way to tell which test is being run.

              One option though could be to have my classloader dig into the junit stack, and weave the org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main() method so this information is available in a system property somewhere. Eclipse seems to load that class for each test run.