ArchUnit: FreezingArchRule breaks when executed from IDE and maven

Environment:

  • JDK11

Expected behavior: When the store files are generated, the tests should all pass independent of the test execution (here: IntelliJ or maven)

Actual behavior:

  • When the store files were generated through IntelliJ, the tests only pass when they are executed through IntelliJ. Executing the tests through maven will result in test failures.
  • When the store files were generated through maven, the tests only pass when they are executed through maven. Executing the tests through IntelliJ will result in test failures.

How to reproduce:

  • Check out this PR: https://github.com/Taskana/taskana/pull/1971 where we’ve enabled our architecture tests (store files were generated through IntelliJ)
  • Execute the ArchitectureTest class through IntelliJ. All tests should pass.
  • Execute the ArchitectureTest class through maven. Some tests should fail. Execution command (from project root directory):
#build dependencies
./mvnw clean install -pl :taskana-core-test -am -DskipTests
#execute tests from ArchitectureTest class
./mvnw clean verify -pl :taskana-core-test -Dtest="ArchitectureTest"

Further notes:

As of right now we’ve disabled the tests, since this behavior is blocking us. You can find our test class here: https://github.com/Taskana/taskana/blob/master/lib/taskana-core-test/src/test/java/acceptance/ArchitectureTest.java The tests packagesShouldBeFreeOfCyclicDependencies and classesShouldBeFreeOfCyclicDependencies will fail. We’ve already set the following properties to an unreasonable high amount in order to make sure that all errors are detected.

cycles.maxNumberToDetect=100000
cycles.maxNumberOfDependenciesPerEdge=10000

During our initial debugging we’ve found out that the line numbers differ between the execution through maven and IntelliJ. Furthermore we’ve seen that IntelliJ and maven name lambda’s differently, which is a second difference in the store files.

Screenshot from 2022-07-18 16-18-53 Screenshot from 2022-07-18 16-18-30

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 1
  • Comments: 16

Commits related to this issue

Most upvoted comments

Hey @codecholeric,

My problem is that I can’t reproduce it anymore thinking I pulled your latest changes, then recompiled everything, ran the test from IntelliJ, the store was created, ran it from Maven -> success. Deleted the store, recreated it from Maven, ran the test in IntelliJ -> success.

I’ve provided a video where I showcase what I did. Hopefully this helps you. https://drive.google.com/file/d/1KRMzIp7ipZYZxynLzKX8HZ1XMx7YTafJ/view?usp=sharing

So there either must be some random factor, or it depends on the platform. What OS are you running the tests on? Windows by any chance? wink (just asking, cause I had some problems in the past; I’m running the tests on Linux…)

I am using linux myself.

[mustapha@NT220403 taskana]$ uname -r
5.19.7-arch1-1
[mustapha@NT220403 taskana]$ cat /etc/os-release 
NAME="Arch Linux"
PRETTY_NAME="Arch Linux"
ID=arch
BUILD_ID=rolling
ANSI_COLOR="38;2;23;147;209"
HOME_URL="https://archlinux.org/"
DOCUMENTATION_URL="https://wiki.archlinux.org/"
SUPPORT_URL="https://bbs.archlinux.org/"
BUG_REPORT_URL="https://bugs.archlinux.org/"
LOGO=archlinux-logo

Could you maybe create the store from your IDE, safe copy it somewhere, create it from Maven as well, and then zip both stores and attach them to a comment here? Because otherwise I wouldn’t know how to dig deeper into this thinking

sure thing 😃 In the video you can see how I created these files. archunit_store_maven.zip archunit_store_intellij.zip output_intellij.txt output_maven.txt

Regarding 1.0.0, this is the last issue I’m looking into. If we’re sure it’s not a blocker I can release 1.0.0

Alright. I don’t want to be the blocking factor. Therefore I will try to reply as fast as I can 😃

Okay, this was quite the rabbit hole 😂 The first thing I noticed was that while some cycles between these classes were missing, this would not happen anymore if I would disable the AspectJ weaving. Looking into the bytecode I noticed that applying AspectJ would make the call to TaskanaConfigurationInitializer.parseProperty(..) invisible in the bytecode of the classes. This is because AspectJ would weave in some additional synthetic access methods TaskanaConfigurationInitializer.access$123 which would then call parseProperty. So the question at this point was only, why was one cycle always detected if this call was missing, or more precisely, why was only one cycle detected, since normally ArchUnit would be supposed to transparently replace those calls to access$123 with the call users would expect from the source code (compare #889). Turns out that 1.0.0-rc1 actually contains a bug there 🙈 So, I’m really glad that this issue brought this to surface. Basically, the implementation to remove those access$123 methods was the same as for lambda$xyz$123 methods, but for the latter the origins of the calls would be unique. But, for access$123 they actually overrode each other, which lead to a non-deterministic behavior which access would be imported in the end (but seemingly deterministic enough so that it would be the same as long as the system and the environment would not change). You can see more details and (hopefully) a fix here (#957). In any case, I also published the version with the fix as 1.0.0-SNAPSHOT, so maybe you can test this, if it solves your problem? It should now detect all 6 cycles for all 6 inner classes of TaskanaConfigurationInitializer and thus not have different frozen cycles on different environments anymore. You have to add the snapshot repository to test it:

<repositories>
    <repository>
      <id>sonatype-snapshots</id>
      <url>https://oss.sonatype.org/content/repositories/snapshots</url>
    </repository>
  </repositories>

Can you let me know if this now behaves reasonable for you?