I am testing a Spring Boot Batch Application. I am using a in memory H2 DB that I would like to initialize with some data but its failing with a Unique index or primary key violation: PRIMARY_KEY_7 ON ...
.
I have tried tweaking the application.properties
, adding and removing
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.default_schema=AD1
Also tweaking the spring.datasource.url
.
The entity is as follows:
@Table(schema = "ad1",name = "Student")
public class Student {
@Id
@Column(name = "student_id")
private String studentId;
@Column(name = "student_name")
private String studentName;
@Column(name = "favourite_subject")
private String favouriteSubject;
@Column(name = "enrollment_date")
private LocalDate enrollmentDate;
}
To note is that the schema
attribute has been set to ad1
data-h2.sql
which lives in src/test/resources
is as follows:
Insert into ad1.Student (student_id,student_name,favourite_subject,enrollment_date) values ('1151AB26','John','Math',to_date('01-JAN-19','DD-MON-RR'));
application.properties
also in src/test/resources
is as follows:
spring.datasource.platform=h2
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=Oracle;INIT=CREATE SCHEMA IF NOT EXISTS AD1
spring.datasource.username=sa
spring.datasource.password=sa
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.properties.hibernate.default_schema=AD1
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.batch.job.enabled=false
To note, is that spring.datasource.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=Oracle;INIT=CREATE SCHEMA IF NOT EXISTS AD1
. I had to initialize the schema to AD1
I am using Cucumber so I have a a cucumber test class:
@RunWith(Cucumber.class)
@CucumberOptions(features = "src/test/resources", plugin = { "pretty", "html:target/cucumber" })
public class CucumberTest {
}
Last but not least the Spring boot test class
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = StudentBatchApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration
public abstract class SpringCucumberIntegrationTest {
What happens is that when I start up the test I get the following:
Caused by: org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "PRIMARY_KEY_7 ON AD1.Student(student_id) VALUES ('1151AB26', 1)"; SQL statement:
Insert into AD1.Student (student_id,student_name,favourite_subject,enrollment_date) values ('1151AB26','John','Math',to_date('01-JAN-19','DD-MON-RR')) [23505-197]
When I troubleshoot this, by putting a break-point at the moment the initialization is happening, the process runs the same line twice:
( /* key:1 */ '1151AB26', 'John', 'Math', TIMESTAMP '2019-01-01 00:00:00')
( /* key:2 */ '1151AB26', 'John', 'Math', TIMESTAMP '2019-01-01 00:00:00')
Right after this, it throws the exception.
As I mentioned, in the process of troubleshooting I noticed that the one line inside data-h2.sql
was somehow being ran twice and hence giving this Unique index violation. Troubleshooting further, I traced back to the point in the process where it was loading the data script (ie. data-h2.sql
) and noticed that it was loading this script twice. Once in target\classes\data-h2.sql
and once in target\test-classes\data-h2.sql
. I honestly don't know why this script file was being copied to target\classes\data-h2.sql
.
In the end I found that this was an eclipse issue. When I ran the tests using command-line mvn clean test
. The tests ran perfectly, but when I ran the tests with eclipse Run As -> JUnit Test
I would encounter this problem. For some reason whenever I cleaned the application in eclipse Project -> Clean
it copied all the resource files from src/main/resources
and src/test/resources
into target\classes
. What I had to do was add the following line to my .classpath
file.
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>