]> source.dussan.org Git - aspectj.git/commitdiff
Add test reproducing problem from #198
authorAlexander Kriegisch <Alexander@Kriegisch.name>
Thu, 29 Dec 2022 14:17:53 +0000 (15:17 +0100)
committerAlexander Kriegisch <Alexander@Kriegisch.name>
Wed, 4 Jan 2023 14:22:03 +0000 (15:22 +0100)
Signed-off-by: Alexander Kriegisch <Alexander@Kriegisch.name>
tests/features164/declareMixin/CaseEConcurrent.java [new file with mode: 0644]
tests/src/test/java/org/aspectj/systemtest/ajc164/DeclareMixinTests.java
tests/src/test/resources/org/aspectj/systemtest/ajc164/declareMixin.xml

diff --git a/tests/features164/declareMixin/CaseEConcurrent.java b/tests/features164/declareMixin/CaseEConcurrent.java
new file mode 100644 (file)
index 0000000..df1e137
--- /dev/null
@@ -0,0 +1,84 @@
+// TESTING: multiple instances causing factory invocation multiple times (but is cached correctly)
+// Concurrency fix regression test for https://github.com/eclipse/org.aspectj/issues/198
+import org.aspectj.lang.annotation.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class CaseEConcurrent {
+  private String id;
+
+  public static void main(String[]argv) throws InterruptedException {
+    final CaseEConcurrent cea = new CaseEConcurrent("a");
+    final CaseEConcurrent ceb = new CaseEConcurrent("b");
+
+    Thread t1 = new Thread(new Runnable() { public void run() { ((I)cea).methodOne(); } });
+    Thread t2 = new Thread(new Runnable() { public void run() { ((I)cea).methodTwo(); } });
+    Thread t3 = new Thread(new Runnable() { public void run() { ((I)ceb).methodOne(); } });
+    Thread t4 = new Thread(new Runnable() { public void run() { ((I)ceb).methodTwo(); } });
+
+    t1.start();
+    t2.start();
+    t3.start();
+    t4.start();
+
+    t1.join();
+    t2.join();
+    t3.join();
+    t4.join();
+  }
+
+  public CaseEConcurrent(String id) {
+    this.id=id;
+  }
+
+  public String toString() {
+    return "CaseEConcurrent instance: "+id;
+  }
+
+  // Helper methods 'doSomething' and 'callMe' help to produce byte code similar to what we need in order to fix
+  // https://github.com/eclipse/org.aspectj/issues/198. If necessary, just temporarily uncomment, compile and analyse
+  // the byte code, e.g. with JDK tool 'javap -v'.
+  /*
+  public void doSomething() {
+    synchronized (this) {
+      if (id == null)
+        id = "doing something";
+    }
+    callMe(id);
+  }
+
+  public void callMe(String param) {
+    System.out.println("I was called with param " + param);
+  }
+  */
+
+}
+
+aspect X {
+  @DeclareMixin("CaseEConcurrent")
+  public I createImplementation(Object o) {
+    System.out.println("Delegate factory invoked for " + o);
+    try { Thread.sleep(250); } catch (InterruptedException e) { throw new RuntimeException(e); }
+    Implementation impl = new Implementation(o);
+    return impl;
+  }
+}
+
+interface I {
+  void methodOne();
+  void methodTwo();
+}
+
+class Implementation implements I {
+  Object o;
+
+  public Implementation(Object o) {
+    this.o = o;
+  }
+
+  public void methodOne() {
+    System.out.println("methodOne running on "+o);
+  }
+  public void methodTwo() {
+    System.out.println("methodTwo running on "+o);
+  }
+}
index 1f5c135e361043dcabe51a363e0a493bb69ac3b4..1c312d18b91ffc7c0fa7e71dc98f2498ff3bd2b2 100644 (file)
@@ -67,6 +67,12 @@ public class DeclareMixinTests extends org.aspectj.testing.XMLBasedAjcTestCase {
                runTest("casee");
        }
 
+       // multiple instances causing factory invocation multiple times (but is cached), concurrent case
+       // see https://github.com/eclipse/org.aspectj/issues/198
+       public void testCaseEConcurrent() {
+               runTest("casee_concurrent");
+       }
+
        // Factory method directly takes the type specified in the Mixin target (strongly typed)
        public void testCaseF() {
                runTest("casef");
index 02853f93a667571de6a4b426cd828cd22a8154bd..c397fae87fe11d1687d8969d2bfca81f5a578440 100644 (file)
@@ -1,7 +1,7 @@
 <!DOCTYPE suite SYSTEM "../tests/ajcTestSuite.dtd"[]>
 
 <suite>
-   
+
    <ajc-test dir="features164/declareMixin" title="casea">
      <compile files="CaseA.java" options="-1.5"/>
      <run class="CaseA">
@@ -11,7 +11,7 @@
        </stdout>
      </run>
    </ajc-test>
-   
+
    <ajc-test dir="features164/declareMixin" title="caseb">
      <compile files="CaseB.java" options="-1.5"/>
      <run class="CaseB">
@@ -21,7 +21,7 @@
        </stdout>
      </run>
    </ajc-test>
-   
+
    <ajc-test dir="features164/declareMixin" title="casec">
      <compile files="CaseC.java" options="-1.5"/>
      <run class="CaseC">
@@ -31,7 +31,7 @@
        </stdout>
      </run>
    </ajc-test>
-   
+
    <ajc-test dir="features164/declareMixin" title="cased">
      <compile files="CaseD.java" options="-1.5"/>
      <run class="CaseD">
@@ -41,7 +41,7 @@
        </stdout>
      </run>
    </ajc-test>
-   
+
    <ajc-test dir="features164/declareMixin" title="casee">
      <compile files="CaseE.java" options="-1.5"/>
      <run class="CaseE">
        </stdout>
      </run>
    </ajc-test>
-   
+
+   <ajc-test dir="features164/declareMixin" title="casee_concurrent">
+     <compile files="CaseEConcurrent.java" options="-1.5"/>
+     <run class="CaseEConcurrent">
+       <stdout ordered="no">
+         <!--
+           Without the concurrency fix from https://github.com/eclipse/org.aspectj/issues/198, each delegate factory
+           would be invoked twice
+         -->
+         <line text="Delegate factory invoked for CaseEConcurrent instance: a"/>
+         <line text="Delegate factory invoked for CaseEConcurrent instance: b"/>
+         <line text="methodOne running on CaseEConcurrent instance: a"/>
+         <line text="methodTwo running on CaseEConcurrent instance: a"/>
+         <line text="methodOne running on CaseEConcurrent instance: b"/>
+         <line text="methodTwo running on CaseEConcurrent instance: b"/>
+       </stdout>
+     </run>
+   </ajc-test>
+
    <ajc-test dir="features164/declareMixin" title="casef">
      <compile files="CaseF.java" options="-1.5"/>
      <run class="CaseF">
@@ -65,7 +83,7 @@
        </stdout>
      </run>
    </ajc-test>
-   
+
    <ajc-test dir="features164/declareMixin" title="caseg">
      <compile files="CaseG.java" options="-1.5"/>
      <run class="CaseG">
        </stdout>
      </run>
    </ajc-test>
-   
+
    <ajc-test dir="features164/declareMixin" title="caseh">
      <compile files="CaseH.java" options="-1.5">
          <message kind="error" text="The value for annotation attribute DeclareMixin"/>
      </compile>
    </ajc-test>
-   
+
    <ajc-test dir="features164/declareMixin" title="casei">
      <compile files="CaseI.java" options="-1.5">
          <message kind="error" text="Types listed in the 'interfaces'"/>
      </compile>
    </ajc-test>
-   
+
    <ajc-test dir="features164/declareMixin" title="casej">
      <compile files="CaseJ.java" options="-1.5">
          <message kind="error" text="createImplementation1"/>
          <message kind="error" text="Method 'int X.createImplementation2(java.lang.Object)':  factory methods "/>
      </compile>
    </ajc-test>
-   
+
    <ajc-test dir="features164/declareMixin" title="casek">
      <compile files="CaseK.java" options="-1.5">
          <message kind="error" text="factory methods for a mixin can take a maximum of one parameter"/>
      </compile>
    </ajc-test>
-   
+
    <ajc-test dir="features164/declareMixin" title="casel">
      <compile files="CaseL.java" options="-1.5">
        <message kind="error" text="Cannot cast from CaseL to C"/>
      </compile>
    </ajc-test>
-   
+
    <ajc-test dir="features164/declareMixin" title="casem">
      <compile files="CaseM.java" options="-1.5">
        <message kind="error" text=": factory methods for a mixin must either return an interface type or specify interfaces in the annotation and return a class"/>
      </compile>
    </ajc-test>
-   
+
    <ajc-test dir="features164/declareMixin" title="casen">
      <compile files="CaseN.java" options="-1.5"/>
      <run class="CaseN">
        </stdout>
      </run>
    </ajc-test>
-   
+
    <ajc-test dir="features164/declareMixin" title="caseo">
      <compile files="CaseO.java" options="-1.5">
        <message kind="error" text="factory method does not return something that implements 'I'"/>
      </compile>
    </ajc-test>
-   
+
    <ajc-test dir="features164/declareMixin" title="casep">
      <compile files="CaseP.java" options="-1.5"/>
      <run class="CaseP">
        </stdout>
      </run>
    </ajc-test>
-   
+
    <ajc-test dir="features164/declareMixin" title="caseq">
      <compile files="CaseQ.java" options="-1.5"/>
      <run class="CaseQ">
          <line text="goo() running"/>
        </stdout>
      </run>
-   </ajc-test>   
-     
+   </ajc-test>
+
    <ajc-test dir="features164/declareMixin" title="caser">
      <compile files="CaseR.java" options="-1.5"/>
      <run class="CaseR">
          <line text="false"/>
        </stdout>
      </run>
-   </ajc-test>    
-    
+   </ajc-test>
+
    <ajc-test dir="features164/declareMixin" title="cases">
      <compile files="CaseS.java" options="-1.5">
        <message kind="error" text="not compatible"/>
      </compile>
-   </ajc-test>     
-   
+   </ajc-test>
+
    <ajc-test dir="features164/declareMixin" title="caset">
      <compile files="CaseT.java" options="-1.5 -showWeaveInfo">
        <message kind="weave" text="Mixing interface 'I' (CaseT.java) into type 'CaseT' (CaseT.java)"/>
      </compile>
-   </ajc-test>    
-</suite>
\ No newline at end of file
+   </ajc-test>
+</suite>