Changed entity found with old values in an integration test - java

I have the following repository:
#Repository
public interface UserRepository extends JpaRepository<User, String> {
Optional<User> findUserByUniqueName(String uniqueName);
}
In an integration test, first, I change the uniqueName field of a user entity and save it to database. then I call an endpoint with mockMvc and add the oldUniqueName to the headers of the request.
#Test
#Transactional
void test() {
User user =
userRepository.findUserByUniqueName("oldUniqueName").orElse(null);
assertThat(user).isNotNull();
user.setUniqueName("newUniqueName");
userRepository.saveAndFlush(user);
headers = ... // adding oldUniqueName to the headers
mockMvc
.perform(get(endpointUrl).headers(headers))
.andExpect(status().isUnauthorized());
}
The request is then intercepted by a custom security filter to do some modifications in the security context. in this filter I extract the UniqueName from the request header and try to find the corresponding user in database:
#Override
#Transactional
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String oldUniqueName = extractUniqueNameFromRequest(request);
try {
User user = userRepository.findUserByUniqueName(oldUniqueName).orElseThrow(new Exception());
// update security context
}
catch(Exception e) {
// handle exception
}
}
I am expecting that the call to the repository with the oldUniqueName returns an empty Optional and therefore an exception is thrown. However, something strange happens. Although I am querying the database with a non existing uniqueName (oldUniqueName), the User Entity is found but it's uniqueName field has the value "newUniqueName". I guess it has something to do with transactions or maybe cache but can't figure it out. Does anybody know what I am doing wrong?

I'm not completely sure, but it looks like the mock mvc request runs in it's own thread and therefore transaction. Since you didn't commit the transaction of your integration test, mock mvc still sees the old data.
If this assumption is true you should be able to fix it by putting the first part of your integration test in a separate transaction.
You can do this by removing the #Transactional annotation and use TransactionTemplate instead.

Related

How do I test business logic in a servlet using Junit?

I'm having a servlet that does some pre-condition checks before invoking a DAO method, like following:
private void processRequest(HttpServletRequest request, HttpServletResponse response){
if(a condition is met)
myDAOFunction();
else
redirect();
}
How should I construct my unit test to verify whether with a certain request, the servlet invokes my function, and with other requests that does not meet the condition then it will redirect the page?
I have tried this solution: Since my DAO function would make some changes in the database if it were called, and through that I can test if the servlet handles the requests and responses correctly. But I figure that is not quite an elegant solution.
So what you need to verify if the servlet can interact with the DAO related codes correctly. If your design already separate and encapsulate all the codes related to interacting with DB in a DAO service class , you can easily test it by mocking this DAO service class using Mockito and then verify if the expected methods on the mock DAO service are invoked with the expected parameters. If not , please refractor your codes such that it will have this separate DAO service class.
For mocking MockHttpServletRequest and MockHttpServletResponse , spring-test already provides some utilities to create them which are useful for testing the Servlet stuff. Although they are primarily designed to work with the codes written by spring-mvc , it should also be used for the codes that are not written by spring and should be more convenient to use when compared Mockito.
Assuming your servlet is called FooBarServlet, the test case may look like :
#ExtendWith(MockitoExtension.class)
public class FooBarServletTest {
#Mock
DaoService daoService;
#Test
void testSaveToDatabase(){
FooBarServlet sut = new FooBarServlet(daoService);
MockHttpServletRequest request = MockMvcRequestBuilders.get("/foobar")
......
.buildRequest(new MockServletContext());
MockHttpServletResponse response = new MockHttpServletResponse();
sut.processRequest(request, response);
verify(daoService).save("xxxxxx");
}
#Test
void testRedirect(){
FooBarServlet sut = new FooBarServlet(daoService);
MockHttpServletRequest request = MockMvcRequestBuilders.get("/foobar")
......
.buildRequest(new MockServletContext());
MockHttpServletResponse response = new MockHttpServletResponse();
sut.processRequest(request, response);
verify(daoService,never()).save(any());
}
}

Handle exceptions in a rest controller in Spring Boot

I create REST web-service with Spring Boot.
I would like to know what is a better way to handle exceptions in a controller. I have seen other questions and didn’t found an answer.
My controller:
#GetMapping
public ResponseEntity<?> saveMyUser(){
MyUser myUser = new MyUser(“Anna”);
//throws SQLException
MyUserDetails userDetails = userService.saveMyUser(myUser);
//if successful
return ResponseBody.ok(userDetails);
}
saveMyUser() method of UserService:
public MyUserDetails saveUser(MyUser) throws SQLException {...}
So at this point I have at least 2 simple options:
Add exception to method signature.
Here I may rely on Spring Boot to pass all information about exception and status code to a client. However do not know if it is a reliable approach.
Surround with try/catch and pass all information about exceptions manually.
What is a better simple way?
You can create an additional class with #ControllerAdivce annotation and later you will be able to write custom response logic for each exception e.g:
#ControllerAdvice
public class GlobalExceptionHandler {
#ExceptionHandler({SQLException.class})
public ResponseEntity<Object> sqlError(Exception ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Some SQL exception occured");
}
}
Also, you can extend ResponseEntityExceptionHandler and override the default behavior for mapping from exceptions to HTTP response.
Also, take a look at this, it holds very usefull information for your case.

How to read request headers from incoming message in a graphQL endpoint in spring boot application

I have a spring boot application running with a graphql endpoint that validates and executes queries and mutations, however, I need to read one header in the incoming message in order to pass its value to another endpoint. Is there a way in graphql to read these values? some sort of getHeaders or something like that?
GraphQL itself does not define any things related to how to expose it over the network , so it does not define any things related to get HTTP header.It is up to developers to use their ways.So, it depends on the underlaying technologies you use to serve GraphQL over HTTP.
Consider you use graphql-spring-boot and graphql-java-tools , and assuming that you does not customize GraphQLContext , you can try to add DataFetchingEnvironment argument to your resolver function and then get the GraphQLContext from it. You can then get HttpServletRequest from the context and access the headers :
public Foo resolveFoo(Map<String,String> input , DataFetchingEnvironment env){
GraphQLContext context = env.getContext();
HttpServletRequest request = context.getHttpServletRequest().get();
request.getHeader("content-type");
}
The solution by #Ken Chan was not working for me. GraphQLContext had no method named getHttpServletRequest.
Solved it by using GraphQLServletContext instead. You can change the code to:
public Foo resolveFoo(Map<String,String> input , DataFetchingEnvironment env){
GraphQLServletContext context = env.getContext();
String header = context.getHttpServletRequest().getHeader("content-type");
}
Apparently the type of the context is not standardized. I use SPQR, and in my case I discovered (via debug):
DefaultGlobalContext<ServletWebRequest> context = handlerParameters.getDataFetchingEnvironment().getContext();
context.getNativeRequest().getHeader("something");
Not a direct answer to your problem statement, but one can use a Filter to handle it before the request hits the resolver endpoints (if that's a requirement):
public class HeaderFilter implements Filter {
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) {
final HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String headerVal= httpServletRequest.getHeader("<header string>");
try {
filterChain.doFilter(httpServletRequest, servletResponse);
} catch (IOException | ServletException e) {
//handle as you wish
}
}
These answers are too old, for latest versions. There are two ways (1) you can try to autowire one HttpServletRequest in your controller, such as
#Slf4j
#Controller
public class YourQueryController {
#Autowired
private HttpServletRequest request;
....
Then implement following logic to get header:
request.getHeader("Authorization")
(2) To make use of out-of-box support of RequestContextHolder over HTTP requests
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
val authorization = attributes.getRequest().getHeader("Authorization");
Google brought me this answer and unfortunately it was for Spring framework. Many use Spring framework but if you use Apache Tomcat with GraphQL integration like I do, you can do use this.
graphql.kickstart.servlet.context.DefaultGraphQLServletContext.DefaultGraphQLServletContext context = dataFetchingEnvironment.getContext();
jakarta.servlet.http.HttpServletRequest request = context.getHttpServletRequest();
String tokenBearer = request.getHeader("Authorization");
hth

Mock SpringContextHolder using MockMVC

I am writing unit test cases for Controller layer. I have a call where i am getting user from Spring SecurityContextHolder. When i run my test case i get Null pointer exception because I don't know how to mock Spring security context.
Below is my code, any suggestion how to do it?
Controller Methhod:
#RequestMapping(method = RequestMethod.POST)
public void saveSettings(#RequestBody EmailSettingDTO emailSetting) {
User user = ((CurrentUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUser();
settings.saveUserEmailSetting(user, emailSetting);
}
My Test case :
#Test public void testSaveSettings() throws Exception {
mockMvc.perform(post(BASE_URL).content(this.objectMapper.writeValueAsString(emailDto))
.contentType(MediaTypes.HAL_JSON)).andExpect(status().isOk());
}
There is a Spring Security Test library for this purpose.
You can use #WithMockUser to achieve this. See the post
You can use #WithUserDetails
this annotation can be added to a test method to emulate running with a UserDetails returned from the UserDetailsService.
By using this, you create a context to run a test in, for example:
#Test
#WithUserDetails("admin")
public void testAdmin() throws Exception {
mockMvc.perform(...);
}
This will execute testAdmin() with the SecurityContext of admin.
But please note, in order to use this; there must be a User persisted with the name admin, otherwise you will get result exceptions.

Obtaining actual parameter values in a Jersey ResourceFilterFactory

I want to implement custom authorisation in my REST services using Jersey. This custom authorisation inspects annotations on methods as well as the actual parameters that a
method receives.
My jax-rs annotated method looks like:
#GET
#Path("customers")
#Requires(Role.CustomerManager)
public Customer getCustomer(#ParseFromQueryString #CheckPermission final Customer customer) {
// ...
}
The #ParseFromQueryString is an annotation that indicates Jersey (through an Injectable provider) to unmarshall a Customer from a query string. The code for that looks like:
public class QueryStringCustomerInjectable implements Injectable<Customer> {
public Customer getValue() {
final Customer customer = new Customer();
// ... a UriInfo was injected using the #Context annotation
// ... extract parameters from QueryString and use setters
return customer;
}
}
The #CheckPermission annotation indicates my custom authoriser that permissions are to be checked on a customer. Some users have access to information on some customers. Similarly, the #Requires annotation takes a role that the invoker should have. These are not java's security roles (Strings), rather, they are enum values.
Using Jersey's ResourceDebuggingFilter as a starting point, I have been able to get to the point of knowing which method will be invoked. However, I still haven't figured out how to determine which parameters will actually be used to invoke the method.
At the top of my head, I can think of two work arounds:
A Method interceptor using Guice + Jersey.
Code this logic in the QueryStringCustomerInjectable, but this seems a bit sloppy. It would be a class doing too much.
Yet, I would really like to do this using only Jersey / JAX-RS. I feel that I am so close!
Ideas? Pointers?
Thanks!
You should use Filters or Interceptors to handle all the information about method.
see Jersey Filter and Interceptors
For the Customer deserialization you could implement the javax.ws.rs.ext.ParamConverterProvider and register it into Jersey. Then you can inject it into your methods with #QueryParam("customer"). It's a bit more flexible since you can use it also with #BeanParam or #PathParam annotations.
Then you can use the ContainerRequestFilter. See as a reference how jersey does the Oauth1 for example OAuth1ServerFilter.
The next thing you can do is to create maybe a feature which will register the newly created filter (see Oauth1ServerFeature for a reference - I couldn't find the source code right now).
Good luck!
Why not using your own Servlet filter e.g.
public class YourFilter implements Filter {
...
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
// HttpServletRequest httpReq = (HttpServletRequest) request;
// HttpServletResponse httpResp = (HttpServletResponse) response;
// HttpServletRequest httpReq = (HttpServletRequest) request;
// HttpServletResponse httpResp = (HttpServletResponse) response;
// ..... httpReq.getUserPrincipal();
// then set what you need using ThreadLocal and use it inside your resource class
// do not forget to call
filterChain.doFilter(request, response); // at the end of this method
}
The last step is to register your servlet filter. This is done using web app's web.xml
It will intercept your HTTP requests before the actual code inside jersey resource is called.

Categories

Resources