Apache Camel Integration test results in OutOfMemory - spring-mvc

I have a simple Camel route that sends data to an external REST interface, integrated with Spring MVC.
#RestController
public class MyController {
#Autowired
private camelService camelService;
#RequestMapping(method = RequestMethod.POST, value = "/test")
#ResponseStatus(HttpStatus.CREATED)
public TestModel createEV(#Valid #RequestBody TestModel testModel) {
camelService.publishTestCase(testModel);
return testModel;
}
}
#Service
public class CamelService {
#Produce(uri = "direct:test")
private ProducerTemplate producerTemplate;
#Override
public void publishTestCase(TestModel testModel) {
producerTemplate.sendBody(testModel);
}
}
#Component
public class TestRouter extends SpringRouteBuilder
#Override
public void configure() throws Exception {
errorHandler(loggingErrorHandler(log).level(LoggingLevel.ERROR));
from("direct:test")
.routeId("testRoute")
.beanRef("mapper", "map")
.to("velocity:test.vm")
.setHeader(Exchange.HTTP_METHOD, simple("POST"))
.to("log:test?level=DEBUG&showAll=true&multiline=true&maxChars=100000")
.to("cxfrs:http://url.here");
}
}
Then there's an integration test for the rest endpoint with mockMvc that mocks the external camel endpoint.
#ContextConfiguration(loader = SpringApplicationContextLoader, classes = Application)
#WebIntegrationTest
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
class MyControllerIntegrationTest extends Specification {
#Autowired
private CamelContext camelContext
MockMvc mockMvc
#Autowired
WebApplicationContext wac
#Shared
def setupOnceRun = false
#Shared
def validInput = new File(JSON_DIR + '/valid.json').text
def setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build()
// no way to use setupSpec as Autowired fields can't be Shared
if (!setupOnceRun) {
ModelCamelContext mcc = camelContext.adapt(ModelCamelContext);
camelContext.getRouteDefinition("testRoute).adviceWith(mcc, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
mockEndpointsAndSkip("cxfrs:http://url.here")
}
});
setupOnceRun = true
}
}
def 'valid scenario'() {
setup:
MockEndpoint mockEndpoint = (MockEndpoint) camelContext.hasEndpoint("mock:cxfrs:http://url.here")
mockEndpoint.expectedMessageCount(1)
when:
def response = mockMvc.perform(post('/test').content(validInput)).andReturn()
then:
response.getResponse().getStatus() == 201
mockEndpoint.assertIsSatisfied()
}
}
The test is passing if you run it by itself but once it's included in the build together with other integration tests it's constantly producing OutOfMemory. MaxPermSize is 4G, it doesn't look like that's an issue. I am new to Camel so my guess is that I am wiring the test in a wrong way. Would appreciate any suggestions.

Related

#Value not visible inside #component filter during tests

I created filter which logging and saving all requests, this is part of this:
#Component
public class RequestFilter extends OncePerRequestFilter {
#Value("${app.endpoint}")
private String requestMapping;
private final RequestRepository requestRepository;
#Autowired
public RequestFilter(RequestRepository requestRepository) {
this.requestRepository = requestRepository;
}
....
}
When app is running requestMapping is properly readed from spring context, but
when I created test for that filter requestMapping is null
#SpringBootTest
#RunWith(SpringRunner.class)
#AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.H2)
#ContextConfiguration(classes = {MyApplication.class})
#AutoConfigureMockMvc
#ActiveProfiles("test")
public class FilterTest {
#Autowired
private WebApplicationContext webApplicationContext;
#Autowired
private RequestRepository requestRepository;
#Autowired
protected MockMvc mockMvc;
#Before
public void setup() {
RequestFilter rpmRequestFilter = new RequestFilter(this.requestRepository);
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.addFilter(invalidVpmRequestFilter)
.build();
}
}
And of course in application-test.properties I have configured this property:
app.endpoint=/log/save
Does someone know where the problem can be? Why this is doesnt work in tests?
As M. Deinum pointed out, the problem is that you are creating an instance of RequestFilter and if you want Spring to inject components (#Autowired) or propoerties (#Value) in it, you have to let Spring handle the instantiation as follow :
#....
public class FilterTest {
....
#Autowired
RequestFilter requestFilter;
#Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.addFilter(requestFilter)
.build();
}
}

CordaApp with Spring Boot Api different response

I have integrated the cordapp with spring boot .One strange observation we found that the response differs coming from the cordawebserver and spring boot server for example
Blockquote
API :GET: market/me
gives
{
“me”: {
“commonName”: null,
“organisationUnit”: null,
“organisation”: “PartyG-CT”,
“locality”: “Tokyo”,
“state”: null,
“country”: “JP”,
“x500Principal”: {
“name”: “O=PartyG-CT,L=Tokyo,C=JP”,
“encoded”: “MDExCzAJBgNVBAYTAkpQMQ4wDAYDVQQHDAVUb2t5bzESMBAGA1UECgwJUGFydHlHLUNU”
}
}
}
with Spring boot
while with cordawebserver we are getting :
{
“me”: “C=JP,L=Tokyo,O=PartyG-CT”
}
Same behaviour we are finding the same for different APIs Any help will be appreciated
#GET
#Path("peers")
#Produces(javax.ws.rs.core.MediaType.APPLICATION_JSON)
// CordaX500Name
public Map<String, List<CordaX500Name>> getPeers() {
List<NodeInfo> nodeInfoSnapshot = proxy.networkMapSnapshot();
return ImmutableMap.of(
"peers",
nodeInfoSnapshot
.stream()
.map(node -> node.getLegalIdentities().get(0).getName())
.filter(name -> !name.equals(myLegalName) && !name.getOrganisation().equals(controllerName)
&& !name.getOrganisation().equals(NETWORK_MAP_NAME))
.collect(toList()));
}
//boot entry point
#SpringBootApplication
public class FacilityServer {
#Autowired
public static NodeRPCConnection nodeRPCConnection;
/**
* Starts our Spring Boot application.
*/
public static void main(String[] args) throws Exception {
SpringApplication springApplication = new SpringApplication();
springApplication.setBannerMode(Banner.Mode.OFF);
springApplication.run(FacilityServer.class, args);
}
#EventListener(ApplicationReadyEvent.class)
public void initiateFacilityObserverPostStartup() throws Exception{
FacilityObserver.startFacilityWatch();
}
// this class for using the jersey instead of spring rest impltn
#Configuration
#ApplicationPath("rest")
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
}
#PostConstruct
public void setUp() {
register(MarketApi.class);
//register(GenericExceptionMapper.class);
}
}
I found the solution ;According to the corda documentation we need to register cordajackson mapper .Then, we will be able to get the same response as in corda webserer.
for example:
List<StateAndRef<YourState>> vaultStatesList = vaultStates.getStates();
ObjectMapper mapper = JacksonSupport.createNonRpcMapper();
String json = mapper.writeValueAsString(vaultStatesList);

Test Spring Mvc controller and inject static class

The following code is the standard method to write a JUnit test for a Mvc controller.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = ApplicationTestCassandra.class)
#WebAppConfiguration
public class TestControllerTests {
#Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
#Before
public void setup() throws Exception {
this.mockMvc = webAppContextSetup(webApplicationContext).build();
}
#Test
public void testupTimeStart() throws Exception {
this.mockMvc.perform(get("/uptime"))
.andExpect(status().isOk());
}
}
This works fine, but I would like to replace an autowired class with a special class for testing. The class CassandraSimpleConnection is injected via #Autowired in my controller.
I have tried several approaches, but no luck.
The following code fails because of an Mvc 404 error, because I guess my application with the REST interface is not running at all.
#RunWith(SpringJUnit4ClassRunner.class)
//ApplicationTestCassandra is SpringBoot application startpoint class with #SpringBootApplication annotation
//#ContextConfiguration(classes = ApplicationTestCassandra.class, loader = AnnotationConfigContextLoader.class)
#ContextConfiguration(loader = AnnotationConfigWebContextLoader.class)//, classes = {ApplicationTestCassandra.class})
#WebAppConfiguration
public class TestControllerTests {
#Service
#EnableWebMvc
#ComponentScan(basePackages={"blabla.functionalTests"})
static class CassandraSimpleConnection {
public Metadata testConnection(TestConfiguration configuration) {
Metadata metadata = null;
// return metadata;
throw new RuntimeException("Could not connect to any server");
}
}
If I use
#ContextConfiguration(loader = AnnotationConfigWebContextLoader.class, classes = {ApplicationTestCassandra.class})
CassandraSimpleConnection is not replaced with my static class.
Could somebody help me please? The documentation about the annotations is quite confusing.
Read the comments and here is the solution:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = { MyApplication.class })
public class MyTests {
#MockBean
private MyBeanClass myTestBean;
#Before
public void setup() {
...
when(myTestBean.doSomething()).thenReturn(someResult);
}
#Test
public void test() {
// MyBeanClass bean is replaced with myTestBean in the ApplicationContext here
}
}

How to write a mockito test case for ResourceAssembler with in Spring Hateos?

I am trying to write a unit test for the below Assembler but i keep getting Could not find current request via RequestContextHolder. Is this being called from a Spring MVC handler?. I wanted to know how i can mock out the resource creation?
#Component
public class LoginResourceAssembler extends ResourceAssemblerSupport<User, ResourceSupport> {
public LoginResourceAssembler() {
super(User.class, ResourceSupport.class);
}
#Override
public ResourceSupport toResource(User user) {
ResourceSupport resource = new ResourceSupport();
final String id = user.getId();
resource.add(linkTo(MyAccountsController.class).slash(id).slash("accounts").withRel("accounts"));
return resource;
}
}
Instead of changing from a plain unit test to a IMO integration test (given dependency of the spring framework) you could do something like:
#RunWith(MockitoJUnitRunner.class)
public class LoginResourceAssemblerTest {
#InjectMocks
private LoginResourceAssembler loginResourceAssembler;
#Before
public void setup() {
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(new MockHttpServletRequest()));
}
#Test
public void testToResource() {
//...
}
}
I was seeing the error Could not find current request via RequestContextHolder. Is this being called from a Spring MVC handler because my test class was annotated with #RunWith(MockitoJUnitRunner.class) and this was not injecting the controller.
To fix this error, i annotated my test case with
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
A working test case in my case
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
public class LoginResourceAssemblerTest {
#Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
#InjectMocks
private LoginResourceAssembler loginResourceAssembler;
#Before
public void setUp() {
initMocks(this);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
#Test
public void testToResource() {
User user = new User();
user.setId("1234");
ResourceSupport resource = loginResourceAssembler.toResource(user);
assertEquals(1,resource.getLinks().size());
assertEquals("accounts",resource.getLinks().get(0).getRel());
assertTrue(resource.getLinks().get(0).getHref().contains("accounts"));
}
}

Spring MVC - How to create a proper Service layer?

I'm using SpringBoot and I am trying to create a service layer for my web application but i cant make it work.
My classes look like this
ServiceFactory
#Service
public class ServiceFactory {
#Autowired
public static EncuestaService getEncuestaService()
{
return new EncuestaServiceImpl();
}
}
EncuestaService
public interface EncuestaService {
void crearEncuesta(Encuesta encuesta, Map<String,String> parametros);
}
EncuestaServiceImpl
#Service
public class EncuestaServiceImpl implements EncuestaService {
#Override
public void crearEncuesta(Encuesta encuesta, Map<String, String> parametros) {
CrearEncuesta nueva = new CrearEncuesta(encuesta,parametros);
nueva.execute();
}
}
CrearEncuesta
#Service
public class CrearEncuesta {
private Encuesta encuesta;
private Map<String,String> parametros;
#Autowired
private RespuestasRepository respuestasRepository;
#Autowired
private EncuestasRepository encuestasRepository;
public CrearEncuesta(Encuesta encuesta, Map<String,String> parametros) {
super();
this.encuesta = encuesta;
this.parametros = parametros;
}
public void execute()
{
encuestasRepository.save(encuesta);
}
}
Everytime I call ServiceFactory.getEncuestasService().crearEncuesta() from any Controller it returns me a NullPointerException.
From what I have been reading I should not be creating a new EncuestsaServiceImpl() in my ServiceFactory but I don't really know the correct way to do so. I would appreciate if anyone could help me out :P.
Edit:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
Controller
#Controller
public class EncuestaController {
#RequestMapping(value ="registrarEncuesta", method = RequestMethod.POST)
private String formularioEncuesta(#Valid #ModelAttribute("formEncuesta") EncuestaForm formEncuesta, BindingResult bindingResult,#RequestParam Map<String,String> allRequestParams)
{
if (bindingResult.hasErrors()) {
return "nuevaEncuesta";
}
try {
Encuesta nueva = formEncuesta.toEncuesta();
ServiceFactory.getEncuestaService().crearEncuesta(nueva,allRequestParams);
} catch (DataIntegrityViolationException e) {
return "nuevaEncuesta";
}
return "redirect:/encuestas";
}
}
You will have to read a little bit more about dependency injection. The central principle in Spring Framework is dependency injection which should be used to avoid referencing beans (service implementations, repository implementations etc...) statically. Spring container also servers as a bean factory that will instantiate and inject (autowire) implementations to beans that need them.
Because Spring will instantiate service interface implementations for you, you don't need ServiceFactory. In your controller you need to add a reference (a field) to EncuestaService and annotate it as Autowired and Spring will wire in the implementation. And then you can just use it in your controller.
#Controller
public class EncuestaController {
#Autowired
EncuestaService encuestaService;
#RequestMapping(value ="registrarEncuesta", method = RequestMethod.POST)
private String formularioEncuesta(#Valid #ModelAttribute("formEncuesta") EncuestaForm formEncuesta, BindingResult bindingResult,#RequestParam Map<String,String> allRequestParams)
{
if (bindingResult.hasErrors()) {
return "nuevaEncuesta";
}
try {
Encuesta nueva = formEncuesta.toEncuesta();
encuestaService.crearEncuesta(nueva,allRequestParams);
} catch (DataIntegrityViolationException e) {
return "nuevaEncuesta";
}
return "redirect:/encuestas";
}
}

Resources