I have several session beans that I have written unit tests for. I have setup Maven to include a persistence.xml in the src/main/resources/META-INF directory that refers to
This answer might sounds silly but I was looking for a way which lets me run those tests from eclipse by Run As
-> JUnit Test
. This is how I made it:
@BeforeClass
public static void setUp() throws IOException {
Files.copy(new File("target/test-classes/META-INF/persistence.xml"), new File("target/classes/META-INF/persistence.xml"));
// ...
}
I'm just copying the test/persistence.xml to classes/persistence.xml. This works.
When running tests using embedded Glassfish, the JPA provider does not use the classpath displayed on the command-line, before executing the maven-surefire-plugin goal (that is used to run the test phase). Embedded Glassfish deploys the artifacts that are available as part of a test scope, as a ScatteredArchive
. This scattered archive is typically created in the java.io.tmpdir
directory usually with the name gfembed<a_random_number>tmp
, unless the embedded Glassfish configuration specified the location of a Glassfish installation root, and a Glassfish domain.
When the embedded Glassfish domain is prepared with the deployed scattered archive, the files to be deployed are typically copied into an exploded directory that houses all the classes (including all dependencies) required by the application. This directory typically happens to be present in the GF_EMBED_DOMAIN_HOME/applications/<application_name>
directory. The persistence.xml
files from your src/main/resources/META-INF
and src/test/resources/META-INF
directories are copied here into the <application-name>/META-INF
directory. Needless to state, the one that gets copied last, or the one that doesn't get overwritten is the one that is used by the JPA provider during the tests. This always happens to be the file in src/main/resources/META-INF
.
You can overcome this situation in two ways:
1. Using a custom Glassfish domain configuration file
You can specify a domain configuration file (domain.xml
) that will contain the datasource definition for jdbc/mylog
. This is what I do currently for it is very flexible and the domain configuration file can contain other configurations as well. The config file, needs to specified as part of test setup in the following way:
Map<String, Object> props = new HashMap<String, Object>();
props.put("org.glassfish.ejb.embedded.glassfish.installation.root", "./glassfish-install/glassfish");
container = EJBContainer.createEJBContainer(props);
context = container.getContext();
datasource = (DataSource) context.lookup("jdbc/mylog"); //You can lookup the datasource too, to confirm that your setup is successful.
The afore-mentioned glassfish-install
directory and its sub-directory glassfish
are present in the Maven project root (and also checked into version control); the glassfish
directory must contain a directory structure of domain1/config
to represent the directory structure of the Glassfish domain of name domain1
. The structure in the project can be seen in the below screenshot. The other related files (the JDBC resource adapter JARs and the like), can be obtained from a Glassfish installation directory, but typically these might also be placed in the correct location by the embedded Glassfish runtime, if configured correctly.
The contents of the Glassfish domain configuration file are different from the default one used by embedded Glassfish, except for the datasource and connection pool configuration (the relevant entries added in my usecase where I perform integration tests, have been posted below):
<domain log-root="${com.sun.aas.instanceRoot}/logs" application-root="${com.sun.aas.instanceRoot}/applications" version="10.0">
<system-applications/>
<applications/>
<resources>
<jdbc-resource pool-name="MyPool" jndi-name="jdbc/mylog"/>
...
<jdbc-connection-pool driver-classname="" datasource-classname="org.apache.derby.jdbc.ClientDataSource" res-type="javax.sql.DataSource" description="" name="MyPool" ping="true">
<property name="User" value="APP"></property>
<property name="RetrieveMessageText" value="true"></property>
<property name="CreateDatabase" value="true"></property>
<property name="ServerName" value="localhost"></property>
<property name="Ssl" value="off"></property>
<property name="SecurityMechanism" value="4"></property>
<property name="TraceFileAppend" value="false"></property>
<property name="TraceLevel" value="-1"></property>
<property name="PortNumber" value="1527"></property>
<property name="LoginTimeout" value="0"></property>
<property name="Password" value="APP"></property>
<property name="databaseName" value="MYDB"></property>
</jdbc-connection-pool>
...
</resources>
<servers>
<server name="server" config-ref="server-config">
<resource-ref ref="jdbc/__TimerPool"/>
<resource-ref ref="jdbc/__default"/>
<resource-ref ref="jdbc/mylog"/>
</server>
</servers>
...
...
The default domain.xml file can be downloaded from the java.net site, and modified, in the event you wish to keep the changes as minimal as possible, instead of copying one from a Glassfish installation.
2. Copying over the persistence.xml files
One can add goals to the Maven POM file, to backup and copy the persistence.xml
file from src/test/resources/META-INF
to src/main/resources/META-INF
, before the test
phase. After the test phase is complete, the original is restored. I will not go into details of this, as a similar solution is already discussed in a related StackOverflow question. I did not use this approach for integration tests as I required changes to be done beyond the ones that can be carried in persistence.xml
, like creation of a custom realm. I use it for unit-tests however, due to the fact that the JPA provider will fetch the persistence.xml
file from target/classes
instead of target/test-classes
, despite the latter appearing first in the classpath order. If you use Hibernate as your JPA provider, enabling TRACE logging for the org.hibernate.ejb
logger (as the Ejb3Configuration
class is responsible for performing the lookup) would convince you that file in test-classes
will not be picked up.
Note:
Most of the answer assumes Glassfish 3.1 but may hold good for upcoming versions as well.
By "embedded glassfish container", do you mean a maven plugin that runs glassfish for you? The classpath for a maven plugin is different and managed differently than the maven test classpath. You might need to be working with a different classpath.