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

[JBPM-10231] Fixed non-idempotent unit tests in jbpm-runtime-manager #2421

Closed
wants to merge 1 commit into from

Conversation

kaiyaok2
Copy link

@kaiyaok2 kaiyaok2 commented May 22, 2024

link

The Problem

Some unit tests are non-idempotent, as they pass in the first run but fail in the second run in the same environment. A fix is necessary since unit tests shall be self-contained, ensuring that the state of the system under test is consistent at the beginning of each test. In practice, fixing non-idempotent tests can help proactively avoid state pollution that results in test order dependency (which could cause problems under test selection , prioritization or parallelization).

Reproduce

Using the NIOInspector plugin that supports rerunning JUnit tests in the same environment. Use EventHnadlingTest#testRunMultiEventProcessPerRequestRuntimeManager as an example:

cd jbpm-runtime-manager
mvn edu.illinois:NIOInspector:rerun -Dtest=org.jbpm.runtime.manager.concurrent.EventHnadlingTest#testRunMultiEventProcessPerRequestRuntimeManager

3 Non-Idempotent Tests & Proposed Fix

EventHnadlingTest#testRunMultiEventProcessPerRequestRuntimeManager

Reason: With "Per Request" strategy, for every call to getRuntimeEngine(), a new instance will usually be delivered with brand new KieSession. However, the exception to this is when getRuntimeEngine() invoked within the same transaction from different places (which would be the case if testRunMultiEventProcessPerRequestRuntimeManager is re-executed). In that case, the manager caches the currently active instance. Therefore, in the second execution of the test, an error will be thrown since the retrieved (cached) KieSession is already closed by the previous test execution. To resolve this, the runtime engine manager shall be disposed to ensure that its KieSession is destroyed as well. 

Error message of the test in the repeated run:

java.lang.IllegalStateException: Session/EntityManager is closed
	at org.hibernate.internal.AbstractSharedSessionContract.checkOpen(AbstractSharedSessionContract.java:375)
	at org.hibernate.engine.spi.SharedSessionContractImplementor.checkOpen(SharedSessionContractImplementor.java:148)
	at org.hibernate.internal.SessionImpl.joinTransaction(SessionImpl.java:3633)
	at org.drools.persistence.jpa.JpaPersistenceContext.joinTransaction(JpaPersistenceContext.java:106)
	at org.drools.persistence.PersistableRunner$TransactionInterceptor.execute(PersistableRunner.java:603)
	at org.drools.persistence.PersistableRunner$TransactionInterceptor.execute(PersistableRunner.java:572)
	at org.drools.core.command.impl.AbstractInterceptor.executeNext(AbstractInterceptor.java:39)
	at org.drools.persistence.jpa.OptimisticLockRetryInterceptor.internalExecute(OptimisticLockRetryInterceptor.java:102)
	at org.drools.persistence.jpa.OptimisticLockRetryInterceptor.execute(OptimisticLockRetryInterceptor.java:83)
	at org.drools.persistence.jpa.OptimisticLockRetryInterceptor.execute(OptimisticLockRetryInterceptor.java:44)
	at org.drools.core.command.impl.AbstractInterceptor.executeNext(AbstractInterceptor.java:39)
	at org.drools.persistence.jta.TransactionLockInterceptor.execute(TransactionLockInterceptor.java:73)
	at org.drools.persistence.jta.TransactionLockInterceptor.execute(TransactionLockInterceptor.java:45)
	at org.drools.core.command.impl.AbstractInterceptor.executeNext(AbstractInterceptor.java:39)
	at org.jbpm.runtime.manager.impl.error.ExecutionErrorHandlerInterceptor.internalExecute(ExecutionErrorHandlerInterceptor.java:66)
	at org.jbpm.runtime.manager.impl.error.ExecutionErrorHandlerInterceptor.execute(ExecutionErrorHandlerInterceptor.java:52)
	at org.jbpm.runtime.manager.impl.error.ExecutionErrorHandlerInterceptor.execute(ExecutionErrorHandlerInterceptor.java:29)
	at org.drools.persistence.PersistableRunner.execute(PersistableRunner.java:400)
	at org.drools.persistence.PersistableRunner.execute(PersistableRunner.java:68)
	at org.drools.core.runtime.InternalLocalRunner.execute(InternalLocalRunner.java:37)
	at org.drools.core.runtime.InternalLocalRunner.execute(InternalLocalRunner.java:41)
	at org.drools.core.command.impl.CommandBasedStatefulKnowledgeSession.startProcess(CommandBasedStatefulKnowledgeSession.java:275)
	at org.drools.core.command.impl.CommandBasedStatefulKnowledgeSession.startProcess(CommandBasedStatefulKnowledgeSession.java:259)
	at org.jbpm.runtime.manager.concurrent.EventHnadlingTest.testRunMultiEventProcessPerRequestRuntimeManager(EventHnadlingTest.java:86)

Fix: Add the line manager.disposeRuntimeEngine(runtime); before closing the manager

PerCaseRuntimeManagerTest#testMultipleProcessesInSingleCaseCompletedInSequence

Reason: The "Per Case" strategy specifies that every process instance that belongs to same case will be bound to a single ksession for its entire life time.  Once started, whenever such operations are invoked, the manager will retrieve the same ksession. Similarly, manager.disposeRuntimeEngine(runtime) shall be called before manager.close() to ensure that the second test execution does not directly retrieve the already closed ksession.

Error message in the repeated run:

java.lang.IllegalStateException: Session/EntityManager is closed
	at org.hibernate.internal.AbstractSharedSessionContract.checkOpen(AbstractSharedSessionContract.java:375)
	at org.hibernate.engine.spi.SharedSessionContractImplementor.checkOpen(SharedSessionContractImplementor.java:148)
	at org.hibernate.internal.SessionImpl.joinTransaction(SessionImpl.java:3633)
	at org.drools.persistence.jpa.JpaPersistenceContext.joinTransaction(JpaPersistenceContext.java:106)
	at org.drools.persistence.PersistableRunner$TransactionInterceptor.execute(PersistableRunner.java:603)
	at org.drools.persistence.PersistableRunner$TransactionInterceptor.execute(PersistableRunner.java:572)
	at org.drools.core.command.impl.AbstractInterceptor.executeNext(AbstractInterceptor.java:39)
	at org.drools.persistence.jpa.OptimisticLockRetryInterceptor.internalExecute(OptimisticLockRetryInterceptor.java:102)
	at org.drools.persistence.jpa.OptimisticLockRetryInterceptor.execute(OptimisticLockRetryInterceptor.java:83)
	at org.drools.persistence.jpa.OptimisticLockRetryInterceptor.execute(OptimisticLockRetryInterceptor.java:44)
	at org.drools.core.command.impl.AbstractInterceptor.executeNext(AbstractInterceptor.java:39)
	at org.drools.persistence.jta.TransactionLockInterceptor.execute(TransactionLockInterceptor.java:73)
	at org.drools.persistence.jta.TransactionLockInterceptor.execute(TransactionLockInterceptor.java:45)
	at org.drools.core.command.impl.AbstractInterceptor.executeNext(AbstractInterceptor.java:39)
	at org.jbpm.runtime.manager.impl.error.ExecutionErrorHandlerInterceptor.internalExecute(ExecutionErrorHandlerInterceptor.java:66)
	at org.jbpm.runtime.manager.impl.error.ExecutionErrorHandlerInterceptor.execute(ExecutionErrorHandlerInterceptor.java:52)
	at org.jbpm.runtime.manager.impl.error.ExecutionErrorHandlerInterceptor.execute(ExecutionErrorHandlerInterceptor.java:29)
	at org.drools.persistence.PersistableRunner.execute(PersistableRunner.java:400)
	at org.drools.persistence.PersistableRunner.execute(PersistableRunner.java:68)
	at org.drools.core.runtime.InternalLocalRunner.execute(InternalLocalRunner.java:37)
	at org.drools.core.runtime.InternalLocalRunner.execute(InternalLocalRunner.java:41)
	at org.drools.core.command.impl.CommandBasedStatefulKnowledgeSession.getIdentifier(CommandBasedStatefulKnowledgeSession.java:134)
	at org.jbpm.runtime.manager.impl.PerCaseRuntimeManagerTest.testMultipleProcessesInSingleCaseCompletedInSequence(PerCaseRuntimeManagerTest.java:349)

Fix: Same as the previous test: add manager.disposeRuntimeEngine(runtime); before closing the manager

PerRequestRuntimeManagerTest#testMultiplePerRequestManagerFromSingleThread

Reason: This is actually a typo - the process instance runtime2 is managed by manager2, not manager.
The original code is

manager.disposeRuntimeEngine(runtime1);
manager.disposeRuntimeEngine(runtime2);

It shall be changed to 

manager.disposeRuntimeEngine(runtime1);
manager2.disposeRuntimeEngine(runtime2);

Error message of one of the tests in the repeated run:

java.lang.IllegalStateException: RuntimeManager with id second is already active
	at org.jbpm.runtime.manager.impl.AbstractRuntimeManager.<init>(AbstractRuntimeManager.java:141)
	at org.jbpm.runtime.manager.impl.PerRequestRuntimeManager.<init>(PerRequestRuntimeManager.java:74)
	at org.jbpm.runtime.manager.impl.RuntimeManagerFactoryImpl.newPerRequestRuntimeManager(RuntimeManagerFactoryImpl.java:73)
	at org.jbpm.runtime.manager.impl.PerRequestRuntimeManagerTest.testMultiplePerRequestManagerFromSingleThread(PerRequestRuntimeManagerTest.java:543)

Fix: As described above

Verifying this change

After the patch, running the tests repeatedly in the same environment will not lead to failures.

@elguardian
Copy link
Member

@fjtirado looks like it worths review.

@gmunozfe
Copy link
Member

jenkins test this

@gmunozfe gmunozfe self-requested a review May 22, 2024 07:01
Copy link

sonarcloud bot commented May 22, 2024

Quality Gate Passed Quality Gate passed

Issues
6 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarCloud

Copy link
Member

@gmunozfe gmunozfe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, thanks for your contribution @kaiyaok2 !

@gmunozfe gmunozfe added backport-7.67.x Generate backport PR for 7.67.x branch backport-7.67.x-blue Generate backport PR for 7.67.x-blue branch labels May 22, 2024
@kaiyaok2
Copy link
Author

kaiyaok2 commented Jun 4, 2024

Closing this as superseded by #2422

@kaiyaok2 kaiyaok2 closed this Jun 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport-7.67.x Generate backport PR for 7.67.x branch backport-7.67.x-blue Generate backport PR for 7.67.x-blue branch
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants