Related
I have very simple spring boot 1.4 application with one rest controller. When i tried to test the context loading of this i am getting error like below :-
13:29:03.623 [main] DEBUG o.s.t.c.j.SpringJUnit4ClassRunner - SpringJUnit4ClassRunner constructor called with [class com.byteobject.cloudsanthe.frontendservice.FrontendServiceApplicationTests]
13:29:03.628 [main] DEBUG o.s.test.context.BootstrapUtils - Instantiating CacheAwareContextLoaderDelegate from class [org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate]
13:29:03.632 [main] DEBUG o.s.test.context.BootstrapUtils - Instantiating BootstrapContext using constructor [public org.springframework.test.context.support.DefaultBootstrapContext(java.lang.Class,org.springframework.test.context.CacheAwareContextLoaderDelegate)]
13:29:03.641 [main] DEBUG o.s.test.context.BootstrapUtils - Instantiating TestContextBootstrapper for test class [com.byteobject.cloudsanthe.frontendservice.FrontendServiceApplicationTests] from class [org.springframework.boot.test.context.SpringBootTestContextBootstrapper]
13:29:03.644 [main] INFO o.s.b.t.c.SpringBootTestContextBootstrapper - Neither #ContextConfiguration nor #ContextHierarchy found for test class [com.byteobject.cloudsanthe.frontendservice.FrontendServiceApplicationTests]
13:29:03.650 [main] DEBUG o.s.b.t.c.SpringBootTestContextBootstrapper - #TestExecutionListeners is not present for class [com.byteobject.cloudsanthe.frontendservice.FrontendServiceApplicationTests]: using defaults.
13:29:03.659 [main] INFO o.s.b.t.c.SpringBootTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener, org.springframework.boot.test.autoconfigure.AutoConfigureReportTestExecutionListener, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener, org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
13:29:03.667 [main] INFO o.s.b.t.c.SpringBootTestContextBootstrapper - Could not instantiate TestExecutionListener [org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [org/springframework/transaction/interceptor/TransactionAttribute]
13:29:03.671 [main] INFO o.s.b.t.c.SpringBootTestContextBootstrapper - Could not instantiate TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [org/springframework/transaction/interceptor/TransactionAttributeSource]
13:29:03.672 [main] INFO o.s.b.t.c.SpringBootTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener#2db7a79b, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener#6950e31, org.springframework.boot.test.autoconfigure.AutoConfigureReportTestExecutionListener#b7dd107, org.springframework.test.context.support.DependencyInjectionTestExecutionListener#42eca56e, org.springframework.test.context.support.DirtiesContextTestExecutionListener#52f759d7, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener#7cbd213e, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener#192d3247, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener#3ecd23d9, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener#569cfc36]
13:29:03.674 [main] DEBUG o.s.t.annotation.ProfileValueUtils - Retrieved #ProfileValueSourceConfiguration [null] for test class [com.byteobject.cloudsanthe.frontendservice.FrontendServiceApplicationTests]
13:29:03.674 [main] DEBUG o.s.t.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [com.byteobject.cloudsanthe.frontendservice.FrontendServiceApplicationTests]
13:29:03.690 [main] DEBUG o.s.t.annotation.ProfileValueUtils - Retrieved #ProfileValueSourceConfiguration [null] for test class [com.byteobject.cloudsanthe.frontendservice.FrontendServiceApplicationTests]
13:29:03.690 [main] DEBUG o.s.t.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [com.byteobject.cloudsanthe.frontendservice.FrontendServiceApplicationTests]
13:29:03.691 [main] DEBUG o.s.t.annotation.ProfileValueUtils - Retrieved #ProfileValueSourceConfiguration [null] for test class [com.byteobject.cloudsanthe.frontendservice.FrontendServiceApplicationTests]
13:29:03.691 [main] DEBUG o.s.t.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [com.byteobject.cloudsanthe.frontendservice.FrontendServiceApplicationTests]
13:29:03.692 [main] DEBUG o.s.t.annotation.ProfileValueUtils - Retrieved #ProfileValueSourceConfiguration [null] for test class [com.byteobject.cloudsanthe.frontendservice.FrontendServiceApplicationTests]
13:29:03.692 [main] DEBUG o.s.t.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [com.byteobject.cloudsanthe.frontendservice.FrontendServiceApplicationTests]
13:29:03.695 [main] DEBUG o.s.t.c.s.AbstractDirtiesContextTestExecutionListener - Before test class: context [DefaultTestContext#67b467e9 testClass = FrontendServiceApplicationTests, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration#47db50c5 testClass = FrontendServiceApplicationTests, locations = '{}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextLoader = 'null', parent = [null]]], class annotated with #DirtiesContext [false] with mode [null].
13:29:03.696 [main] DEBUG o.s.t.annotation.ProfileValueUtils - Retrieved #ProfileValueSourceConfiguration [null] for test class [com.byteobject.cloudsanthe.frontendservice.FrontendServiceApplicationTests]
13:29:03.696 [main] DEBUG o.s.t.annotation.ProfileValueUtils - Retrieved ProfileValueSource type [class org.springframework.test.annotation.SystemProfileValueSource] for class [com.byteobject.cloudsanthe.frontendservice.FrontendServiceApplicationTests]
13:29:03.697 [main] DEBUG o.s.t.c.s.DependencyInjectionTestExecutionListener - Performing dependency injection for test context [[DefaultTestContext#67b467e9 testClass = FrontendServiceApplicationTests, testInstance = com.byteobject.cloudsanthe.frontendservice.FrontendServiceApplicationTests#548ad73b, testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration#47db50c5 testClass = FrontendServiceApplicationTests, locations = '{}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextLoader = 'null', parent = [null]]]].
13:29:03.699 [main] ERROR o.s.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.boot.test.autoconfigure.AutoConfigureReportTestExecutionListener#b7dd107] to prepare test instance [com.byteobject.cloudsanthe.frontendservice.FrontendServiceApplicationTests#548ad73b]
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
at org.springframework.boot.test.autoconfigure.AutoConfigureReportTestExecutionListener.prepareTestInstance(AutoConfigureReportTestExecutionListener.java:49)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:228)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:230)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:249)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:193)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: java.lang.IllegalArgumentException: Cannot load an ApplicationContext with a NULL 'contextLoader'. Consider annotating your test class with #ContextConfiguration or #ContextHierarchy.
at org.springframework.util.Assert.notNull(Assert.java:115)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:91)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
... 24 common frames omitted
13:29:03.705 [main] DEBUG o.s.t.c.s.AbstractDirtiesContextTestExecutionListener - After test class: context [DefaultTestContext#67b467e9 testClass = FrontendServiceApplicationTests, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration#47db50c5 testClass = FrontendServiceApplicationTests, locations = '{}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextLoader = 'null', parent = [null]]], class annotated with #DirtiesContext [false] with mode [null].
test class is :-
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
public class FrontendServiceApplicationTests {
#Test
public void contextLoads() {
}
}
And application class is :-
#SpringBootApplication
#ImportResource({"classpath:dbContext.xml", "classpath:dbClientMappingContext.xml"})
public class FrontendServiceApplication {
/**
* The main method.
*
* #param args the arguments
*/
public static void main(String[] args) {
SpringApplication.run(FrontendServiceApplication.class, args);
}
}
What i am doing wrong here?
It looks like Spring Boot cannot find your #SpringBootApplication class using classpath scanning.
So give the following a try:
#RunWith(SpringRunner.class)
#SpringBootTest(
classes = FrontendServiceApplication.class,
webEnvironment = WebEnvironment.RANDOM_PORT
)
public class FrontendServiceApplicationTests {
#Test
public void contextLoads() {
}
}
I'm using Spring Boot 1.3.3.RELEASE with Spring Batch 3.0.6.RELEASE and am having trouble getting Spring Batch/Spring Boot to not auto-start my jobs.
This question is similar to how to stop spring batch scheduled jobs from running at first time when executing the code?
I have the following test class:
#RunWith(SpringJUnit4ClassRunner.class)
#Configuration
#ComponentScan(useDefaultFilters = false,
includeFilters = #ComponentScan.Filter(value = GetMarkerViaSpringBatchApplicationTest.class,
type = FilterType.ASSIGNABLE_TYPE) )
#EnableBatchProcessing
//#IntegrationTest({"spring.batch.job.enabled=false"})
#EnableAutoConfiguration
#TestPropertySource(
locations = {"classpath:env.properties", "classpath:application.properties", "classpath:database.properties"},
properties = {"spring.batch.job.enabled=false"})
#SpringApplicationConfiguration(classes = {GetMarkerViaSpringBatchApplicationTest.class},
locations = {"classpath:**/GetMarkerViaSpringBatchApplicationTest-context.xml"})
public class GetMarkerViaSpringBatchApplicationTest {
#Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
#Test
public void testLaunchJob() throws Exception {
JobExecution jobExecution = jobLauncherTestUtils.launchJob();
assertThat(jobExecution.getStatus()).isEqualTo(BatchStatus.COMPLETED);
}
}
In the same directory (package) as the test class I have config file GetMarkerViaSpringBatchApplicationTest-context.xml.
GetMarkerViaSpringBatchApplicationTest-context.xml contents:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:batch="http://www.springframework.org/schema/batch"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<import resource="classpath:/META-INF/spring/get-marker-job-new.xml" />
<bean id="jobLauncherTestUtils" class="org.springframework.batch.test.JobLauncherTestUtils" />
<bean id="batchConfigurer" class="org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer">
<constructor-arg name="dataSource" ref="hsqlDataSource" />
</bean>
</beans>
get-marker-job-new.xml contents:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:batch="http://www.springframework.org/schema/batch" xmlns:task="http://www.springframework.org/schema/task"
xmlns:file="http://www.springframework.org/schema/integration/file" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/file http://www.springframework.org/schema/integration/file/spring-integration-file.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<import resource="classpath:META-INF/spring/application-context.xml" />
<import resource="classpath:META-INF/spring/database.xml" />
<!-- The #EnableBatchProcessing on the main class sets up: job-repository, jobLauncher, and jobRepository -->
<!-- Spring Boot with Spring Batch doesn't like multiple DataSources since it doesn't know which one -->
<!-- to pick for Spring Batch. This class will therefore coerce to pick the proper HSQL dataSource. -->
<!-- See https://stackoverflow.com/questions/25540502/use-of-multiple-datasources-in-spring-batch -->
<bean id="batchConfigurer" class="org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer">
<constructor-arg name="dataSource" ref="hsqlDataSource" />
</bean>
<bean id="foo" class="myClass" />
<bean id="myTasklet" class="org.springframework.batch.core.step.tasklet.MethodInvokingTaskletAdapter">
<property name="targetObject" ref="myClass" />
<property name="targetMethod" value="deliver" />
</bean>
<batch:job id="batchJob" restartable="false">
<batch:step id="step1">
<batch:tasklet ref="myTasklet"/>
</batch:step>
</batch:job>
</beans>
application-context.xml contents:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
xmlns:oxm="http://www.springframework.org/schema/oxm" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd
http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<import resource="classpath:META-INF/spring/database.xml" />
<!-- load properties from config files -->
<context:property-placeholder location="classpath:env.properties,classpath:application.properties,classpath:database.properties" />
<bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
</beans>
database.xml contents:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
<bean id="myDataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.myco.driverClassName}" />
<property name="username" value="${jdbc.myco.username}" />
<property name="password" value="${jdbc.myco.encpassword}" />
<property name="jdbcUrl" value="${jdbc.myco.url}" />
<property name="maximumPoolSize" value="${jdbc.myco.pool.maxactive}" />
</bean>
<alias alias="dataSource" name="myDataSource" />
<bean id="hsqlDataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close" primary="true">
<property name="driverClassName" value="${jdbc.hsqldb.driverClassName}" />
<property name="username" value="${jdbc.hsqldb.username}" />
<property name="password" value="${jdbc.hsqldb.password}" />
<property name="jdbcUrl" value="${jdbc.hsqldb.url}" />
<property name="maximumPoolSize" value="${jdbc.hsqldb.pool.maxactive}" />
</bean>
</beans>
application.properties (in root dir which is also in the classpath):
spring.datasource.platform=sqlserver
spring.profiles.active=local
spring.batch.job.enabled=true
spring.batch.initializer.enabled=true
spring.batch.schema=classpath:org/springframework/batch/core/schema-hsqldb.sql
Note that spring.batch.job.enabled=true in the application.properties but false in the #IntegrationTest and the #TestPropertySource.
Whenever I set spring.batch.job.enabled=true in the application.properties regardless of trying various combos of spring.batch.job.enabled=false in the #IntegrationTest and the #TestPropertySource whenever I run this test the job is getting kicked off before the jobLauncherTestUtils.launchJob() gets called.
Logs from the run:
15:52:49,083 (o.s.test.context.support.AbstractDirtiesContextTestExecutionListener) - Before test class: context [DefaultTestContext#1733f619 testClass = GetMarkerViaSpringBatchApplicationTest, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration#5461ef35 testClass = GetMarkerViaSpringBatchApplicationTest, locations = '{classpath:**/GetMarkerViaSpringBatchApplicationTest-context.xml}', classes = '{class xxx.myco.batch.client.GetMarkerViaSpringBatchApplicationTest}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{classpath:env.properties, classpath:application.properties, classpath:database.properties}', propertySourceProperties = '{spring.batch.job.enabled=false, marker=SELC_ALPHA_DONE, marker_date=2016/06/21, interval=1, times=1, is_fail=true, fail_path=${pkg.out}\\failed_alpha_report}', contextLoader = 'o.s.boot.test.SpringApplicationContextLoader', parent = [null]]], class annotated with #DirtiesContext [false] with mode [null].
15:52:49,099 (o.s.test.context.support.DependencyInjectionTestExecutionListener) - Performing dependency injection for test context [[DefaultTestContext#1733f619 testClass = GetMarkerViaSpringBatchApplicationTest, testInstance = xxx.myco.batch.client.GetMarkerViaSpringBatchApplicationTest#6769360f, testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration#5461ef35 testClass = GetMarkerViaSpringBatchApplicationTest, locations = '{classpath:**/GetMarkerViaSpringBatchApplicationTest-context.xml}', classes = '{class xxx.myco.batch.client.GetMarkerViaSpringBatchApplicationTest}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{classpath:env.properties, classpath:application.properties, classpath:database.properties}', propertySourceProperties = '{spring.batch.job.enabled=false, marker=SELC_ALPHA_DONE, marker_date=2016/06/21, interval=1, times=1, is_fail=true, fail_path=${pkg.out}\\failed_alpha_report}', contextLoader = 'o.s.boot.test.SpringApplicationContextLoader', parent = [null]]]].
15:52:50,572 (o.s.core.env.PropertySourcesPropertyResolver) - Searching for key 'spring.batch.job.enabled' in [class path resource [database.properties]]
15:52:50,572 (o.s.core.env.PropertySourcesPropertyResolver) - Searching for key 'spring.batch.job.enabled' in [class path resource [application.properties]]
15:52:50,572 (o.s.core.env.PropertySourcesPropertyResolver) - Found key 'spring.batch.job.enabled' in [class path resource [application.properties]] with type [String] and value 'false'
15:52:50,665 (o.s.core.env.PropertySourcesPropertyResolver) - Searching for key 'spring.batch.job.enabled' in [class path resource [database.properties]]
15:52:50,665 (o.s.core.env.PropertySourcesPropertyResolver) - Searching for key 'spring.batch.job.enabled' in [class path resource [application.properties]]
15:52:50,665 (o.s.core.env.PropertySourcesPropertyResolver) - Found key 'spring.batch.job.enabled' in [class path resource [application.properties]] with type [String] and value 'false'
15:52:50,665 (o.s.core.env.PropertySourcesPropertyResolver) - Searching for key 'spring.batch.job.enabled' in [class path resource [database.properties]]
15:52:50,665 (o.s.core.env.PropertySourcesPropertyResolver) - Searching for key 'spring.batch.job.enabled' in [class path resource [application.properties]]
15:52:50,665 (o.s.core.env.PropertySourcesPropertyResolver) - Found key 'spring.batch.job.enabled' in [class path resource [application.properties]] with type [String] and value 'false'
15:52:52,132 (o.s.core.env.PropertySourcesPropertyResolver) - Searching for key 'spring.batch.job.enabled' in [class path resource [database.properties]]
15:52:52,132 (o.s.core.env.PropertySourcesPropertyResolver) - Searching for key 'spring.batch.job.enabled' in [class path resource [application.properties]]
15:52:52,132 (o.s.core.env.PropertySourcesPropertyResolver) - Found key 'spring.batch.job.enabled' in [class path resource [application.properties]] with type [String] and value 'false'
15:53:00,861 (o.s.core.env.PropertySourcesPropertyResolver) - Searching for key 'spring.batch.job.enabled' in [class path resource [database.properties]]
15:53:00,861 (o.s.core.env.PropertySourcesPropertyResolver) - Searching for key 'spring.batch.job.enabled' in [class path resource [application.properties]]
15:53:00,861 (o.s.core.env.PropertySourcesPropertyResolver) - Found key 'spring.batch.job.enabled' in [class path resource [application.properties]] with type [String] and value 'false'
15:53:00,861 (o.s.core.env.PropertySourcesPropertyResolver) - Searching for key 'spring.batch.job.enabled' in [class path resource [database.properties]]
15:53:00,861 (o.s.core.env.PropertySourcesPropertyResolver) - Searching for key 'spring.batch.job.enabled' in [class path resource [application.properties]]
15:53:00,861 (o.s.core.env.PropertySourcesPropertyResolver) - Found key 'spring.batch.job.enabled' in [class path resource [application.properties]] with type [String] and value 'false'
15:53:00,861 (o.s.core.env.PropertySourcesPropertyResolver) - Searching for key 'spring.batch.job.enabled' in [class path resource [database.properties]]
15:53:00,861 (o.s.core.env.PropertySourcesPropertyResolver) - Searching for key 'spring.batch.job.enabled' in [class path resource [application.properties]]
15:53:00,861 (o.s.core.env.PropertySourcesPropertyResolver) - Found key 'spring.batch.job.enabled' in [class path resource [application.properties]] with type [String] and value 'false'
15:53:00,876 (o.s.core.env.PropertySourcesPropertyResolver) - Searching for key 'spring.batch.job.enabled' in [class path resource [database.properties]]
15:53:00,876 (o.s.core.env.PropertySourcesPropertyResolver) - Searching for key 'spring.batch.job.enabled' in [class path resource [application.properties]]
15:53:00,876 (o.s.core.env.PropertySourcesPropertyResolver) - Found key 'spring.batch.job.enabled' in [class path resource [application.properties]] with type [String] and value 'false'
...
BatchAutoConfiguration#jobExplorer did not match
- #ConditionalOnMissingBean (types: o.s.batch.core.explore.JobExplorer; SearchStrategy: all) found the following [jobExplorer] (OnBeanCondition)
BatchAutoConfiguration#jobLauncherCommandLineRunner did not match
- #ConditionalOnMissingBean (types: o.s.boot.autoconfigure.batch.JobLauncherCommandLineRunner; SearchStrategy: all) found no beans (OnBeanCondition)
- #ConditionalOnProperty expected 'true' for properties spring.batch.job.enabled (OnPropertyCondition)
BatchAutoConfiguration.JpaBatchConfiguration did not match
- required #ConditionalOnClass classes not found: javax.persistence.EntityManagerFactory (OnClassCondition)
...
15:53:02,225 (o.s.test.context.cache.DefaultCacheAwareContextLoaderDelegate) - Storing ApplicationContext in cache under key [[MergedContextConfiguration#5461ef35 testClass = GetMarkerViaSpringBatchApplicationTest, locations = '{classpath:**/GetMarkerViaSpringBatchApplicationTest-context.xml}', classes = '{class xxx.myco.batch.client.GetMarkerViaSpringBatchApplicationTest}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{classpath:env.properties, classpath:application.properties, classpath:database.properties}', propertySourceProperties = '{spring.batch.job.enabled=false, marker=SELC_ALPHA_DONE, marker_date=2016/06/21, interval=1, times=1, is_fail=true, fail_path=${pkg.out}\\failed_alpha_report}', contextLoader = 'o.s.boot.test.SpringApplicationContextLoader', parent = [null]]]
15:53:02,256 (o.s.test.context.support.AbstractDirtiesContextTestExecutionListener) - Before test method: context [DefaultTestContext#1733f619 testClass = GetMarkerViaSpringBatchApplicationTest, testInstance = xxx.myco.batch.client.GetMarkerViaSpringBatchApplicationTest#6769360f, testMethod = testLaunchJob#GetMarkerViaSpringBatchApplicationTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration#5461ef35 testClass = GetMarkerViaSpringBatchApplicationTest, locations = '{classpath:**/GetMarkerViaSpringBatchApplicationTest-context.xml}', classes = '{class xxx.myco.batch.client.GetMarkerViaSpringBatchApplicationTest}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{classpath:env.properties, classpath:application.properties, classpath:database.properties}', propertySourceProperties = '{spring.batch.job.enabled=false, marker=SELC_ALPHA_DONE, marker_date=2016/06/21, interval=1, times=1, is_fail=true, fail_path=${pkg.out}\\failed_alpha_report}', contextLoader = 'o.s.boot.test.SpringApplicationContextLoader', parent = [null]]], class annotated with #DirtiesContext [false] with mode [null], method annotated with #DirtiesContext [false] with mode [null].
15:53:04,669 (o.s.test.context.support.AbstractDirtiesContextTestExecutionListener) - After test method: context [DefaultTestContext#1733f619 testClass = GetMarkerViaSpringBatchApplicationTest, testInstance = xxx.myco.batch.client.GetMarkerViaSpringBatchApplicationTest#6769360f, testMethod = testLaunchJob#GetMarkerViaSpringBatchApplicationTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration#5461ef35 testClass = GetMarkerViaSpringBatchApplicationTest, locations = '{classpath:**/GetMarkerViaSpringBatchApplicationTest-context.xml}', classes = '{class xxx.myco.batch.client.GetMarkerViaSpringBatchApplicationTest}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{classpath:env.properties, classpath:application.properties, classpath:database.properties}', propertySourceProperties = '{spring.batch.job.enabled=false, marker=SELC_ALPHA_DONE, marker_date=2016/06/21, interval=1, times=1, is_fail=true, fail_path=${pkg.out}\\failed_alpha_report}', contextLoader = 'o.s.boot.test.SpringApplicationContextLoader', parent = [null]]], class annotated with #DirtiesContext [false] with mode [null], method annotated with #DirtiesContext [false] with mode [null].
15:53:04,685 (o.s.test.context.support.AbstractDirtiesContextTestExecutionListener) - After test class: context [DefaultTestContext#1733f619 testClass = GetMarkerViaSpringBatchApplicationTest, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration#5461ef35 testClass = GetMarkerViaSpringBatchApplicationTest, locations = '{classpath:**/GetMarkerViaSpringBatchApplicationTest-context.xml}', classes = '{class xxx.myco.batch.client.GetMarkerViaSpringBatchApplicationTest}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{classpath:env.properties, classpath:application.properties, classpath:database.properties}', propertySourceProperties = '{spring.batch.job.enabled=false, marker=SELC_ALPHA_DONE, marker_date=2016/06/21, interval=1, times=1, is_fail=true, fail_path=${pkg.out}\\failed_alpha_report}', contextLoader = 'o.s.boot.test.SpringApplicationContextLoader', parent = [null]]], class annotated with #DirtiesContext [false] with mode [null].
I've read http://forum.spring.io/forum/spring-projects/batch/748038-i-do-not-want-enablebatchprocessing-to-launch-a-job and how to stop spring batch scheduled jobs from running at first time when executing the code? but can't seem to get the jobLauncher to NOT auto-start.
My understanding is that application.properties properties should be overriden by the 2 places I'm trying to set this directly within the Test but BatchAutoConfiguration doesn't seem to honor that override.
If I set spring.batch.job.enabled=false (or comment that property out) in the application.properties and try to drive it from either #IntegrationTest or #TestPropertySource it behaves as expected.
Is my understanding of the overriding of values incorrect?
Any help would be appreciated.
If you add application.properties to #TestPropertySource then it ends up overriding the other stuff. You don't need it there if you are using spring boot.
I am starting a project using Spring 3.2.1.RELEASE, Hibernate 4.1.9.FINAL as jpa provider, spring data 1.2.0.RELEASE for repository and bitronix 2.1.3 as transaction manager. I am new to all of these technologies so I'm sorry if I'm missing some huge point.
I am running a simple unit test to create a User object in a database:
#ContextConfiguration(locations={"classpath:tests-context.xml"})
#Transactional
#TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false)
#RunWith(SpringJUnit4ClassRunner.class)
public class UserTest extends AbstractTransactionalJUnit4SpringContextTests
{
#Autowired
protected UserMgmtService userService;
#Test
public void createUserTest()
{
User user = new User();
user.setFirstName("jonny");
user.setLastName("doe");
user.setUsername("user5");
user.setPasswordHash("1238");
user.setEmail("user5#domain.com");
System.out.println("Created user" + user);
User testUser = userService.saveUser(user);
System.out.println("Saved user" + testUser);
Assert.assertEquals("The user should be equal to saved user", user, testUser);
}
}
My test-context.xml used is as follows:
<context:annotation-config/>
<!-- Bitronix Transaction Manager embedded configuration -->
<bean id="btmConfig" factory-method="getConfiguration"
class="bitronix.tm.TransactionManagerServices">
</bean>
<!-- DataSource definition -->
<bean id="dataSource" class="bitronix.tm.resource.jdbc.PoolingDataSource"
init-method="init" destroy-method="close">
<property name="className" value="bitronix.tm.resource.jdbc.lrc.LrcXADataSource" />
<property name="uniqueName" value="jdbc/MySQL_Test_Repository" />
<property name="minPoolSize" value="0" />
<property name="maxPoolSize" value="5" />
<property name="allowLocalTransactions" value="true" />
<property name="driverProperties">
<props>
<prop key="driverClassName">com.mysql.jdbc.Driver</prop>
<prop key="url">jdbc:mysql://localhost:3306 MySQL_Test_Repository</prop>
<prop key="user">root</prop>
<prop key="password">123654</prop>
</props>
</property>
</bean>
<!-- create BTM transaction manager -->
<bean id="BitronixTransactionManager" factory-method="getTransactionManager"
class="bitronix.tm.TransactionManagerServices" depends-on="btmConfig,dataSource"
destroy-method="shutdown" />
<!-- Transaction manager -->
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"
depends-on="BitronixTransactionManager">
<property name="transactionManager" ref="BitronixTransactionManager" />
<property name="userTransaction" ref="BitronixTransactionManager" />
<property name="allowCustomIsolationLevels" value="true" />
</bean>
<!-- AOP configuration for transactions -->
<aop:config>
<aop:pointcut id="userServiceMethods"
expression="execution(* users.service.UserMgmtService.*(..))" />
<aop:advisor advice-ref="transactionAdvice"
pointcut-ref="userServiceMethods" />
</aop:config>
<!-- Transaction configuration -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" rollback-for="Exception" />
</tx:attributes>
</tx:advice>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- bean declaring the property map for the entity manager factory bean -->
<bean id="jpaPropertyMap" class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="sourceMap">
<map>
<entry key="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
<!-- show the sql code executed -->
<entry key="hibernate.show_sql" value="true"/>
<!-- format the shown sql code -->
<entry key="hibernate.format_sql" value="true"/>
<!-- enables hibernate to create db schemas from classes;
Possible values: validate | update | create | create-drop
with create-drop the schema will be created/dropped for each hibernate sesssion open/close-->
<entry key="hibernate.hbm2ddl.auto" value="update"/>
<!-- sets the hibernate classname for the TransactionManagerLookup;
hibernate wraps and hides the underlying transaction system and needs a reference
to the transaction manager used -->
<entry key="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory"/>
<entry key="hibernate.transaction.manager_lookup_class"
value="org.hibernate.transaction.BTMTransactionManagerLookup"/>
</map>
</property>
</bean>
<!-- bean declaring the entity manager factory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="ruleEditor.persistence"/>
<property name="dataSource" ref="dataSource" />
<property name="jpaPropertyMap" ref="jpaPropertyMap"/>
</bean>
<!-- The location where Spring scans for interfaces implementing the JPARepository
and creates their implementation -->
<jpa:repositories base-package="users.repository" />
<!-- Persistence annotations for post processing -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<!-- User service implementation bean -->
<bean id="userMgmtService" class="users.service.impl.UserMgmtServiceImpl"/>
</beans>
The Repository implementation is a standard JPARepository:
public interface UserRepository extends JpaRepository<User, Long>
{
User findByUsername(String username);
}
And the service implementation only makes calls to the repository:
#Service("userMgmtService")
public class UserMgmtServiceImpl implements UserMgmtService
{
#Autowired
private UserRepository userRepository;
#Override
public User saveUser(User user)
{
User savedUser = userRepository.save(user);
return savedUser;
}
The problem is that when I execute the test, it passes, but no user is created in the database. I thought it might be because of the Rollback behavior so I set the defaultRollback=false in the User test. Here is some information provided by the transaction framework when set to DEBUG that might be relevant:
Running UserTest
2013-02-12 13:01:12 INFO XmlBeanDefinitionReader:315 - Loading XML bean definitionsfrom class path resource [tests-context.xml]
2013-02-12 13:01:12 INFO GenericApplicationContext:510 - Refreshing org.springframework.context.support.GenericApplicationContext#7d95609: startup date [Tue Feb 12 13:01:12 CET 2013]; root of context hierarchy
2013-02-12 13:01:12 INFO GenericApplicationContext:1374 - Bean 'dataSource' of type [class bitronix.tm.resource.jdbc.PoolingDataSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:12 INFO GenericApplicationContext:1374 - Bean 'jpaPropertyMap' of type [class org.springframework.beans.factory.config.MapFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:12 INFO GenericApplicationContext:1374 - Bean 'jpaPropertyMap' of type [class java.util.LinkedHashMap] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:12 INFO LocalContainerEntityManagerFactoryBean:264 - Building JPA container EntityManagerFactory for persistence unit 'ruleEditor.persistence'
2013-02-12 13:01:13 INFO SchemaUpdate:182 - HHH000228: Running hbm2ddl schema update
2013-02-12 13:01:13 INFO SchemaUpdate:193 - HHH000102: Fetching database metadata
2013-02-12 13:01:13 INFO SchemaUpdate:205 - HHH000396: Updating schema
2013-02-12 13:01:13 INFO TableMetadata:65 - HHH000261: Table found: MySQL_Test_Repository.user
2013-02-12 13:01:13 INFO TableMetadata:66 - HHH000037: Columns: [id, enabled, first_name, username, email, password_hash, last_name]
2013-02-12 13:01:13 INFO TableMetadata:68 - HHH000108: Foreign keys: []
2013-02-12 13:01:13 INFO TableMetadata:69 - HHH000126: Indexes: [id, username, primary]
2013-02-12 13:01:13 INFO SchemaUpdate:240 - HHH000232: Schema update complete
2013-02-12 13:01:13 INFO BitronixTransactionManager:390 - Bitronix Transaction Manager version 2.1.3
2013-02-12 13:01:13 WARN Configuration:649 - cannot get this JVM unique ID. Make sure it is configured and you only use ASCII characters. Will use IP address instead (unsafe for production usage!).
2013-02-12 13:01:13 INFO Recoverer:152 - recovery committed 0 dangling transaction(s) and rolled back 0 aborted transaction(s) on 1 resource(s) [jdbc/MySQL_Test_Repository]
2013-02-12 13:01:14 INFO GenericApplicationContext:1374 - Bean 'entityManagerFactory' of type [class org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:14 INFO GenericApplicationContext:1374 - Bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0' of type [class org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:14 INFO GenericApplicationContext:1374 - Bean 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0' of type [class org.springframework.transaction.annotation.AnnotationTransactionAttributeSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:14 INFO GenericApplicationContext:1374 - Bean 'org.springframework.transaction.config.internalTransactionAdvisor' of type [class org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2013-02-12 13:01:14 INFO JtaTransactionManager:470 - Using JTA UserTransaction: a BitronixTransactionManager with 0 in-flight transaction(s)
2013-02-12 13:01:14 INFO JtaTransactionManager:481 - Using JTA TransactionManager: a BitronixTransactionManager with 0 in-flight transaction(s)
2013-02-12 13:01:14 DEBUG NameMatchTransactionAttributeSource:94 - Adding transactional method [*] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception]
2013-02-12 13:01:14 DEBUG AnnotationTransactionAttributeSource:106 - Adding transactional method 'createUserTest' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2013-02-12 13:01:14 DEBUG AnnotationTransactionAttributeSource:106 - Adding transactional method 'createUserTest' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2013-02-12 13:01:14 DEBUG JtaTransactionManager:365 - Creating new transaction with name [createUserTest]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2013-02-12 13:01:14 INFO TransactionalTestExecutionListener:279 - Began transaction (1): transaction manager [org.springframework.transaction.jta.JtaTransactionManager#2a3998f8]; rollback [false]
Created userusers.model.User#63aa9dc1[userId=0,first name=jonny,last name=doe,email=user5#domain.com,username=user5,password=1238,enabled=false]
2013-02-12 13:01:14 DEBUG JtaTransactionManager:470 - Participating in existing transaction
2013-02-12 13:01:14 DEBUG JtaTransactionManager:470 - Participating in existing transaction
Saved userusers.model.User#6b38579e[userId=0,first name=jonny,last name=doe,email=user5#domain.com,username=user5,password=1238,enabled=false]
2013-02-12 13:01:14 DEBUG JtaTransactionManager:752 - Initiating transaction commit
2013-02-12 13:01:14 WARN Preparer:69 - executing transaction with 0 enlisted resource
2013-02-12 13:01:14 INFO TransactionalTestExecutionListener:299 - Committed transaction after test execution for test context [TestContext#5a93c236 testClass = UserTest, testInstance = UserTest#1ab395af, testMethod = createUserTest#UserTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration#42821db testClass = UserTest, locations = '{classpath:tests-context.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']]
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.029 sec
2013-02-12 13:01:14 INFO GenericApplicationContext:1042 - Closing org.springframework.context.support.GenericApplicationContext#7d95609: startup date [Tue Feb 12 13:01:12 CET 2013]; root of context hierarchy
2013-02-12 13:01:14 INFO BitronixTransactionManager:320 - shutting down Bitronix Transaction Manager
2013-02-12 13:01:14 INFO LocalContainerEntityManagerFactoryBean:441 - Closing JPA EntityManagerFactory for persistence unit 'ruleEditor.persistence'
The logs show a testException=[null] but I have no idea why that would be.. I even tried to use the saveAndFlush() method provided by the JPARepository but doing so I get the error javax.persistence.TransactionRequiredException: no transaction is in progress
So if anyone has some idea of what I am doing wrong and can point me in the right direction I would very much appreciate the help.
After some careful reading of the logs, I found this warning:
WARN Ejb3Configuration:1309 - HHH000193: Overriding hibernate.transaction.factory_class is dangerous, this might break the EJB3 specification implementation
This was related to a property that I had set in the jpaPropertyMap bean in my tests-context.xml file:
<entry key="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory" />
It turns out that once I removed this line in the configuration file I could see hibernate performing an "insert" action and the user was actually created in the database. Since I am new to spring and all the technologies I used, I must have copied the configuration from somewhere without really analysing it. So, I am now able to run junit4 tests in a project using spring data, hibernate and bitronix as transaction manager.
I'm facing a weird problem. I'm currently writing a web application based on Spring-MVC 3.2, and Hibernate 4.1.9. I wrote a sample controller with its TestNG unit tests, and everything is fine except for editing. I can see that when saving a new object, it works like a charm, but if I try to edit an existing object, it doesn't get saved without giving out any reason (I'm calling the same method for adding and updating).
The log of adding a new object of type Application
14:26:36.636 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - DispatcherServlet with name '' processing POST request for [/app/add.json]
14:26:36.637 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method for path /app/add.json
14:26:36.650 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Returning handler method [public java.lang.Long com.wstars.kinzhunt.platform.apps.web.AppController.createApp(com.wstars.kinzhunt.platform.model.apps.Application)]
14:26:36.651 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'appController'
14:26:36.821 [main] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Reading [class com.wstars.kinzhunt.platform.model.apps.Application] as "application/json" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter#5dc6bb75]
14:26:36.890 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Opening Hibernate Session
14:26:36.890 [main] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13580799968
14:26:36.892 [main] DEBUG c.w.c.dao.hibernate.BaseDaoHibernate - Saving or Updating Object: com.wstars.kinzhunt.platform.model.apps.Application#54fc519b[id=<null>,name=KinzHunt,company=com.wstars.kinzhunt.platform.model.apps.Company#151c2b4[id=1,name=KinzHunt],callbackUrl=http://www.kinzhunt.com/callback/,website=http://www.kinzhunt.com,senderEmail=no-reply#kinzhunt.com,logoUrl=<null>]
14:26:36.892 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Opening Hibernate Session
14:26:36.893 [main] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13580799968
14:26:36.893 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Closing Hibernate Session
14:26:36.894 [main] DEBUG o.h.e.def.AbstractSaveEventListener - executing identity-insert immediately
14:26:36.898 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
14:26:36.899 [main] DEBUG org.hibernate.jdbc.ConnectionManager - opening JDBC connection
14:26:36.899 [main] DEBUG o.s.j.d.DriverManagerDataSource - Creating new JDBC DriverManager Connection to [jdbc:h2:mem:platform_test;DB_CLOSE_DELAY=-1]
14:26:36.901 [main] DEBUG org.hibernate.SQL - /* insert com.wstars.kinzhunt.platform.model.apps.Application */ insert into applications (id, callback_url, company_id, logo_url, name, sender_email, website) values (null, ?, ?, ?, ?, ?, ?)
14:26:36.904 [main] DEBUG o.h.id.IdentifierGeneratorHelper - Natively generated identity: 2
14:26:36.904 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
14:26:36.905 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Closing Hibernate Session
14:26:36.905 [main] DEBUG org.hibernate.jdbc.ConnectionManager - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
14:26:36.905 [main] DEBUG org.hibernate.jdbc.ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
14:26:36.926 [main] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Written [2] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter#5dc6bb75]
14:26:36.927 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Null ModelAndView returned to DispatcherServlet with name '': assuming HandlerAdapter completed request handling
14:26:36.928 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Successfully completed request
While the log for saving an edited object is
14:27:03.398 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - DispatcherServlet with name '' processing POST request for [/app/1/edit.json]
14:27:03.398 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method for path /app/1/edit.json
14:27:03.401 [main] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Returning handler method [public java.lang.Long com.wstars.kinzhunt.platform.apps.web.AppController.editApp(com.wstars.kinzhunt.platform.model.apps.Application,java.lang.Long)]
14:27:03.401 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'appController'
14:27:03.404 [main] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Reading [class com.wstars.kinzhunt.platform.model.apps.Application] as "application/json" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter#5dc6bb75]
14:27:03.409 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Opening Hibernate Session
14:27:03.410 [main] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13580800234
14:27:03.411 [main] DEBUG c.w.c.dao.hibernate.BaseDaoHibernate - Saving or Updating Object: com.wstars.kinzhunt.platform.model.apps.Application#1ba4f8a6[id=1,name=KinzHunt,company=com.wstars.kinzhunt.platform.model.apps.Company#6bc06877[id=1,name=KinzHunt],callbackUrl=http://www.kinzhunt.com/callback/,website=http://www.wstars.com/KinzHunt/,senderEmail=no-reply#kinzhunt.com,logoUrl=<null>]
14:27:03.412 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Opening Hibernate Session
14:27:03.412 [main] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13580800234
14:27:03.413 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Closing Hibernate Session
14:27:03.422 [main] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Closing Hibernate Session
14:27:03.424 [main] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Written [1] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter#5dc6bb75]
14:27:03.424 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Null ModelAndView returned to DispatcherServlet with name '': assuming HandlerAdapter completed request handling
14:27:03.425 [main] DEBUG o.s.t.w.s.TestDispatcherServlet - Successfully completed request
As you can see, in the second log, no prepared statement is created, and no JDBC connection is opened. My test configuration for the database is like this:
<bean id="targetDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:mem:platform_test;DB_CLOSE_DELAY=-1" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="targetDataSource" />
<property name="packagesToScan">
<list>
<value>com.mypackage.model.*</value>
</list>
</property>
<property name="namingStrategy">
<bean class="com.example.common.config.MyOwnNamingStrategy"/>
</property>
<property name="hibernateProperties">
<map>
<entry key="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
<entry key="hibernate.max_fetch_depth" value="1" />
<entry key="hibernate.use_sql_comments" value="true" />
<entry key="hibernate.hbm2ddl.auto" value="update" />
</map>
</property>
<!-- <property key="hibernate.current_session_context_class" value="thread"/> -->
<!-- <property key="hibernate.transaction.factory_class" value="org.hibernate.transaction.JDBCTransactionFactory"/> -->
</bean>
<bean id="h2WebServer" class="org.h2.tools.Server"
factory-method="createWebServer" depends-on="targetDataSource"
init-method="start" lazy-init="false">
<constructor-arg value="-web,-webPort,11111" />
</bean>
My controller code is:
#Controller
public class AppController extends BaseAnnotatedController {
#Autowired
private AppManagementService appManagementService;
#RequestMapping(value="/app/add", method=RequestMethod.POST, consumes={"application/json"})
public #ResponseBody Long createApp(#RequestBody Application app) {
saveApp(app);
return app.getId();
}
#RequestMapping(value="/app/{appId}/edit", method=RequestMethod.POST, consumes={"application/json"})
public #ResponseBody Long editApp(#RequestBody Application app, #PathVariable Long appId) {
if (!appId.equals(app.getId())) {
WSError error = new WSError(ValidationErrorType.GENERIC, "id");
throw new ValidationException(error);
} else {
saveApp(app);
return app.getId();
}
}
#RequestMapping(value="/app/list", method=RequestMethod.GET)
public #ResponseBody List<Application> listApps() {
return appManagementService.listAllApps();
}
#RequestMapping(value="/app/{appId}/get", method=RequestMethod.GET)
public #ResponseBody Application getAppDetails(#PathVariable Long appId) {
return appManagementService.getApplication(appId);
}
private void saveApp(Application app) {
if (isValid(app)) {
appManagementService.saveApp(app);
}
}
public #ResponseBody List<Application> listAllApps() {
return appManagementService.listAllApps();
}
}
My test class is:
#Test
public class AppControllerIntegrationTests extends AbstractContextControllerTests {
private MockMvc mockMvc;
#Autowired
AppController appController;
#Autowired
private AppManagementService appManagementService;
#Autowired
private BaseDao baseDao;
#BeforeClass
public void classSetup() {
Company comp = new Company();
comp.setName("Some Company");
baseDao.saveObject(comp);
}
#BeforeMethod
public void setup() throws Exception {
this.mockMvc = webAppContextSetup(this.wac).build();
}
#Test
public void testAddInvalidAppWebJson() throws Exception {
String appJson = getInvalidApp().toJsonString();
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/add.json")
.contentType(MediaType.APPLICATION_JSON).content(appJson);
ResultActions resultAction = this.mockMvc.perform(requestBuilder);
resultAction.andExpect(status().isForbidden());
MvcResult mvcResult = resultAction.andReturn();
Exception resolvedException = mvcResult.getResolvedException();
assertTrue(resolvedException instanceof ValidationException);
ValidationException validationException = (ValidationException) resolvedException;
assertEquals(validationException.getErrors().size(), 3);
}
#Test
public void testAddAppWebJson() throws Exception {
Application app = getMockApp();
String appJson = app.toJsonString();
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/add.json")
.contentType(MediaType.APPLICATION_JSON).content(appJson);
this.mockMvc.perform(requestBuilder).andExpect(status().isOk());
}
#Test
public void testEditAppWithWrongIdWebJson() throws Exception {
String appJson = getMockAppWithId().toJsonString();
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/2/edit.json")
.contentType(MediaType.APPLICATION_JSON).content(appJson);
this.mockMvc
.perform(requestBuilder)
.andExpect(status().isForbidden())
.andExpect(
content()
.string("{\"errors\":[{\"errorType\":\"-100\",\"field\":\"id\",\"constraint\":null}],\"objects\":null}"));
}
#Test(dependsOnMethods={"testAddApp", "testAddAppWebJson"})
public void testEditAppWebJson() throws Exception {
Application app = getMockAppWithId();
setAppWebsiteToDifferentOne(app);
String appJson = app.toJsonString();
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/1/edit.json")
.contentType(MediaType.APPLICATION_JSON).content(appJson);
this.mockMvc.perform(requestBuilder).andExpect(status().isOk());
}
#Test
public void testEditInvalidAppWebJson() throws Exception {
Application app = getMockAppWithId();
app.setWebsite("Saba7o 3asal");
String appJson = app.toJsonString();
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/app/1/edit.json")
.contentType(MediaType.APPLICATION_JSON).content(appJson);
this.mockMvc
.perform(requestBuilder)
.andExpect(status().isForbidden())
.andExpect(
content()
.string("{\"errors\":[{\"errorType\":\"-114\",\"field\":\"website\",\"constraint\":null}],\"objects\":null}"));
}
#Test(dependsOnMethods="testEditAppWebJson")
public void testGetAppDetails() throws Exception {
RequestBuilder requestBuilder = MockMvcRequestBuilders.get("/app/1/get.json");
Application app = getMockAppWithId();
setAppWebsiteToDifferentOne(app);
this.mockMvc.perform(requestBuilder).andExpect(status().isOk())
.andExpect(content().string(app.toJsonString()));
}
}
My service method is:
#Override
#Transactional(readOnly=false)
public void saveApp(Application app) {
baseDao.saveObject(app);
}
All test methods pass, except for the last one, since it's expecting the website of the app to be the one which was edited. Where have I gone wrong?
Need to know which hibernate method is called in saveApp() also make sure your service is annotated with #Transactional.
We want to use the Atomikos JTA Transaction Manager. We have a unit test which we want to roll back once it completes, thereby leaving the table clean for the next run.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:spring/appContext-test.xml"})
#TransactionConfiguration(transactionManager = "txManager")
public class InboundEmailDaoTest extends AbstractTransactionalJUnit4SpringContextTests {
#Autowired
private InboundEmailDao dao;
#BeforeTransaction
public void beforeTransaction() {
System.out.println("InboundEmailDaoTest: Rows before: " + this.countRowsInTable("myapp.polin2fos_inbound_email"));
}
#AfterTransaction
public void afterTransaction() {
System.out.println("InboundEmailDaoTest: Rows after: " + this.countRowsInTable("myapp.polin2fos_inbound_email"));
}
#Test
public void when_inserting_then_record_is_created() {
String subject = "subject here";
InboundEmail inboundEmail = new InboundEmail();
inboundEmail.setEmailSubject(subject);
//More here...
inboundEmail.setOriginator("originator");
inboundEmail.setOriginSystem("myapp");
inboundEmail.setProcessingStatus("RECEIVED");
inboundEmail.setAttachment("big fat attachment here");
inboundEmail.setAttachmentFilename("Big fat attachment filename here");
int rowsBefore = this.countRowsInTable("myapp.polin2fos_inbound_email");
System.out.println("Rows before: " + rowsBefore);
dao.insert(inboundEmail);
int rowsAfter = this.countRowsInTable("myapp.polin2fos_inbound_email");
System.out.println("Rows after: " + rowsAfter);
assertTrue((rowsAfter == rowsBefore + 1));
}
}
When we run with the Spring-bundled JTA transaction manager configged as below
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
... we get:
Running co.myco.myapp.repository.dao.InboundEmailDaoTest
12:02:22.751 INFO [main][org.springframework.beans.factory.support.DefaultListableBeanFactory] Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#13785d3: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.support.PropertySourcesPlaceholderConfigurer#0,caseTypeDaoImpl,inboundEmailDaoImpl,inboundEmailRepositoryImpl,propertyPlaceholderConfigurer,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,txManager,dataSource,org.mybatis.spring.mapper.MapperScannerConfigurer#0,sqlSessionFactory,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0,caseTypeMapper,inboundEmailMapper]; root of factory hierarchy
12:02:22.798 INFO [main][org.springframework.jdbc.datasource.DriverManagerDataSource] Loaded JDBC driver: oracle.jdbc.OracleDriver
InboundEmailDaoTest: Rows before: 0
12:02:23.770 INFO [main][org.springframework.test.context.transaction.TransactionalTestExecutionListener] Began transaction (1): transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager#8e4805]; rollback [true]
Rows before: 0
12:02:23.832 DEBUG [main][com.myco.repository.mybatis.InboundEmailMapper.insert] ooo Using Connection [oracle.jdbc.driver.T4CConnection#44d990]
12:02:23.835 DEBUG [main][com.myco.repository.mybatis.InboundEmailMapper.insert] ==> Preparing: insert into myapp.polin2fos_inbound_email (EMAIL_SUBJECT, RECEIVED_DATE, ORIGINATOR, ORIGIN_SYSTEM, PROCESSING_STATUS, ATTACHMENT, ATTACHMENT_FILENAME) values (?, sysdate, ?, ?, ?, ?, ?)
12:02:23.888 DEBUG [main][com.myco.repository.mybatis.InboundEmailMapper.insert] ==> Parameters: subject here(String), originator(String), myapp(String), RECEIVED(String), big fat attachment here(String), Big fat attachment filename here(String)
Rows after: 1
12:02:23.927 INFO [main][org.springframework.test.context.transaction.TransactionalTestExecutionListener] Rolled back transaction after test execution for test context [[TestContext#1958cc2 testClass = InboundEmailDaoTest, testInstance = co.myco.myapp.repository.dao.InboundEmailDaoTest#14c28db, testMethod = when_inserting_then_record_is_created#InboundEmailDaoTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration#10e687b testClass = InboundEmailDaoTest, locations = '{classpath:spring/appContext-test.xml}', classes = '{}', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader']]]
InboundEmailDaoTest: Rows after: 0
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.252 sec
But when we run with the Atomikos Transaction Manager configged as follows:
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="AtomikosTransactionManager" />
<property name="userTransaction" ref="AtomikosUserTransaction" />
</bean>
<!-- ATOMIKOS Transaction-Manager-Specific Setup -->
<bean id="AtomikosTransactionManager"
class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<!-- when close is called, should we force
transactions to terminate or not? -->
<property name="forceShutdown" value="false" />
</bean>
<bean id="AtomikosUserTransaction"
class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="300" />
</bean>
... we get:
Running co.myco.myapp.repository.dao.InboundEmailDaoTest
12:12:42.267 INFO [main][org.springframework.beans.factory.support.DefaultListableBeanFactory] Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#13785d3: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.support.PropertySourcesPlaceholderConfigurer#0,caseTypeDaoImpl,inboundEmailDaoImpl,inboundEmailRepositoryImpl,propertyPlaceholderConfigurer,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,txManager,AtomikosTransactionManager,AtomikosUserTransaction,dataSource,org.mybatis.spring.mapper.MapperScannerConfigurer#0,sqlSessionFactory,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0,caseTypeMapper,inboundEmailMapper]; root of factory hierarchy
12:12:42.310 INFO [main][org.springframework.jdbc.datasource.DriverManagerDataSource] Loaded JDBC driver: oracle.jdbc.OracleDriver
12:12:42.853 INFO [main][com.atomikos.logging.LoggerFactory] Using Slf4J for logging.
12:12:42.854 WARN [main][com.atomikos.icatch.config.UserTransactionServiceImp] No properties path set - looking for transactions.properties in classpath...
12:12:42.855 WARN [main][com.atomikos.icatch.config.UserTransactionServiceImp] transactions.properties not found - looking for jta.properties in classpath...
12:12:42.855 WARN [main][com.atomikos.icatch.config.UserTransactionServiceImp] Failed to open transactions properties file - using default values
12:12:42.893 INFO [main][com.atomikos.persistence.imp.FileLogStream] Starting read of logfile C:\Code\unblocking-workspace-29-05-12\myapp-master\myapp-repository\.\tmlog47.log
12:12:42.893 INFO [main][com.atomikos.persistence.imp.FileLogStream] Done read of logfile
12:12:42.893 INFO [main][com.atomikos.persistence.imp.FileLogStream] Logfile closed: C:\Code\unblocking-workspace-29-05-12\myapp-master\myapp-repository\.\tmlog47.log
12:12:42.899 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING core version: 3.8.0
12:12:42.899 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.console_file_name = tm.out
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.console_file_count = 1
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.automatic_resource_registration = true
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.client_demarcation = false
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.threaded_2pc = false
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.serial_jta_transactions = true
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.log_base_dir = .\
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.console_log_level = WARN
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.max_actives = 50
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.checkpoint_interval = 500
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.enable_logging = true
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.output_dir = .\
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.log_base_name = tmlog
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.console_file_limit = -1
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.max_timeout = 300000
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.tm_unique_name = 100.100.100.100.tm
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING java.naming.factory.initial = com.sun.jndi.rmi.registry.RegistryContextFactory
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING java.naming.provider.url = rmi://localhost:1099
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.service = com.atomikos.icatch.standalone.UserTransactionServiceFactory
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.force_shutdown_on_vm_exit = false
12:12:42.900 INFO [main][com.atomikos.icatch.config.imp.AbstractUserTransactionService] USING com.atomikos.icatch.default_jta_timeout = 10000
12:12:42.906 INFO [main][org.springframework.transaction.jta.JtaTransactionManager] Using JTA UserTransaction: com.atomikos.icatch.jta.UserTransactionImp#1568654
12:12:42.906 INFO [main][org.springframework.transaction.jta.JtaTransactionManager] Using JTA TransactionManager: com.atomikos.icatch.jta.UserTransactionManager#18d30fb
InboundEmailDaoTest: Rows before: 1
12:12:43.149 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning NULL!
12:12:43.149 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning NULL!
12:12:43.149 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning NULL!
12:12:43.165 DEBUG [main][com.atomikos.icatch.imp.CoordinatorImp] Coordinator 100.100.100.100.tm0000100049 entering state: ACTIVE
12:12:43.170 DEBUG [main][com.atomikos.icatch.imp.thread.TaskManager] TaskManager: initializing...
12:12:43.170 INFO [main][com.atomikos.icatch.imp.thread.TaskManager] THREADS: using JDK thread pooling...
12:12:43.176 DEBUG [main][com.atomikos.icatch.imp.thread.TaskManager] THREADS: using executor class com.atomikos.icatch.imp.thread.Java15ExecutorFactory$Executor
12:12:43.177 DEBUG [main][com.atomikos.icatch.imp.thread.Java15ExecutorFactory] (1.5) executing task: com.atomikos.timing.PooledAlarmTimer#160bf50
12:12:43.177 DEBUG [main][com.atomikos.icatch.imp.thread.ThreadFactory] ThreadFactory: creating new thread: Atomikos:0
12:12:43.178 DEBUG [main][com.atomikos.icatch.imp.TransactionServiceImp] Creating composite transaction: 100.100.100.100.tm0000100049
12:12:43.182 INFO [main][com.atomikos.icatch.imp.BaseTransactionManager] createCompositeTransaction ( 300000 ): created new ROOT transaction with id 100.100.100.100.tm0000100049
12:12:43.185 INFO [main][org.springframework.test.context.transaction.TransactionalTestExecutionListener] Began transaction (1): transaction manager [org.springframework.transaction.jta.JtaTransactionManager#ed9f47]; rollback [true]
Rows before: 1
12:12:43.376 DEBUG [main][co.myco.myapp.repository.mybatis.InboundEmailMapper.insert] ooo Using Connection [oracle.jdbc.driver.T4CConnection#96ad7c]
12:12:43.379 DEBUG [main][co.myco.myapp.repository.mybatis.InboundEmailMapper.insert] ==> Preparing: insert into myapp.polin2fos_inbound_email (EMAIL_SUBJECT, RECEIVED_DATE, ORIGINATOR, ORIGIN_SYSTEM, PROCESSING_STATUS, ATTACHMENT, ATTACHMENT_FILENAME) values (?, sysdate, ?, ?, ?, ?, ?)
12:12:43.429 DEBUG [main][co.myco.myapp.repository.mybatis.InboundEmailMapper.insert] ==> Parameters: subject here(String), originator(String), myapp(String), RECEIVED(String), big fat attachment here(String), Big fat attachment filename here(String)
12:12:43.494 INFO [main][org.springframework.beans.factory.xml.XmlBeanDefinitionReader] Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
12:12:43.529 INFO [main][org.springframework.jdbc.support.SQLErrorCodesFactory] SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]
12:12:43.532 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning instance with id 100.100.100.100.tm0000100049
12:12:43.532 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning instance with id 100.100.100.100.tm0000100049
12:12:43.532 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning instance with id 100.100.100.100.tm0000100049
12:12:43.532 DEBUG [main][com.atomikos.icatch.imp.BaseTransactionManager] getCompositeTransaction() returning instance with id 100.100.100.100.tm0000100049
12:12:43.533 DEBUG [main][com.atomikos.icatch.imp.CoordinatorImp] Coordinator 100.100.100.100.tm0000100049 entering state: ABORTING
12:12:43.534 DEBUG [main][com.atomikos.icatch.imp.CoordinatorImp] Coordinator 100.100.100.100.tm0000100049 entering state: TERMINATED
12:12:43.534 DEBUG [main][com.atomikos.icatch.imp.CoordinatorImp] Coordinator 100.100.100.100.tm0000100049 : stopping timer...
12:12:43.534 DEBUG [main][com.atomikos.icatch.imp.CoordinatorImp] Coordinator 100.100.100.100.tm0000100049 : disposing statehandler TERMINATED...
12:12:43.534 DEBUG [main][com.atomikos.icatch.imp.CoordinatorImp] Coordinator 100.100.100.100.tm0000100049 : disposed.
12:12:43.536 DEBUG [main][com.atomikos.icatch.imp.CompositeTransactionImp] Ignoring error during event callback
java.lang.IllegalStateException: Transaction no longer active
at com.atomikos.icatch.imp.TxTerminatedStateHandler.rollbackWithStateCheck(TxTerminatedStateHandler.java:106)
at com.atomikos.icatch.imp.CompositeTransactionImp.doRollback(CompositeTransactionImp.java:237)
at com.atomikos.icatch.imp.CompositeTerminatorImp.rollback(CompositeTerminatorImp.java:123)
at com.atomikos.icatch.imp.CompositeTransactionImp.rollback(CompositeTransactionImp.java:346)
at com.atomikos.icatch.imp.CompositeTransactionImp.entered(CompositeTransactionImp.java:373)
at com.atomikos.finitestates.FSMImp.notifyListeners(FSMImp.java:186)
at com.atomikos.finitestates.FSMImp.setState(FSMImp.java:277)
at com.atomikos.icatch.imp.CoordinatorImp.setState(CoordinatorImp.java:429)
at com.atomikos.icatch.imp.CoordinatorImp.setStateHandler(CoordinatorImp.java:286)
at com.atomikos.icatch.imp.CoordinatorStateHandler.rollback(CoordinatorStateHandler.java:764)
at com.atomikos.icatch.imp.ActiveStateHandler.rollback(ActiveStateHandler.java:264)
at com.atomikos.icatch.imp.CoordinatorImp.rollback(CoordinatorImp.java:747)
at com.atomikos.icatch.imp.TransactionStateHandler.rollback(TransactionStateHandler.java:179)
at com.atomikos.icatch.imp.TransactionStateHandler.rollbackWithStateCheck(TransactionStateHandler.java:197)
at com.atomikos.icatch.imp.CompositeTransactionImp.doRollback(CompositeTransactionImp.java:237)
at com.atomikos.icatch.imp.CompositeTerminatorImp.rollback(CompositeTerminatorImp.java:123)
at com.atomikos.icatch.imp.CompositeTransactionImp.rollback(CompositeTransactionImp.java:346)
at com.atomikos.icatch.jta.TransactionImp.rollback(TransactionImp.java:234)
at com.atomikos.icatch.jta.TransactionManagerImp.rollback(TransactionManagerImp.java:524)
at com.atomikos.icatch.jta.UserTransactionImp.rollback(UserTransactionImp.java:141)
at org.springframework.transaction.jta.JtaTransactionManager.doRollback(JtaTransactionManager.java:1037)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:845)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:822)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener$TransactionContext.endTransaction(TransactionalTestExecutionListener.java:518)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.endTransaction(TransactionalTestExecutionListener.java:292)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.afterTestMethod(TransactionalTestExecutionListener.java:185)
at org.springframework.test.context.TestContextManager.afterTestMethod(TestContextManager.java:406)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:91)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:236)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:134)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:113)
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.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:103)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:74)
12:12:43.537 INFO [main][com.atomikos.icatch.imp.CompositeTransactionImp] rollback() done of transaction 100.100.100.100.tm0000100049
In short, it seems Atomikos is ABORTING and TERMINATING our Tx mid flight for no apparent reason. Does anyone have any idea why?
The problem can be in a configuration that is not present in your code snippets.
Datasource should be wrapped into com.atomikos.jdbc.AtomikosDataSourceBean.
If you use Hibernate in your DAO implementation, there are properties that should be set up, like hibernate.transaction.factory_class or hibernate.transaction.manager_lookup_class.
I have a similar set-up and this works for me.
#TransactionConfiguration(transactionManager = "txManager", defaultrollback=true)
You can also set individual #Test methods with #Rollback(true/false)
Depending on what you are calling in your tests you may have to set #Transactional on the class or
#Transactional(propagation=Propagation.REQUIRES_NEW) per transaction #Test method