views:

986

answers:

3

Hi all,

I've got a JUnit-test which is successfull when starting with mvn test but fails when starting from Eclipse (see stack trace below). What I'm trying to do is inserting new elements into the database with entityManager.persist() and entityManager.flush() (when calling flush, I get the error).

My config.properties looks the following:

db.url=jdbc:derby:target/testdb;create=true;territory=en_US;collation=TERRITORY_BASED
db.username=
db.password=

# Hibernate
hibernate.show_sql=true
hibernate.hbm2ddl.auto=create

With that configuration, my test fails in Eclipse, but runs with "mvn test"; if I remove the line "hibernate.hbm2ddl.auto=create", the test is successful from both, "mvn test" and Eclipse. When running the application, it works; it really only fails when running the JUnit-Test with "hibernate.hbm2ddl.auto=create" enabled.

In my Test-class, there's a setup-Method looking the following:

  @Before
  @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
  public void setUpDatabase() {
    final Resource deleteScript = applicationContext.getResource("delete.sql");
    final Resource insertScript = applicationContext.getResource("insert.sql");
    SimpleJdbcTestUtils.executeSqlScript(simpleJdbcTemplate, deleteScript, true);
    SimpleJdbcTestUtils.executeSqlScript(simpleJdbcTemplate, insertScript, false);
  }

delete.sql contains "delete from" statements, insert.sql inserts the statments again.

Java version 1.6.0_16, maven 2.1.0.

Any ideas?

Thanks a lot,

Stefan

javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not insert: [ch.netcetera.gisab.masterdata.model.security.RuleTarget]
    at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:614)
    at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:307)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:198)
    at $Proxy47.flush(Unknown Source)
    at ch.netcetera.gisab.masterdata.dao.RuleDAOImpl.updateRuleTargetsOfRule(RuleDAOImpl.java:84)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    at $Proxy72.updateRuleTargetsOfRule(Unknown Source)
    at ch.netcetera.gisab.masterdata.services.RoleServiceImpl.updateUserRoleTO(RoleServiceImpl.java:145)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    at $Proxy74.updateUserRoleTO(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
    at org.springframework.aop.interceptor.CustomizableTraceInterceptor.invokeUnderTrace(CustomizableTraceInterceptor.java:255)
    at org.springframework.aop.interceptor.AbstractTraceInterceptor.invoke(AbstractTraceInterceptor.java:110)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    at $Proxy74.updateUserRoleTO(Unknown Source)
    at ch.netcetera.gisab.masterdata.services.RoleServiceTest.testUpdateUserRoleTO(RoleServiceTest.java:140)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.test.context.junit4.SpringTestMethod.invoke(SpringTestMethod.java:160)
    at org.springframework.test.context.junit4.SpringMethodRoadie.runTestMethod(SpringMethodRoadie.java:233)
    at org.springframework.test.context.junit4.SpringMethodRoadie$RunBeforesThenTestThenAfters.run(SpringMethodRoadie.java:333)
    at org.springframework.test.context.junit4.SpringMethodRoadie.runWithRepetitions(SpringMethodRoadie.java:217)
    at org.springframework.test.context.junit4.SpringMethodRoadie.runTest(SpringMethodRoadie.java:197)
    at org.springframework.test.context.junit4.SpringMethodRoadie.run(SpringMethodRoadie.java:143)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.invokeTestMethod(SpringJUnit4ClassRunner.java:160)
    at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
    at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
    at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:97)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [ch.netcetera.gisab.masterdata.model.security.RuleTarget]
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:94)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2295)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2688)
    at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
    at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:304)
    ... 66 more
Caused by: java.sql.SQLIntegrityConstraintViolationException: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'SQL091001075326220' defined on 'RULETARGET'.
    at org.apache.derby.impl.jdbc.SQLExceptionFactory40.getSQLException(Unknown Source)
    at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source)
    at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(Unknown Source)
    at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(Unknown Source)
    at org.apache.derby.impl.jdbc.EmbedConnection.handleException(Unknown Source)
    at org.apache.derby.impl.jdbc.ConnectionChild.handleException(Unknown Source)
    at org.apache.derby.impl.jdbc.EmbedStatement.executeStatement(Unknown Source)
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement.executeStatement(Unknown Source)
    at org.apache.derby.impl.jdbc.EmbedPreparedStatement.executeUpdate(Unknown Source)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:102)
    at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:46)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2275)
    ... 75 more
Caused by: java.sql.SQLException: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'SQL091001075326220' defined on 'RULETARGET'.
    at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
    at org.apache.derby.impl.jdbc.SQLExceptionFactory40.wrapArgsForTransportAcrossDRDA(Unknown Source)
    ... 87 more
Caused by: ERROR 23505: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'SQL091001075326220' defined on 'RULETARGET'.
    at org.apache.derby.iapi.error.StandardException.newException(Unknown Source)
    at org.apache.derby.impl.sql.execute.IndexChanger.insertAndCheckDups(Unknown Source)
    at org.apache.derby.impl.sql.execute.IndexChanger.doInsert(Unknown Source)
    at org.apache.derby.impl.sql.execute.IndexChanger.insert(Unknown Source)
    at org.apache.derby.impl.sql.execute.IndexSetChanger.insert(Unknown Source)
    at org.apache.derby.impl.sql.execute.RowChangerImpl.insertRow(Unknown Source)
    at org.apache.derby.impl.sql.execute.InsertResultSet.normalInsertCore(Unknown Source)
    at org.apache.derby.impl.sql.execute.InsertResultSet.open(Unknown Source)
    at org.apache.derby.impl.sql.GenericPreparedStatement.execute(Unknown Source)
    ... 81 more

Edit:

I forgot: no error during startup, but during the failing test method, I get the following warning in the log:

2009-10-01 10:16:38,924 | main            | WARN  | JDBCExceptionReporter          | SQL Warning: 10000, SQLState: 01J01
2009-10-01 10:16:38,924 | main            | WARN  | JDBCExceptionReporter          | Database 'target/testdb' not created, connection made to existing database instead.
Hibernate: insert into RuleTarget (ruleid, targetid, type, version, id) values (?, ?, ?, ?, ?)
2009-10-01 10:16:38,939 | main            | WARN  | JDBCExceptionReporter          | SQL Error: 20000, SQLState: 23505
2009-10-01 10:16:38,939 | main            | ERROR | JDBCExceptionReporter          | The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'SQL091001101631840' defined on 'RULETARGET'.
2009-10-01 10:16:38,939 | main            | ERROR | AbstractFlushingEventListener  | Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: could not insert: [ch.netcetera.gisab.masterdata.model.security.RuleTarget]
A: 

What I've noticed that sometimes my unit test outputs change depending on the level of sandboxing done by the used testing tool. For example Eclipse seems to sandbox current selection(class, package, project) to a single setup-test-teardown cycle in same context while our CI seems to sandox every single unit test as setup-test-teardown cycle.

What this means is that if your test1 has a side effect which is then used in test2, it may work in Eclipse but it also may fail elsewhere. If this is the case, you need to rewrite your unit tests at least partly to decouple them from each other.

Esko
Thanks a lot for your answer...I thought about something like that; but if I run only that specific method out of Eclipse, it doesn't work either...
swalkner
A: 

My remarks/question:

  • when you remove line "hibernate.hbm2ddl.auto" - the default action is none
  • what base test class you use? Try extends class org.springframework.test.jpa.AbstractJpaTests - it does rollback after each method
  • from exception stack trace seems to tables aren't clean before inserts
  • where your database (file) is stored? Maybe maven build clean database file.
  • do you use any maven plugins that are run in maven and not in eclipse (like hibernate3-maven-plugin)?

EDIT: In my opinion test should be run in clean database and leave database clean, so each test/method should rollback after execution. Look at my qestion and responses. I think that using hibernate3-maven-plugin is optional.

cetnar
- my Test class extends AbstractTransactionalJUnit4SpringContextTests- database file is stored locally; maven clean didn't help...- most interesting: yes, hibernate3-maven is used!
swalkner
+2  A: 

Based on the SQLIntegrityConstraintViolationException it looks like your delete statements are not being executed, do you perhaps have two delete.sql files or not have src/test/resources configured as a source location in Eclipse?

The applicationContext.getResource("delete.sql") call will expect to find delete.sql in the output directory. In a Maven build the contents of src/test/resources will be copied to target/test-classes, this will only be done in an Eclipse build if the source location is defined.

The true at the end of the first executeSqlScript call means the process will continue without throwing an exception in the event of an error, so it may be that the resource is not found, and the delete statements not executed. If you run the build with the option set to false (and existing content) does it fail?

Note you can configure the Eclipse .classpath file to output test content to target/test-classes to avoid conflicts.

The steps to do this are:

  1. Open the project properties (alt-enter)
  2. Select**Java Build Path**
  3. Select the Source tab
  4. Click on Allow output folders for source folders. This adds a new entry to the source folder tree.
  5. Expand the source folder tree.
  6. Double-click on the Output folder: entry.
  7. A dialog asks you if you want to use the project's default output folder or a specific output folder. Choose the second option and click Browse...
  8. Select the folder you want and click OK and then Finish.

You should end up with the following entries in the .classpath file:

<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
Rich Seller
Thanks a lot for that information!I checked - there's only one delete.sql-file and while debugging it becomes clear that it's really found.
swalkner
Dude! Thanks very much for this!
Sergio Oliveira Jr.