406 error on Spring MVC integration test, while the service works fine in browser - spring

I have a Spring 4 MVC web application. I am doing the Integration Test for my REST Services. The services are working fine from invoking through browser rest-clients and jquery/restangular UI as well. However, when I run my Integration Test, I am getting the error Expected :200 Actual :406.
This issue comes only when Spring convert the Object to json. I tried manual conversion by ObjectMapper and returned the result. In this case, the test started working.
Here are my files:
Controller:
#RequestMapping(value="/permissions", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<Object> getPermissions() throws Exception {
return new ResponseEntity<Object>(getPermissions(), HttpStatus.OK);
}
Integration Test:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration({"classpath*:rest-config.xml", "classpath:domain-config.xml"})
public class ITController {
#Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
#Test
public void getPermissions() throws Exception {
MvcResult result = this.mockMvc.perform(get("/permissions/4")
.accept("application/json"))
.andExpect(status().isOk())
.andExpect(content().contentType("application/json")).andReturn();
Permission p = new GsonBuilder().create().fromJson(result.getResponse().getContentAsString(), Permission.class);
Assert.assertNotNull(p);
}
}
If I add the below code to the controller, then the test start working.
ObjectMapper mapper = new ObjectMapper();
String stringVal = mapper.writeValueAsString(permission);
Part of my spring config file:
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="order" value="1"/>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes" value="application/json"/>
</bean>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="text/plain;charset=UTF-8"/>
</bean>
</list>
</property>
</bean>
I am using jackson version 2.2.1 in my application.
DEBUG Log
2014-07-14 14:41:37 DEBUG EntityPrinter:121 - com.myapp.entity.Permission{isActive=true, description=permission, id=4, Name=mypermission}
2014-07-14 14:41:37 DEBUG JdbcTransaction:113 - committed JDBC Connection
2014-07-14 14:41:37 DEBUG JdbcTransaction:126 - re-enabling autocommit
2014-07-14 14:41:37 DEBUG LogicalConnectionImpl:314 - Releasing JDBC connection
2014-07-14 14:41:37 DEBUG LogicalConnectionImpl:332 - Released JDBC connection
2014-07-14 14:41:37 DEBUG ConnectionProxyHandler:219 - HHH000163: Logical connection releasing its physical connection

Related

Camel Splitter Unit Test get wrong ExpectedMessageCount

I have to write unit test for a camel RouteBuilder that use splitter pattern.
Here my RouteConfiguration
protected void configureTest(){
from("direct:in").id("in")
.to("mock:a")
.split(body())
.to("mock:b")
.end();
}
And the test
public class AlertingRouteBuilderTest extends CamelSpringTestSupport {
#Test
public void testest() throws Exception {
String[] bodyArray = new String[]{"tenant1", "tenant2", "tenant3"};
getMockEndpoint("mock:a").setExpectedMessageCount(1);
getMockEndpoint("mock:b").setExpectedMessageCount(3);
template.sendBody("direct:in", bodyArray);
assertNotNull(context.hasEndpoint("direct:in"));
assertMockEndpointsSatisfied();
}
}
#Override
protected AbstractApplicationContext createApplicationContext() {
return new ClassPathXmlApplicationContext("classpath:cmCtx_alertingProcessTest.xml");
}
with this context.xml file
<bean id="A"
class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="foo.AProcessor"/>
</bean>
<bean id="B"
class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="foo.BProcessor"/>
</bean>
<bean id="routeBuilder"
class="foo.RouteBuilder" >
</bean>
<camel:camelContext id="context-objectAnalysis" trace="true" errorHandlerRef="errorHandler">
<camel:propertyPlaceholder id="properties" location="camel.properties"/>
<camel:routeBuilder ref="routeBuilder"/>
</camel:camelContext>
I tried different way to split my body
.split(body())
.split(body(String[].class))
....
But I get
java.lang.AssertionError: mock://b Received message count. Expected: <3> but was: <0>
I don't understand why my splitter does'nt go into my mock:b processor.
In the trace console I have
16:18:34.046 [main] DEBUG o.a.camel.processor.SendProcessor - >>>> Endpoint[mock://a] Exchange[Message: [Ljava.lang.String;#58ec5e8]
16:18:34.051 [main] DEBUG o.a.c.component.mock.MockEndpoint - mock://a >>>> 0 : Exchange[Message: [Ljava.lang.String;#58ec5e8] with body: [Ljava.lang.String;#58ec5e8 and headers:{breadcrumbId=ID-EFR02223-61984-1495635511863-0-1}
16:18:34.053 [main] INFO o.a.c.processor.interceptor.Tracer - ID-EFR02223-61984-1495635511863-0-2 >>> (direct:in) mock://a --> split[bodyAs[[Ljava.lang.String;]] <<< Pattern:InOnly, Headers:{breadcrumbId=ID-EFR02223-61984-1495635511863-0-1}, BodyType:String[], Body:[Ljava.lang.String;#58ec5e8
16:18:34.064 [main] DEBUG o.a.c.processor.MulticastProcessor - Done sequential processing 3 exchanges
Tell me if you need more info to help me.
EDIT:
camel version 2.12.1
Thanks.

Camel Transactional client with Spring, how to rollback route changes?

Consider the following two test. The findOne() has no side effect, the delete() has a side effect on the underlying h2 database. My problem is the #Transactional does not rollback the changes for the delete() method.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:app-context.xml")
public class AccountProcessorTest extends BaseRouteTest {
private static final String ACCOUNTS_ENDPOINT = "seda:bar";
#Test
#Transactional
public void findOne() {
final Map<String, Object> headers = new HashMap<String, Object>();
headers.put("id", 1);
headers.put(Exchange.HTTP_METHOD, "GET");
final String response = template.requestBodyAndHeaders(ACCOUNTS_ENDPOINT, null, headers, String.class);
assertEquals("Checking account",JsonPath.read(response, "name"));
}
#Test
#Transactional
public void delete() {
final Map<String, Object> headers = new HashMap<String, Object>();
headers.put("id", 1);
headers.put(Exchange.HTTP_METHOD, "DELETE");
final String response = template.requestBodyAndHeaders(ACCOUNTS_ENDPOINT, null, headers, String.class);
assertEquals(200, JsonPath.read(response, "code"));
}
}
The BaseRouteTest is just a utility where I get a reference to the Camel ProducerTemplate
public class BaseRouteTest implements InitializingBean {
#Autowired
private ApplicationContext applicationContext;
protected ProducerTemplate template;
#Override
public void afterPropertiesSet() throws Exception {
template = getCamelContext().createProducerTemplate();
}
private CamelContext getCamelContext() {
return applicationContext.getBean("foo", CamelContext.class);
}
}
I have marked the route as transacted using the transacted tag.
<!-- camel-context -->
<camel:camelContext id="foo">
<camel:route>
<camel:from uri="seda:bar"/>
<camel:transacted />
<camel:process ref="accountProcessor"/>
</camel:route>
</camel:camelContext>
My spring configuration file:
<context:component-scan base-package="com.backbase.progfun"/>
<!-- embedded datasource -->
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:data/schema.ddl"/>
<jdbc:script location="classpath:data/insert.sql"/>
</jdbc:embedded-database>
<!-- spring jdbc template -->
<bean class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource" />
</bean>
<!-- transaction management start -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- transaction management end -->
<!-- camel-context -->
<camel:camelContext id="foo">
<camel:route>
<camel:from uri="seda:bar"/>
<camel:transacted />
<camel:process ref="accountProcessor"/>
</camel:route>
</camel:camelContext>
You can try it out quickly if you clone my github repo found here:
https://github.com/altfatterz/camel-transaction
If you run the AccountProcessorTest it the findOne() test case fails because the side effect of delete() test case is not rolled back.
Any suggestion would be greatly appreciated.
Thank you.
Transactions aren't carried across SEDA queues.
Therefore the transaction started by your test is a different transaction from the transaction in your route. So the changes made by your route won't be rolled back when the transaction started by your test is rolled back.

How to execute SQL script only once at startup in Spring?

I have a web application based on Spring JDBC and Jersey RESTful web service. I'm using the following Spring JDBC template class to initiate the dataSource and execute an SQL script (update_condition_table.sql):
public class CustomerJDBCTemplate implements CustomerDAO {
private DataSource dataSource;
private JdbcTemplate jdbcTemplateObject;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
Resource rc = new ClassPathResource("update_condition_table.sql");
JdbcTestUtils.executeSqlScript(jdbcTemplateObject, rc, false);
}
// ......other methods
}
The bean configuration file is beans.xml:
<!-- Initialization for data source -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/customer" />
<property name="username" value="root" />
<property name="password" value="mypassword" />
</bean>
<!-- Definition for customerJDBCTemplate bean -->
<bean id="customerJDBCTemplate" class="com.example.db.CustomerJDBCTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
The Jersey controller class contains the instantiation of class CustomerJDBCTemplate and serves as the REST web service:
#Path("/customer")
public class CustomerService {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
CustomerJDBCTemplate dbController = (CustomerJDBCTemplate) context.getBean("customerJDBCTemplate");
// ... some GET/POST methods
}
When I launched my web app by entering the index URL in the browser, the SQL script gets executed by the customerJDBCTemplate bean. However, when I clicked to navigate to other pages, it crashed and reported that the SQL script cannot be executed again. So obviously the SQL script was executed again after initialization of dataSource and initial launch of the index web page. How to avoid this by just running the SQL script only once upon initial startup of the web app?
Looks like I need to move the bean instantiate code out of CustomerService class, but where should I put that code?
I figured it out that I should set the bean application context to be static within CustomerService class and do it in the static initialization block as follows:
#Path("/customer")
public class CustomerService {
private static ApplicationContext context;
private static CustomerJDBCTemplate dbController;
static {
context = new ClassPathXmlApplicationContext("beans.xml");
dbController = (CustomerJDBCTemplate) context.getBean("customerJDBCTemplate");
}
//... other methods
}
I guess the reason is Jersey creates a different instance of CustomerService for each HTTP session (correct me if I'm wrong). So if I set the bean context as instance variable, it will do the initialization for every HTTP request.
Have your CustomerJDBCTemplate implement InitializingBean. afterPropertiesSet will get called once, right after all properties have been set by Spring's BeanFactory.
For example:
public class CustomerJDBCTemplate implements CustomerDAO, InitializingBean {
...
// ......other methods
public void afterPropertiesSet() throws Exception {
//do your initializing, or call your initializing methods
}
}

Spring Injection of Data using Hibernate

On initialisation of the web app, I am trying to inject some static data from the DB into the bean.
<bean id="CustomDriven" class="java.util.ArrayList">
<constructor-arg>
<value>#{FormCodeHibernateDAO.findAll()}</value>
</constructor-arg>
</bean>
I get an error
6:48:07,977 INFO [main] [UpdateTimestampsCache] starting update timestamps cache at region: org.hibernate.cache.UpdateTimestampsCache
16:48:07,981 INFO [main] [StandardQueryCache] starting query cache at region: org.hibernate.cache.StandardQueryCache
16:48:09,016 DEBUG [main] [GenericDaoJpa] findAll()
16:48:09,017 DEBUG [main] [GenericDaoJpa] getting HIBERNATE session...
16:48:09,196 ERROR [main] [GenericDaoJpa] Error when finding all
org.hibernate.SessionException: Session is closed!
at org.hibernate.impl.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:72)
at org.hibernate.impl.SessionImpl.setFlushMode(SessionImpl.java:1433)
Any reason why I am getting this?
maybe the execution of #{FormCodeHibernateDAO.findAll()} is before than the application context start connection to database, i think so.
I figured the problem, my CustomDriven bean was talking to the DAO Impl directly.
I changed it to talk to the DAO using a service and the new configuration looks like
<bean id="CustomDriven" class="java.util.ArrayList">
<constructor-arg>
<value>#{dataDrivenService.getDataList()}</value>
</constructor-arg>
</bean>
And the DataDriverService class is
public interface DataDrivenService<T> {
public List<T> getDataList();
}
And the ServiceImpl is
#Service( value = "dataDrivenService" )
public class DataDrivenServiceImpl implements DataDrivenService {
#Autowired
#Qualifier( value = "formCodeDAO" )
private FormCodeDAO dao;
#Override
#Transactional( readOnly = true )
public List<FormCode> getDataList() {
return dao.findAll();
}
}
Where FormCodeDAO in interface that extends the GenericDAO implementation

Spring JPA - Injecting transaction manager vs injecting entity manager

If I wanted manage transactions programmatically, what is the difference between starting the transaction by injecting a PlatformTransactionManager vs directly injecting EntityMangerFactory/EntityManager and getting transaction from Entitymanager
public class MyDAO {
#PersistenceContext(unitName="test") EntityManager em;
JpaTransactionManager txnManager = null;
public void setTxnManager(JpaTransactionManager mgr) {
txnManager = mgr;
}
public void process(Request request) throws Exception {
TransactionStatus status =
txnManager.getTransaction(new DefaultTransactionDefinition());
try {
em.persist(request);
txnManager.commit(status);
} catch (Exception up) {
txnManager.rollback(status);
throw up;
}
}
As apposed to injecting EntityManager directly
public class MyDAO {
#PersistenceContext(unitName="test")
EntityManager em;
public void process(Request request) throws Exception {
EntityTransaction txn = em.getTransaction();
try {
em.persist(request);
txn.commit();
} catch (Exception up) {
txn.rollback();
throw up;
}
}
where as spring config snippet looks like this
<beans>
<bean id="MyDAO" class="com.xyz.app.dao.MyDAO">
<context:annotation-config />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerE ntityManagerFactoryBean">
<property name="persistenceUnitName" value="persistence" />
<property name="dataSource" ref="dataSourceProvider" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
</bean>
<bean id="transactionManagerJpa" class="org.springframework.orm.jpa.JpaTransactionM anager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
</beans>
Transaction managers should not be injected into DAOs, because a DAO has no way to tell whether they're one participant in a larger transaction or not.
I think the transaction manager belongs with the service layer, not the persistence layer. The services know about use cases and units of work. They orchestrate other services, DAOs and model objects to fulfill their use cases.

Resources