SecurityContextLogoutHandler testing problem - junit

Is there any way to test this using JUnit and Mockito?
Below is a method that I want to test
#RequestMapping(value = "/logout", method = RequestMethod.GET)
public String logoutPage(HttpServletRequest request, HttpServletResponse response)
{
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null)
{
new SecurityContextLogoutHandler().logout(request, response, auth);
}
return "redirect:/login?logout";
}
Test for logout
#Test
public void testLogoutPage() throws Exception
{
MockHttpServletRequestBuilder requestBuilder = get("/logout");
MockMvcBuilders.standaloneSetup(this.loginController)
.build()
.perform(requestBuilder)
.andExpect(status().isFound())
.andExpect(MockMvcResultMatchers.model().size(0))
.andExpect(view().name("redirect:/login?logout"))
.andExpect(MockMvcResultMatchers.redirectedUrl("/login?logout"));
}
Test covers everything except.
new SecurityContextLogoutHandler().logout(request, response, auth);
I tried some assertions, but always get NullPointerException.

Related

unit test spring controller with WebTestClient and ControllerAdvice

I'm trying to unit test my controller and the specific case which is : my service return a Mono.Empty, I throw a NotFoundException and I wan't to make sure I'm getting a 404 exception
here's my controller :
#GetMapping(path = "/{id}")
public Mono<MyObject<JsonNode>> getFragmentById(#PathVariable(value = "id") String id) throws NotFoundException {
return this.myService.getObject(id, JsonNode.class).switchIfEmpty(Mono.error(new NotFoundException()));
}
Here's my controller advice :
#ControllerAdvice
public class RestResponseEntityExceptionHandler {
#ExceptionHandler(value = { NotFoundException.class })
protected ResponseEntity<String> handleNotFound(SaveActionException ex, WebRequest request) {
String bodyOfResponse = "This should be application specific";
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Resource not found");
}
}
and my test :
#Before
public void setup() {
client = WebTestClient.bindToController(new MyController()).controllerAdvice(new RestResponseEntityExceptionHandler()).build();
}
#Test
public void assert_404() throws Exception {
when(myService.getobject("id", JsonNode.class)).thenReturn(Mono.empty());
WebTestClient.ResponseSpec response = client.get().uri("/api/object/id").exchange();
response.expectStatus().isEqualTo(404);
}
I'm getting a NotFoundException But a 500 error not a 404 which mean my advice hasn't been called
stack trace :
java.lang.AssertionError: Status expected:<404> but was:<500>
> GET /api/fragments/idFragment
> WebTestClient-Request-Id: [1]
No content
< 500 Internal Server Error
< Content-Type: [application/json;charset=UTF-8]
Content not available yet
any idea ?
I believe you can delete this controller advice and just have the following:
#GetMapping(path = "/{id}")
public Mono<MyObject<JsonNode>> getFragmentById(#PathVariable(value = "id") String id) {
return this.myService.getObject(id, JsonNode.class)
.switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND)));
}
As for ResponseEntityExceptionHandler, this class is part of Spring MVC so I don't think you should use it in a WebFlux application.

Spring Boot replace ServletException response in Filter

I have a Spring Boot Filter that I'm using to authenticate using Jwt. If successful, everything works great and I send out a Json response of my design. However, if the Authorization header is missing or incorrect, I throw a ServletException with a custom message. This results in an ugly Json that looks like this:
{
"timestamp":1453192910756,
"status":500,
"error":"Internal Server Error",
"exception":"javax.servlet.ServletException",
"message":"Invalid Authorization header.",
"path":"/api/test"
}
I wish to customize this Json so it takes the standard form I'm using for all my other responses.
My Filter code is here:
public class JwtFilter extends GenericFilterBean {
#Override
public void doFilter(final ServletRequest req,
final ServletResponse res,
final FilterChain chain) throws IOException, ServletException {
System.out.println("JwtFilter");
final HttpServletRequest request = (HttpServletRequest) req;
final String authHeader = request.getHeader("Authorization");
if (authHeader == null) {
throw new ServletException("Missing Authorization header.");
}
if (!authHeader.startsWith("Bearer ")) {
throw new ServletException("Invalid Authorization header.");
}
final String token = authHeader.substring(7);
try {
final Claims claims = Jwts.parser().setSigningKey("secretkey")
.parseClaimsJws(token).getBody();
request.setAttribute("claims", claims);
}
catch (final SignatureException e) {
throw new ServletException("Invalid token.");
}
chain.doFilter(req, res);
}
}
I tried using a wrapper to wrap the response but that didn't work. Another SO post said the response was not changeable but that wouldn't even make sense.
I think the correct way would be to edit the ServletResponse res but I couldn't get it to work.
Thanks!
EDIT: Kind of hacky but it works. If there's a better way, please answer:
public class JwtFilter extends GenericFilterBean {
#Override
public void doFilter(final ServletRequest req,
final ServletResponse res,
final FilterChain chain) throws IOException, ServletException {
System.out.println("JwtFilter");
final HttpServletRequest request = (HttpServletRequest) req;
final String authHeader = request.getHeader("Authorization");
if (authHeader == null) {
res.setContentType("application/json;charset=UTF-8");
res.getWriter().write(ExceptionCreator.createJson("Missing Authorization header."));
return;
}
if (!authHeader.startsWith("Bearer ")) {
res.setContentType("application/json;charset=UTF-8");
res.getWriter().write(ExceptionCreator.createJson("Invalid Authorization header."));
return;
}
final String token = authHeader.substring(7);
try {
final Claims claims = Jwts.parser().setSigningKey("secretkey")
.parseClaimsJws(token).getBody();
request.setAttribute("claims", claims);
}
catch (Exception f) {
res.setContentType("application/json;charset=UTF-8");
res.getWriter().write(ExceptionCreator.createJson("Invalid token."));
return;
}
chain.doFilter(req, res);
}
}
In general, wrapping the response and then modifying the response output stream after the call to doFilter is the correct approach, e.g.
PrintWriter out = response.getWriter();
CharResponseWrapper wrapper = new CharResponseWrapper(
(HttpServletResponse)response);
chain.doFilter(request, wrapper);
CharArrayWriter caw = new CharArrayWriter();
caw.write("your json");
response.setContentLength(caw.toString().getBytes().length);
out.write(caw.toString());
out.close();
Taken from Oracle JavaEE 5 Tutorial
Nevertheless, your usecase seems more appropriate for being dealt with in a RestController handler method, possibly in conjunction with an #ExceptionHandler(ServletException.class) annotated method. This would be a more generic approach that allows you to harness the power of Spring's content negotiation to deal with the JSON serialization.

How to write test cases for jersey api using Junit for testing the api response and parameters?

This is my api i have used Jersey and spring boot.The api is working fine producing correct response and I want to write unit test case for checking api using Junit.
#POST
#Path("/trip/create")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response createTrip(Trip pObjTrip, #HeaderParam("Auth-Token") String pAuthToken) {
Response lRetVal = new Response();
appLog.info(String.format("Creating a trip with [%s]", pObjTrip));
try {
User lObjUser = validateUser(pAuthToken, lRetVal);
if(lObjUser == null) {
} else if (StringUtils.isEmpty(pObjTrip.getTripName())) {
lRetVal.setResult(ResponseIds.API_RESULT_INSUFFICIENT_INFO);
lRetVal.setMessage("All information are not provided");
} else {
lObjUser.setEnabled(true);
pObjTrip.setCreatedBy(lObjUser);
pObjTrip.setCreateTime(Calendar.getInstance());
pObjTrip.setTripStatus(Trip.TRIP_STATUS_CREATED);
m_cObjTripService.saveAndFlush(pObjTrip);
lRetVal.setResult(ResponseIds.API_RESULT_SUCCESS);
lRetVal.setValue(pObjTrip);
}
} catch (Exception ex) {
appLog.warn(ex.toString(), ex);
}
return lRetVal;
}
I have written the test case after searching But getting 400 bad request for(http://localhost:8080/api/trphpr/trip/create).
#After(value = "http://localhost:8080/api/trphpr/trip/create")
public void testCreateTripApi() throws IOException{
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>(2);
map.add("tripNme", "test trip");
org.springframework.http.HttpHeaders lhttpheader = new org.springframework.http.HttpHeaders();
lhttpheader.add("Auth-Token", "7f8b655a007dda8f93a77fcb44de3298efb67615a5585b2fdc6c95b4cc2c4a52282deae6119a2fd6c3f9b4e3723e3d1cb221376ed36d978f0ff31b585d8e70f4");
lhttpheader.setContentType(MediaType.APPLICATION_JSON);
List<HttpMessageConverter<?>> msgConverters = restTemplate.getMessageConverters();
msgConverters.add(new MappingJackson2HttpMessageConverter());
restTemplate.setMessageConverters(msgConverters);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, lhttpheader);
Response apiResponse = (Response) restTemplate.postForObject("http://localhost:8080/api/trphpr/trip/create", request, Response.class);
assertNotNull(apiResponse);
//Asserting the response of the API.
String message = apiResponse.getMessage();
Trip ltrip = (Trip)apiResponse.getValue();
assertEquals("trip created successfully", message);
assertEquals("trip test", ltrip.getTripName());
}
}

How to write EasyMock Unit test for http call timeout?

final HttpResponse response = this.call(queryUri);
entity = response.getEntity();public HttpResponse call(final URI queryUri) throws Exception
{
Future<HttpResponse> futureResponses = executor.submit(new Callable<HttpResponse>()
{
#Override
public HttpResponse call() throws Exception
{
final HttpGet httpget = new HttpGet(queryUri);
return httpclient.execute(httpget);
}
});
return futureResponses.get(A9_CALL_TIMEOUT, TimeUnit.MILLISECONDS);
}
final HttpResponse response = this.call(queryUri);
entity = response.getEntity();
parse(entity.getcontent());
wondering how do I mock all the object, can someone provide me the workable code on test class?
I would recommend that you pull out the creation of the Callable to a protected method.
public Callable<HttpResponse> createCallable(String queryUri){
return new Callable<HttpResponse>(){
#Override
public HttpResponse call() throws Exception
{
final HttpGet httpget = new HttpGet(queryUri);
return httpclient.execute(httpget);
}
});
}
I don't think you actually need EasyMock for this test. In fact it might be easier without it. In your test you can override this method to return a test stub. I think if the get times out, then it will throw a TimeoutException and not actually cancel the job. So I think you just need to catch TimeoutException to make sure everything works.
So maybe your mock just has to sleep for A9_CALL_TIMEOUT plus some additional fudge factor.
#Test
public void testTimeout(){
Subclass sut = new Subclass(){
#Override
public Callable<HttpResponse> createCallable(String queryUri){
return new Callable<HttpResponse>(){
#Override
public HttpResponse call() throws Exception{
try{
Thread.sleep(A9_CALL_TIMEOUT *2);
catch(InterruptException e) {}
}
});
};
//you can also use Junit ExpectedException rule instead
// of the try catch here
try{
sut.runQueryMethodWithExecutor();
fail("should throw timeout");
}catch(TimeoutException e){
//expected
}
}

spring mvc 3 content-type "application/json" works from client but not from unit test

I have a Rest Controller method using Spring 3.1 that looks like this:
#RequestMapping(value="/user", method=RequestMethod.POST, consumes={MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<String> addUser(#RequestBody #Valid User user){
System.out.println("called / user method");
try{
user = userService.addUser(user);
return responseBuilder.addApiResourceSucceeded(user,null);
}catch(Exception e){
return responseBuilder.apiActionFailed("user already exists", HttpStatus.CONFLICT);
}
}
I have test which looks like this:
#Before
public void setUp() {
adapter = new AnnotationMethodHandlerAdapter();
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
mapper = new ObjectMapper();
}
#Test
public void testAddUser() throws Exception {
request.setMethod("POST");
request.setContentType(MediaType.APPLICATION_JSON_VALUE);
request.setRequestURI("/user");
ObjectNode userJson = mapper.createObjectNode();
userJson.put("userId", "jonnybz");
userJson.put("email", "test#gmail.com");
userJson.put("password", "password");
userJson.put("longitude",-10.127205999);
userJson.put("latitude", 57.252269);
ArrayNode arrNode = mapper.createArrayNode();
arrNode.add(-10.1272059999);
arrNode.add(57.2522);
userJson.put("lonLat",arrNode);
request.setContent(mapper.writeValueAsBytes(userJson));
adapter.handle(request, response, userController);
String content = response.getContentAsString();
assertEquals(200, response.getStatus());
User user = dao.listAll().get(0);
objectId = user.getId();
assertNotNull(objectId);
}
When I execute a call against this endpoint from my client app (developed with angular) it works great, but when I run my test I get an " Content type 'application/json' which is coming from a HttpMediaTypeNotSupportedException" error that I cannot track down. The request never seems to hit my method. Am I missing something simple here?
Solved this problem by switching to the spring-mvc-test framework and building my test like this:
#Test
public void testAddUser() throws Exception {
ObjectNode userJson = mapper.createObjectNode();
userJson.put("userId", "jonnbz");
userJson.put("email", "test#gmail.com");
userJson.put("password", "password");
userJson.put("longitude",-10.667205999);
userJson.put("latitude", 74.252269);
ArrayNode arrNode = mapper.createArrayNode();
arrNode.add(-10.667205999);
arrNode.add(74.252269);
userJson.put("lonLat",arrNode);
MvcResult res = MockMvcBuilders.xmlConfigSetup("classpath:test-context.xml").build()
.perform(MockMvcRequestBuilders.post("/user")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.body(mapper.writeValueAsBytes(userJson)))
.andExpect(status().isOk())
.andExpect(content().type(MediaType.APPLICATION_JSON))
.andReturn();
System.out.println(res.getResponse().getContentAsString());
}
You should also include a Accept header of "application/json" in your test, since you have included a consumes="application/json", Spring MVC will match the Accept header value to the consumes value and only then call the mapped method.