Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TestContext framework should support one AspectJ instance per ApplicationContext [SPR-6353] #11019

Open
spring-issuemaster opened this issue Nov 13, 2009 · 3 comments

Comments

@spring-issuemaster
Copy link
Collaborator

commented Nov 13, 2009

John Wu opened SPR-6353 and commented

The Symptom

  • Each test passes when running individually;
  • A few @Transactional tests may fail when running in a test suite. The failure may occur on any @Transactional test class, depending on the nondeterministic runtime tests sequence. In fact, it's quite difficult to reproduce before knowing the root cause.

Steps to Reproduce

  • Using Spring 2.5.6 or 3.0.0.RC1, JUnit 4;
  • Create a SimpleDbOpService (may or may not annotated with @Transactional), add a method to insert a record into DB based on the input parameters;
  • Create a SimpleDbOpATest:
@ContextConfiguration({"base.xml", "A.xml"})
  • Create a SimpleDbOpBTest:
@ContextConfiguration({"base.xml", "B.xml"})
  • Create a SimpleDbOpCTest:
@ContextConfiguration({"base.xml", "A.xml"})
  • Each test is annotated with @Transactional, calling the SimpleDbOpService and verifying the DB operation results at the end of test method;
  • <tx:annotation-driven mode="aspectj"/> in base.xml, also add "transactionManager" definition in
  • Create a test suite class as the following:
    import org.junit.runner.RunWith;
    import org.junit.runners.Suite;
    
    @RunWith(Suite.class)
    @Suite.SuiteClasses({
      SimpleDbOpATest.class,
      SimpleDbOpBTest.class,
      SimpleDbOpCTest.class
    })
    public class Debug {
    
    }
  • The tests in SimpleDbOpCTest will fail.

Root Cause

In the Test Framework, it creates one instance of ApplicationContext for each "Set of context locations" and caches (and switches) the ApplicationContext instances by "context locations". Among all those ApplicationContext instances, the instance of AnnotationTransactionAspect is shared. That is, during the test suite running, there will be only one instance of AnnotationTransactionAspect, no matter how many ApplicationContext instances created.

A reference to BeanFactory (in spring 3.0.0.RC) or transactionManager (in spring 2.5.6) will be injected into AnnotationTransactionAspect (derived from TransactionAspectSupport) while the ApplicationContext being loaded.

In the example above, test A and C have the exactly same context locations, and they will share the same application context instance when running in a test suite. So, when running tests A, B, and C in a suite and in that order, the application context instance switches from A to B to A. However, the transactionManager instance (retrieved from an instance of AnnotationTransactionAspect) will be A, B, and B (should be A though), because there is only one instance of AnnotationTransactionAspect per class loader. In turn, that causes the operations in the C.testXxx() be split in to two transactionManager instances, one from AnnotationTransactionAspect and the other from ApplicationContext. Therefore, the DB result verification fails.

Proposed Solution

To create one Aspect instance per ApplicationContext, not per class loader. Not sure if that's achievable though.

Further Resources


Affects: 2.5.6, 3.0.5

Reference URL: http://forum.springsource.org/showthread.php?t=79949

Issue Links:

  • #11897 Transaction is not started when two spring contexts are created during tests using AspectJ load time weaving ("is duplicated by")
  • #17123 AnnotationTransactionAspect retains reference to JpaTransactionManager from closed context
  • #10789 Dependency injection of @Configurable objects should work across test suites
  • #12619 AnnotationTransactionAspect retains reference to closed BeanFactory

5 votes, 7 watchers

@sbrannen

This comment has been minimized.

Copy link
Member

commented Feb 24, 2019

Added "waiting for triage" label in order to assess whether this is still an issue with recent versions of the framework.

@cdalexndr

This comment has been minimized.

Copy link

commented Jul 20, 2019

Encountered a problem that impacts @Cacheable and @CacheEvict, and can cause inconsistent cache:
Consider a service with two methods, one annotated @Cacheable, other @CacheEvict.

  1. First app context is created, AnnotationCacheAspect.cacheResolver is first set to null from CacheAspectSupport.configure method where all params are null
  2. AnnotationCacheAspect.cacheResolver is set to correct bean in method CacheAspectSupport.afterSingletonsInstantiated
  3. Test method uses first method (@Cacheable) and puts a key in CacheAspectSupport.metadataCache with the cacheResolver from (1) in method CacheAspectSupport.getCacheOperationMetadata (lazy initialized as methods annotated @Cacheable/@CacheEvict are used)
  4. New app context is created. Again AnnotationCacheAspect.cacheResolver is set to null. AnnotationCacheAspect is the same instance as the one from previous app context (!problem!)
  5. AnnotationCacheAspect.cacheResolver is initialized to another bean from second app context
  6. Test method uses second method (@CacheEvict) and puts a key in the same CacheAspectSupport.metadataCache with a cacheResolver initialized above, that is different from the key corresponding to the first service method with @Cacheable
  7. Test method calls first service method, and it expects to re-compute the values and put in cache because it was evicted previously... instead it incorrectly gets the cached value from the first cacheResolver cache

spring-aspects-5.1.8.RELEASE

@cdalexndr

This comment has been minimized.

Copy link

commented Jul 20, 2019

This issue is 10 years old, why is there no initiative to fix this as it creates multiple problems?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.