This is my SLSB:
#Stateless
public class MyService {
PersistenceContext(unitName = "abc")
EntityManager em;
public boolean exists(int id) {
return this.em.find(Employee.class, id) != null;
}
}
This is my persistence.xml (I'm using Glassfish v3):
<persistence>
<persistence-unit name="abc">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/MyDS</jta-data-source>
<properties>
<property name="hibernate.archive.autodetection" value="class" />
<property name="hibernate.dialect"
value="org.hibernate.dialect.MySQLInnoDBDialect" />
</properties>
</persistence-unit>
</persistence>
Now I'm trying to create a test, using OpenEJB embedded container. This is my test class:
class MyServiceText {
#Test
public void testChecksExistence() throws Exception {
Properties properties = new Properties();
properties.setProperty(
javax.naming.Context.INITIAL_CONTEXT_FACTORY,
"org.apache.openejb.client.LocalInitialContextFactory"
);
InitialContext ic = new InitialContext(properties);
// actual testing skipped
}
}
I would like to use HSQL for testing. How can I instruct OpenEJB that my persistence unit "abc" has to point to HSQL during testing? Shall I create a new version of persistence.xml? Shall I use openejb.xml? I'm lost in their examples and documentation.. :(
It's a Maven-3 project.
I would suggest placing a file named jndi.properties in src/test/resources for your OpenEJB configuration. This will then be available in the test classpath, you can then use the no-argument contructor of InitialContext to lookup datasources and ejbs. An example configuration looks like this, I'm using mysql for my datasource:
java.naming.factory.initial=org.apache.openejb.client.LocalInitialContextFactory
myDS=new://Resource?type=DataSource
myDS.JdbcDriver=com.mysql.jdbc.Driver
myDS.JdbcUrl=jdbc:mysql://127.0.0.1:3306/test
myDS.JtaManaged=true
myDS.DefaultAutoCommit=false
myDS.UserName=root
myDS.Password=root
OpenEJB should then automatically replace the reference in persistence.xml with this datasource, if this is the only datasource then this should work even if the names are different.
Edit: Persistence unit settings
According to the documentation you referenced it should also be possible to configure persistence unit properties through jndi.properties:
abc.hibernate.hbm2ddl.auto=update
abc.hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect
I haven't tested this myself since I'm using mysql for both tests and normal executions, only with different database names. Please let me know if this works, I've been thinking about replacing mysql in my testcases too.
Related
I'm building Spring+Hibernate Java Application. I wanted to add some integration tests, done in in-memory database.
So, my normal database is Postgresql, and I populate it using .sql scripts run with flyway plugin. ID fields are set to BIGSERIAL. I wanted to use in-memory database, to resemble my original database, and then try to test some classes with it. I managed to configure preety much everything(I hope so), but when I run the test class itself I get error with CREATE TABLE scripts:
Caused by: org.hsqldb.HsqlException: type not found or user lacks privilege: BIGSERIAL
I found out that I should configure HSQLDB, to enable Postgresql compability.
Use SET DATABASE SQL SYNTAX PGS TRUE or the equivalent URL property sql.syntax_pgs=true to enable the PostgreSQL's non-standard features.
I use persistence.xml to define normal and test persistence unit. This is fragment responsible for defining test persistence unit:
<persistence-unit name="testJPA">
<properties>
<property name="hibernate.archive.autodetection" value="class, hbm"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
<property name="hibernate.connection.username" value="sa"/>
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.connection.url" value="jdbc:hsqldb:mem:butterfly;sql.syntax_pgs=true"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
</properties>
</persistence-unit>
Then I use configuration class for tests:
#Configuration
#EnableAutoConfiguration
#ComponentScan(basePackages = {"core.utilities"} )
#EnableTransactionManagement
public class TestsInitializer {
#Bean
public LocalEntityManagerFactoryBean entityManagerFactory() {
LocalEntityManagerFactoryBean factoryBean = new LocalEntityManagerFactoryBean();
factoryBean.setPersistenceUnitName("testJPA");
return factoryBean;
}
}
And in testclass itself:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { TestsInitializer.class }/*, loader = AnnotationConfigContextLoader.class*/)
#Transactional
public class GenreBATest {
#Autowired
private GenreBA genreBA;
#Test
public void testFindAllAccounts() {
//whatever
}
}
I added the required property at the end of URL, found examples of this exact property across the internet, but it does not resolve my problem.
I'm still getting: Message : type not found or user lacks privilege: BIGSERIAL
What am I doing wrong?
Ok, I found out that scripts were run by flyway ignoring all possible syntax commands from persistence.xml. And flyway run with HSQLDB because I used #EnableAutoConfiguration in test configuration class without excludes :) I learned through hard way that Spring Boot already configures Hibernate to create schema based on entities for an in-memory database. So I don't need to use database scripts at all, and they were run by accident.
I did some research on how to test my DAO layer using HyperSQL and I found this question: https://softwareengineering.stackexchange.com/questions/219362/how-to-test-the-data-access-layer
How do I import DBConnection because I tried using hypersql jar and it did not work. In the question from the link I saw this db.url=jdbc:hsqldb:file:src/test/resources/testData;shutdown=true; but I do not know how to use it.
Using JDBC and Spring, in your application you'd be creating a DataSource object, and using that object to create a JdbcTemplate object, which is what you're using to run your JDBC queries. Similar to this example. So in order to use the HSql database, you'd need to change the values used to setup the DataSource bean but only for your unit tests.
Depending on how you're using Spring (annotations, xml config), there's a few ways of doing it. You'll need to create a new configuration bean, or configuration xml file, and then reference it in your unit tests.
For XML, copy over your spring context xml file, and change the DataSource values to something like:
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:file:src/test/resources/testData;shutdown=true;"/>
<property name="username" value="SA"/>
<property name="password" value=""/>
You'll then need to reference this new context config in your unit test. Something like:
#RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "classpath:/test-config.xml"
#ContextConfiguration("/test-config.xml")
public class DAOTests {
#Autowired
private DatabaseDAO dao;
}
With annotations, you'll need to make a new configuration class (you should have one already, a class annotated with #Configuration) and return the appropriate DataSource. Something like this:
#Bean
public DataSource hsqlDataSource(){
return DataSourceBuilder
.create()
.driverClassName("org.hsql.jdbcDriver")
.url("jdbc:hsqldb:file:src/test/resources/testData;shutdown=true;")
.username("SA")
.password("");
.build();
}
You can setup a profile for your configuration (using #Profile("test") annotation), and then specify which profile you want to use in your unit test (#ActiveProfiles("test")). More information here.
Alternatively, you could use the Spring EmbeddedDatabaseBuilder if you're just trying to do a simple DAO Test. There's a tutorial here. It sets you up with a HSql in memory database (as opposed to a file based one), which is very convenient for setting up / tearing down. Just add the bean to your configuration class, and your DAO should pick it up if Spring is injecting the DataSource for you. Example below taken from here
#Bean
public DataSource dataSource() {
// no need shutdown, EmbeddedDatabaseFactoryBean will take care of this
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("db/setup_script.sql")
.build();
}
There's a bit to Spring configuration management. I haven't covered it in much detail in this answer, but look up a few examples and it will start to make sense.
I want to read environment variables inside persistence.xml file.
Idea is that i don't want my database details to be read from properties file as there is a change of getting properties file override.Instead i want to read details from environment variables.
Is there any way to achieve this criteria.
Iam using Spring 3 my standalone application will be deployed in unix machine.
You can update properties in a persistence unit by supplying a Map (see this).
Conveniently, environment variables can be retrieved as a Map (see this).
Put the two together and you can dynamically update properties in your persistence unit with environment variables.
EDIT: simple example...
persistence.xml...
<persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
<provider>
oracle.toplink.essentials.PersistenceProvider
</provider>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="toplink.logging.level" value="INFO"/>
<property name="toplink.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
<property name="toplink.jdbc.url" value="jdbc:oracle:thin:#myhost:l521:MYSID"/>
<property name="toplink.jdbc.password" value="tiger"/>
<property name="toplink.jdbc.user" value="scott"/>
</properties>
</persistence-unit>
code that updates persistence.xml "default" unit with environment variables...
Map<String, String> env = System.getenv();
Map<String, Object> configOverrides = new HashMap<String, Object>();
for (String envName : env.keySet()) {
if (envName.contains("DB_USER")) {
configOverrides.put("toplink.jdbc.user", env.get(envName)));
}
// You can put more code in here to populate configOverrides...
}
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("default", configOverrides);
I don't think this will cover EMs created via injection. Worse, I think EMs created through EMF can only be EXTENDED (eg equivalent to the annotation #PersistenceContext(type = PersistenceContextType.TRANSACTION) opposed to EXTENDED) so that if one requires a transaction EM, one must use injection.
I'm wondering if its possible to physically rewrite the persistence.xml file at runtime. Problem one being, ability to rewrite the file (permissions, being able to get to it in META-INF etc), and second, rewriting it before its opened for the first time by JPA (which I thinking happens the first time an injected EM field is actually referenced by application code)
You could use this working example.
It gets all properties defined in the persistence.xml from the PersistenceUnitInfo instance which is obtained from the EntityManagerFactory (by using eclipseLink specific implementations). These properties get replaced with the values defined in environment variables.
What value should I place into <jta-data-source> of my persistence.xml?
In glassfish admin panel I created a datasource name "abcDS". In my jndi.properties (inside src/test/resources) I defined it like this:
[...]
abcDS=new://Resource?type=DataSource
abcDS.JdbcDriver=org.hsqldb.jdbcDriver
abcDS.JdbcUrl=jdbc:hsqldb:mem:testdb
abcDS.JtaManaged=true
[...]
What shall I place into persistence.xml? I've found a lot of variants in the Net, like: "jdbc/abcDS", "java:/abcDS", "abcDS". Which one is right? And is there some rule for this? I understand that it's related to JNDI, but...
I'm trying to create EMF in my unit test:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("abc");
This is what I'm getting in log:
[...]
SEVERE: Could not find datasource: abcDS javax.naming.NameNotFoundException:
Name "abcDS" not found.
at org.apache.openejb.core.ivm.naming.IvmContext.federate(IvmContext.java:193)
at org.apache.openejb.core.ivm.naming.IvmContext.lookup(IvmContext.java:150)
at org.apache.openejb.core.ivm.naming.ContextWrapper.lookup(ContextWrapper.java:115)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
[...]
The problem is that Persistence.createEntityManagerFactory("abc") is the "do it yourself" API and doesn't take advantage of the Embedded EJB Container. You can get a container managed EntityManager in your test case very easily.
Just as with the related jndi/datasource question I recommend you check out the examples in the examples.zip. They're all designed to take the struggle out of getting started.
Here's a snippet from the testcase-injection example which shows how you can get an EntityManager and other things from the container for use in a test.
First, add an empty ejb-jar.xml or application-client.xml to your test to turn on scanning for your test code:
src/test/resources/META-INF/application-client.xml
Then, annotate your test case with #org.apache.openejb.api.LocalClient and use the standard JavaEE annotations for the actual injection.
#LocalClient
public class MoviesTest extends TestCase {
#EJB
private Movies movies;
#Resource
private UserTransaction userTransaction;
#PersistenceContext
private EntityManager entityManager;
public void setUp() throws Exception {
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
p.put("movieDatabase", "new://Resource?type=DataSource");
p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver");
p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb");
InitialContext initialContext = new InitialContext(p);
// Here's the fun part
initialContext.bind("inject", this);
}
As movieDatabase is the only DataSource that we've setup, OpenEJB will automatically assign that DataSource to your persistence unit without the need to modify your persistence.xml. You can even leave the <jta-data-source> or <non-jta-data-source> empty and OpenEJB will still know what to do.
But for the sake of completeness, here's how this particular application has defined the persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<persistence-unit name="movie-unit">
<jta-data-source>movieDatabase</jta-data-source>
<non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
<class>org.superbiz.testinjection.Movie</class>
<properties>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
</properties>
</persistence-unit>
</persistence>
Then the fun part, using it all together in tests
public void test() throws Exception {
userTransaction.begin();
try {
entityManager.persist(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
entityManager.persist(new Movie("Joel Coen", "Fargo", 1996));
entityManager.persist(new Movie("Joel Coen", "The Big Lebowski", 1998));
List<Movie> list = movies.getMovies();
assertEquals("List.size()", 3, list.size());
for (Movie movie : list) {
movies.deleteMovie(movie);
}
assertEquals("Movies.getMovies()", 0, movies.getMovies().size());
} finally {
userTransaction.commit();
}
}
This is my persistence.xml:
<persistence>
<persistence-unit name="MyUnit">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/abcDS</jta-data-source>
</persistence-unit>
</persistence>
This is jndi.properties file from src/test/resources which is supposed to create a datasource during testing, since a real application server with a real datasource is absent:
java.naming.factory.initial=org.apache.openejb.client.LocalInitialContextFactory
jdbc/abcDS=new://Resource?type=DataSource
jdbc/abcDS.JdbcDriver=org.hsqldb.jdbcDriver
jdbc/abcDS.JdbcUrl=jdbc:hsqldb:mem:testdb
jdbc/abcDS.JtaManaged=true
jdbc/abcDS.DefaultAutoCommit=false
jdbc/abcDS.UserName=sa
jdbc/abcDS.Password=
This is the test class:
public class FinderTest {
#BeforeClass
public static void startEJB() throws Exception {
InitialContext ic = new InitialContext();
ic.lookup("jdbc/abcDS");
}
}
Unfortunately, the datasource is not created and this is what I keep seeing:
[...]
javax.naming.NameNotFoundException: Name "jdbc/abcDS" not found.
at org.apache.openejb.core.ivm.naming.IvmContext.federate(IvmContext.java:193)
at org.apache.openejb.core.ivm.naming.IvmContext.lookup(IvmContext.java:150)
at org.apache.openejb.core.ivm.naming.IvmContext.lookup(IvmContext.java:124)
at org.apache.openejb.core.ivm.naming.ContextWrapper.lookup(ContextWrapper.java:115)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at com.XXX.FinderTest.startEJB(FinderTest.java:31)
[...]
What am I doing wrong? Please help!
ps. By the way it works this way (what's going on???):
ic.lookup("java:/openejb/Resource/jdbc/abcDS");
Should be found if you lookup openejb:Resource/jdbc/abcDS
As well you can get injection in your TestCase. Basically, you:
add an empty src/test/resources/META-INF/application-client.xml or ejb-jar.xml
Annotate your test with #LocalClient
Call initialContext.bind("inject", this)
See the testcase-injection example in the examples.zip
EDIT If the lookup still fails, post your log output (the console output).