I have a project, working fine, when I deploy the EAR to Jboss EAP. The behavior is as expected.
I also can test my project with Arquillian with a lot of tests, but I observed now the following behavior (below).
I observed the behavior in combination using Hibernate envers @Audited, that each @Test will be wrapped with a transaction or?
Environment:
- Java 11
- Jboss EAP 7.4.7
Dependencies (Gradle):
api 'org.hibernate:hibernate-core:5.3.28.Final'
api 'org.hibernate:hibernate-envers:5.3.28.Final'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2'
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.2'
testFixturesApi 'org.jboss.arquillian.protocol:arquillian-protocol-servlet:1.8.0.Final'
testFixturesApi 'org.wildfly.arquillian:wildfly-arquillian-container-managed:4.0.1.Final'
testFixturesApi 'org.jboss.shrinkwrap.resolver:shrinkwrap-resolver-gradle-depchain:3.2.1'
testFixturesApi 'org.jboss.arquillian.junit5:arquillian-junit5-container:1.8.0.Final'
testFixturesApi 'org.junit.jupiter:junit-jupiter-api:5.10.1'
Entities (stripped):
@Entity
@Audited
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Component implements HasEntityId {
...
}
@Entity
@Audited
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Node extends Component {
...
}
@Entity
@Audited
@Table(name = "tbl_server")
public class Server extends Node {
...
}
Beans (stripped):
@Stateless
public class NodeBeanImpl implements NodeBean {
...
@Override
@Transactional
public Node create(Node node) { // confusing name, but using entityManager.merge, so not only create also updating
....
return savedNode;
}
@Override
public void modifyAndDelete(Node node, String description) {
node.setDescription(description);
Node n = create(node);
System.out.println("DESCR: " + n.getDescription());
delete(n);
}
@Override // NO TRANSACTION!!!!!
public Optional<Node> getByHostNameAndDomainName(String hostName, String domainName) {
return ...
}
}
I observed the behavior, when I checking the envers audit records! In the following test I see, the @Test method will be wrapped (automatically?)
The example is changing the property "description" for demonstration.
@ExtendWith(CertificateArquillianExtension.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class OTest {
@Deployment(testable = true)
public static JavaArchive createDeployment() {
JavaArchive jar = JUnitHelperEJB.buildEJBWithPublic(false);
return jar;
}
@Inject
private NodeBean nodeBean;
private static UUID lastId;
@Test
@Order(100)
void testCreateAndModify() {
Node node = new Server("1", "1", "descr01", "system01.ula.de", "1.1.1.1");
node = nodeBean.create(node);
node.setDescription("descr02");
node = nodeBean.create(node);
lastId = node.getId();
// I get TWO (2) audit records with "descr01" and "descr02"
}
@Test
@Order(110)
void testReadAndModifyTwice() {
Node node = nodeBean.getByHostNameAndDomainName("system01", "ula.de").get(); //Optional!
assertThat(node.getId(), is(lastId));
assertThat(node.getDescription(), is("descr02"));
node.setDescription("descr03");
node = nodeBean.create(node);
node.setDescription("descr04");
node = nodeBean.create(node);
assertThat(node.getDescription(), is("descr04"));
// I get FOUR (4) audit records with "descr01", "descr02", "descr03", "descr04".
}
@Test
@Order(120)
void testDelete() {
Node node = nodeBean.getByHostNameAndDomainName("system01", "ula.de").get(); //Optional!
assertThat(node.getId(), is(lastId));
assertThat(node.getDescription(), is("descr04"));
nodeBean.modifyAndDelete(node, "descr05");
// I get FIVE (5) audit records with "descr01", "descr02", "descr03", "descr04" and a "DEL" record,
// but NO "descr05" !!!
}
}
So I do NOT find the change with descripton="descr05" as an audit record, I just see until "descr04" and next revision is the delete record. modifyAndDelete is modifying the node, and store with create.
Then I delete, so I just must get two audit records.
I just simplified my test case for Stackoverflow.
When I deploy the same logic to Jboss EAP, I will see my missing audit record, so change to "descr05" is a audit record!
I also have seen in another test, calling another method in my bean and than asking entity manager em.isJoinedToTransaction().
I saw, after calling nodeBean.getByHostNameAndDomainName in the @Test, that em.isJoinedToTransaction() changed from false to true. Sound to me, Arquillian is wrapping.
So it looks for my, the call getByHostNameAndDomainName turn on a transaction. The inner create, delete are parts of the @Test transaction, envers will not see this changes until finally committing from the @Test?
So I think, Arquillian is wrapping the transaction handling automatically with in a @Test using a @Stateless bean?
I found a lot of examples with Junit4 and
@Transactional(value = TransactionMode.DISABLED)
It may work? Unfortunately I just change to Junit5 a few weeks ago. I do not want go back.
Can I control the transaction handling in my Junit5 environment?