I'm wondering if this is a bug, or is by design. I've been adding the use of Arq persistence ext alpha4 to some of my tests, and in the process it seems my unit test methods are now participating in JTA transactions where they weren't before.
I had had one start failing that'd previously been succeeding when I added an @ApplyScriptBefore annotation on a different test method in the same test class and same test deployment.
The failing test in question checks to make sure that a certain entity was lazily loading certain expensive elements. It does so by invoking a transactional method of a @Stateless EJB to fetch the entity and return it to the test method, where access to an element that should be lazily loaded is attempted. An exception must be thrown at this point, because the transaction the entity was loaded in has ended with the transactional EJB method. Without Arquillian persistence extension, that's what happens. When I add Arquillian persistence extension to my pom, even without any code changes, the test starts failing, ie the lazy load succeeds so the entity must not be detached, or must've loaded the data eagerly.
A check with PersistenceUnitUtil shows that the data hasn't been eagerly loaded. That's the case whether or not @ApplyScriptBefore is present. Yet, if and only if @ApplyScriptBefore is present in the class, the entity is demand-loaded on access instead of throwing. It seems the entity remains attached to a persistence context when returned from the transactional EJB method - but only when an @ApplyScriptBefore is present in the class.
Any idea what could be going on?
Examination of the PostgreSQL logs shows that the @ApplyScriptBefore is correctly being run in a different PostgreSQL session, under a different user ID. All other work happens within the JPA data source's session, as expected.
UPDATE: Explicitly requiring that the business method that fetches the entity do so in a separate transaction by annotating it @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) resolves the immediate issue; the test now passes. The question remains: why was the transaction being closed at the end of the EJB's business method before I added @ApplyScriptBefore, but not after?
Also, the docs don't make it very clear whether @ApplyScriptBefore scripts run in an externally-created transaction or in autocommit mode (ie: no explicit transaction). It's thus not clear whether they should BEGIN and COMMIT one themselves. It's wrong to do so if there's already a transaction, but may be necessary if there isn't. Maybe @ApplyScriptBefore needs to take a param indicating whether the script expects to be wrapped in a transaction? Some DBs have operations that can't be done within a transaction so the option of having the script in autocommit or doing its own tx management is important. Perhaps @ApplyScriptBefore just needs to be documented to say scripts are always run without an existing transaction and must commit or rollback any open transaction before finishing? With a matching check in the code to make sure the reality matches the docs? (If you agree this is the right approach I can have a go at a patch).