Building simple http-header for Junit test - java

I'm trying to test a HttpServletRequest and for that I have used Mockito as follow:
HttpServletRequest mockedRequest = Mockito.mock(HttpServletRequest.class);
now before putting the http-request in assert methods I just want to build a simple http header as below without starting a real server:
x-real-ip:127.0.0.1
host:example.com
x-forwarded-for:127.0.0.1
accept-language:en-US,en;q=0.8
cookie:JSESSIONID=<session_ID>
can some one help how can I build such a test header? thanks.

You can just stub the calls to request.getHeaders etc. or if you can add a dependency, Spring-test has a MockHttpServletRequest that you could use (see here)
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("x-real-ip","127.0.0.1");
Or you could build your own implementation which allows you to set headers.

The above answer uses MockHttpServletRequest.
If one would like to use Mockito.mock(HttpServletRequest.class) , then could stub the request as follows.
final HttpServletResponse response = mock(HttpServletResponse.class);
when(request.getHeader("host")).thenReturn("stackoverflow.com");
when(request.getHeader("x-real-ip")).thenReturn("127.0.0.1");

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());
}
}

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

Add basic http authentication to MockWebServiceClient

I have som old test that are calling some web services. There was no security on the webservice before. Now basic http authentication has been added to it and test are therefore failing. Test are using org.springframework.ws.test.server.MockWebServiceClient
example of test:
#Autowired
MockWebServiceClient mockClient
def "import valid entity"() {
setup:
def request = loadEntitesToRequest(validEntityFile)
Source requestPayload = createStringSourceFromObject(request)
when: 'Endpoint is requested to import valid entity'
mockClient.sendRequest(withPayload(requestPayload)).andExpect(new ResponseMatcher() {
void match(WebServiceMessage req, WebServiceMessage resp) {
EntityImportResponse response = marshaller.unmarshal(resp.payloadSource)
assert response.errorMessage.isEmpty()
assert response.isSuccess()
}
})
then: 'Entity is successfully imported'
noExceptionThrown()
}
Is there any way to add basic http auth to this client? I know how to add it to WebServiceTemplate but for this i have not found any way.
well, this question is actually a bad one, MockWebserviceClient doesn't deal with http at all, you need to set what you need in http requests outside of this client

Testing MockRestServiceServer spring-test with multipart request

Recently I've started to use Spring's MockRestServiceServer to verify my RestTemplate based requests in tests.
When its used for simple get/post request - all good, however, I couldn't figure out how to use it with POST multipart request:
For example, my working code that I would like to test looks like this:
public ResponseEntity<String> doSomething(String someParam, MultipartFile
file, HttpHeaders headers) { //I add headers from request
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("file", new ByteArrayResource(file.getBytes()) {
#Override
public String getFilename() {
return file.getOriginalFilename();
}
});
map.add("someParam", someParam);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new
HttpEntity<>(map, headers);
return this.restTemplate.exchange(
getDestinationURI(),
HttpMethod.POST,
requestEntity,
String.class);
}
So my question is How I can specify my expectations with org.springframework.test.web.client.MockRestServiceServer? Please notice, that I don't want to just mock the "exchange" method with mockito or something, but prefer to use MockRestServiceServer
I'm using spring-test-4.3.8.RELEASE version
A code snippet would be really appreciated :)
Thanks a lot in advance
Update:
As per James's request I'm adding non-working test snippet (Spock test):
MockRestServiceServer server = MockRestServiceServer.bindTo(restTemplate).build()
server.expect(once(), requestTo(getURI()))
.andExpect(method(HttpMethod.POST))
.andExpect(header(HttpHeaders.CONTENT_TYPE, startsWith("multipart/form-data;boundary=")))
.andExpect(content().formData(["someParam" : "SampleSomeParamValue", "file" : ???????] as MultiValueMap))
.andRespond(withSuccess("sample response", MediaType.APPLICATION_JSON))
multipartFile.getBytes() >> "samplefile".getBytes()
multipartFile.getOriginalFilename() >> "sample.txt"
I get exception while asserting the request content. The form data is different, because an actual form data is created internally with Content-Disposition, Content-Type, Content-Length per parameter and I don't know how to specify these expected values
Multipart request expectations have been added to MockRestServiceServer in Spring 5.3 - see:
pull request
final version
You can use
content().multipartData(MultiValueMap<String, ?> expectedMap)
Parse the body as multipart data and assert it contains exactly the values from the given MultiValueMap. Values may be of type:
String - form field
Resource - content from a file
byte[] - other raw content
content().multipartDataContains(Map<String,?> expectedMap)
Variant of multipartData(MultiValueMap) that does the same but only for a subset of the actual values.
I think this depends on how deeply you want to test the form data. One way, which is not 100% complete, but is a "good enough" for unit testing (usually) is to do something like:
server.expect(once(), requestTo(getURI()))
.andExpect(method(HttpMethod.POST))
.andExpect(content().string(StringContains.containsString('paramname=Value') ))....
This is ugly and incomplete, but is sometimes useful. Of course, you can also work to make the form setup it's own method and then use mocks to try to verify that the expected parameters are all in place.

Cloud Endpoints: Access Paramters in Servlet Filter

I'm trying to build an api with Google Cloud Endpoints.
As Cloud Endpoints does not provide authentication beside Googles own OAuth I try to build my own. Therefore I want to access the parameters provided for the API (for example #Named("token") token) inside a servlet filter.
Unfortunately I cannot find any of the provided information inside the httpRequest. Is that normal? Is there a possibility to access the parameters?
I would appreciate if someone could help me!
UPDATE:
With the infos from jirungaray I tried to build an authentication using headers but ran into the same problem. Used a REST-Client to send some headers as I could not figure out how to do this with the API Explorer. Inside my filter I try to access the token from the headers:
#Override
public void doFilter(
ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String authToken = httpRequest.getHeader(Constants.AUTH_TOKEN);
...
chain.doFilter(request, response);
}
The reason why I try to do something like this, is that I'm using Guice for Dependency Injection and want my token to be injected inside another object.
With Guice I have the following Provider using the token to inject a FacebookClient (using the token) per request.
#Provides
public FacebookClient getFacebookClientProvider(#Named("fbToken") Provider<String> fbToken) {
return new DefaultFacebookClient(fbToken.get(), Version.VERSION_2_2);
}
As described in the Guice wiki (SevletModule) this uses a sevlet filter to get the information from the request.
Is there any solution to achieve this kind of DI with Cloud Endpoints?
Philip,
Yes, it does makes sense you are getting an empty request. Your endpoint calls are first handled by Google (they receive the API calls) and then those are processed and sent to a handler in your app. As this is all done in the background it's very easy to miss that your endpoints aren't actually getting the same request you sent, they get a completely different request sent from Google's infrastructure.
Even though your approach should work including tokens info in url makes them easier to sniff, even if you use SSL or encrypt your params the token is there in plain sight.
For what you are trying to achieve I recommend you include the token as a header in your request and retrieve that header by accessing the HTTPRequest directly on the endpoint, this is injected automatically if you include an HTTPServletRequest param in you endpoint method.
eg.
public APIResponse doSomething(SomeComplexRquestModel request,
HttpServletRequest rawRequest) {
}
If you still feel you should go with your original approach just comment and I'll help you debug the issue.

Categories

Resources