Perform get request in Spring using a header - junit

I'm writing a unit test that test my WebSecurity configuration.
Here is my Test :
#Test
public void access_to_a_protected_url_with_good_credentials_return_ok() throws Exception {
String accessToken = Base64.getEncoder().encodeToString(("user:password").getBytes());
MvcResult result = mvc.perform(get("/protected")
.header("Authorization", "Basic " + accessToken))
.andExpect(status().isOk());
}
Is there a way to simplify this test without passing the authorization token using the way I'm doing ?

One way, similar to yours is to build the request using MockHttpServletRequestBuilder:
#Test
public void access_to_a_protected_url_with_good_credentials_return_ok() throws Exception {
String accessToken = Base64.getEncoder().encodeToString(("user:password").getBytes());
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Authorization", "Bearer "+accessToken);
MockHttpServletRequestBuilder mockReqBuilder = get("/protected").headers(httpHeaders);
ResultActions actions = mockMvc.perform(mockReqBuilder);
actions.andExpect(status().isOk());
}
Did I understand your question correctly?

Related

mock.method call returns null after stubbing

I am trying to test using Mockito
my class under test is
#Service
public class DynatraceAPIServiceImpl implements DynatraceAPIService {
private String apiUrl = "someurl";
private String apiToken = "sometoken";
#Override
public CreateCustomMetricResponse createCustomMetric(CreateCustomMetricRequest request) throws MonitoringException {
logger.info("Inside create custom metric");
if (request == null) {
logger.error("create metric request is null");
throw new MonitoringException("Create metric request is null");
}
String metricId = DynatraceConstants.METRIC_ID;
String displayName = request.getDisplayName();
CreateCustomMetricResponse response = httpUtils.postCustomMetric(apiUrl + "/v1/timeseries/" + metricId, apiToken, request);
if (response == null) {
logger.error("Error in creating custom metric with name : " + displayName);
throw new MonitoringException("Error in creating custom metric with name : " + displayName);
}
logger.info("Custom metric : " + displayName + " is created successfully.");
return response;
}
}
and my Test class is :
#RunWith(MockitoJUnitRunner.class)
public class DynatraceAPIServiceImplTest {
#InjectMocks
DynatraceAPIServiceImpl dynatraceAPIServiceImpl;
#Mock
DynatraceHttpUtils httpUtilsMock;
#Mock
DynatraceMonitoringUtils monitoringUtilsMock;
#Test(expected = MonitoringException.class)
public void createCustomMetricGetsNonNullResponse() throws MonitoringException {
CreateCustomMetricRequest mockRequest = CreateCustomMetricRequest.builder()
.displayName(DISPLAY_NAME)
.types(new String[] {"test-type"})
.build();
CreateCustomMetricResponse response = CreateCustomMetricResponse.builder()
.displayName(DISPLAY_NAME)
.types(new String[] {"test-type"})
.timeseriesId(TIMESERIES_ID)
.build();
boolean val = true;
when(monitoringUtilsMock.isValidMetricIdValue(anyString())).thenReturn(val);
when(httpUtilsMock.postCustomMetric(API_URL + "/v1/timeseries/" + METRIC_ID, API_TOKEN, mockRequest)).thenReturn(response);
CreateCustomMetricResponse actualRespnose = dynatraceAPIServiceImpl.createCustomMetric(mockRequest);
//verify(httpUtilsMock, times(1)).postCustomMetric(anyString(), anyString(), any(CreateCustomMetricRequest.class));
//assertEquals(actualRespnose.getDisplayName(), DISPLAY_NAME);
}
}
Here, when I execute the tests, it always end up having the response value to be null in line
CreateCustomMetricResponse response = httpUtils.postCustomMetric(apiUrl + "/v1/timeseries/" + metricId, apiToken, request);
Even if I have used when() statement to return response as I have created, it is returning null.
Really appreciate if someone can let me know what is wrong here. Thanks.
That normally happens when the params your production code uses differ from the ones that you stubbed the call with, an easy way to find out is to write the test like this
when(httpUtilsMock.postCustomMetric(any(), any(), any())).thenReturn(response);
CreateCustomMetricResponse actualRespnose = dynatraceAPIServiceImpl.createCustomMetric(mockRequest);
verify(httpUtilsMock).postCustomMetric(API_URL + "/v1/timeseries/" + METRIC_ID, API_TOKEN, mockRequest);
If you do that, you'll get a nicer error showing the difference between what your code did and what you verified it for
A better approach in general is to use 'strict stubs' so if your code does anything different to what you stubbed the mock for you'll get a nice error telling you what, where and why

How to run JUnit testing on Firebase Java with authentication?

I am currently using Firebase Authentication in my mobile app. The back end is a Spring boot application. The REST APIs on the back end relies on a token generated from Firebase Authentication to retrieve the Firebase UID (verifyIDToken method) of a user to perform further functions.
Currently, I notice that in Firebase Java API (server-based), there is no way of generating a token for a user, thus there is no easy way for me to do JUnit testing on the server that relies on user authentication. Anyone has clues on how to do so?
This is the sample code that does not work:
#RequestMapping(value = "/api/subscribeChannel/{channelid}", method = RequestMethod.GET, produces = "application/json")
public DeferredResult<Object> subscribeChannel(#PathVariable Long channelid,#RequestHeader(value=FIREBASETOKEN, required = true) String idToken) {
DeferredResult<Object> result = new DeferredResult<Object>(DEFERREDTIMEOUT);
// test it out with a locally generated token
idToken = FirebaseAuth.getInstance().createCustomToken("valid Uid");
Task<FirebaseToken> task = FirebaseAuth.getInstance().verifyIdToken(idToken)
.addOnSuccessListener(new OnSuccessListener<FirebaseToken>() {
#Override
public void onSuccess(FirebaseToken decodedToken) {
String uid = decodedToken.getUid();
logger.info("Subscribe channel on success");
// do something
ret.setStatus("success");
ret.setMessage("channel id " + channelid + " subscribed");
result.setResult(ret);
} else {
result.setErrorResult(retStatus.getMessage());
}
}
}) .addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(Exception arg0) {
Exception te = new TokenNotFoundException(idToken);
logger.error("Token Not Found for " + idToken);
result.setErrorResult(te);
}
});
return result;
}
The custom token you get is different from the ID token that you use to log on. To get an id token from a custom token, do this:
private static final String ID_TOOLKIT_URL =
"https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken";
private static final JsonFactory jsonFactory = Utils.getDefaultJsonFactory();
private static final HttpTransport transport = Utils.getDefaultTransport();
private static final String FIREBASE_API_KEY = "<your api key here>";
private String signInWithCustomToken(String customToken) throws IOException {
GenericUrl url = new GenericUrl(ID_TOOLKIT_URL + "?key="
+ FIREBASE_API_KEY);
Map<String, Object> content = ImmutableMap.<String, Object>of(
"token", customToken, "returnSecureToken", true);
HttpRequest request = transport.createRequestFactory().buildPostRequest(url,
new JsonHttpContent(jsonFactory, content));
request.setParser(new JsonObjectParser(jsonFactory));
com.google.api.client.http.HttpResponse response = request.execute();
try {
GenericJson json = response.parseAs(GenericJson.class);
return json.get("idToken").toString();
} finally {
response.disconnect();
}
}
The Java API to generate custom tokens is documented under Create custom tokens using the Firebase SDK.
From there:
String uid = "some-uid";
String customToken = FirebaseAuth.getInstance().createCustomToken(uid);

Restlet - JUnit - testing MULTIPART_FORM_DATA form Post

I was wondering what the best way to use JUnit to test a Resource for a Form post?
On a #Get I get service values via a Resource with the following:
#Test
public void testGetCollections() throws Exception {
String url ="http://localhost:14502/api/v1/collections";
Client client = new Client(Protocol.HTTP);
ChallengeResponse challengeResponse = new ChallengeResponse(ChallengeScheme.HTTP_BASIC,"user", "f399b0a660f684b2c5a6b4c054f22d89");
Request request = new Request(Method.GET, url);
request.setChallengeResponse(challengeResponse);
Response response = client.handle(request);
System.out.println("request"+response.getStatus().getCode());
System.out.println("request test::"+response.getEntityAsText());
assertEquals(200, response.getStatus().getCode());
ObjectMapper mapper = new ObjectMapper();
List<Collection> collectionList = mapper.readValue(response.getEntityAsText(), new TypeReference<List<Collection>>(){});
for(Collection collection : collectionList){
System.out.println("TITLE: "+collection.getTitle());
}
assertTrue(collectionList.size()>0);
}
On the #Post I'm trying to do the following:
#Test
public void testPostCollections() throws Exception {
String url ="http://localhost:14502/api/v1/collections";
Client client = new Client(Protocol.HTTP);
ChallengeResponse challengeResponse = new ChallengeResponse(ChallengeScheme.HTTP_BASIC,"user", "f399b0a660f684b2c5a6b4c054f22d89");
Request request = new Request(Method.POST, url);
ClientInfo info = new ClientInfo(MediaType.APPLICATION_JSON);
info.getAcceptedMediaTypes().add(
new Preference<MediaType>(MediaType.APPLICATION_JSON));
request.setClientInfo(info);
request.setEntity(
"collectionName=testCollection123&collectionDescription=testCollectionDescription123",
MediaType.MULTIPART_FORM_DATA);
request.setChallengeResponse(challengeResponse);
Response response = client.handle(request);
//boolean valid = false;
System.out.println("request"+response.getStatus().getCode());
System.out.println("request test::"+response.getEntityAsText());
assertEquals(200, response.getStatus().getCode());
}
I'm getting the following 500 error:
The server encountered an unexpected condition which prevented it from fulfilling the request.
BASED ON THE BELOW POSTED ANSWER I MADE THE FOLLOWING WORKING METHOD:
#Test
public void testAssetsPost() throws Exception {
ClientResource cr = new ClientResource("http://localhost:14502/api/v1/ass");
FormDataSet fds = new FormDataSet();
fds.getEntries().add(new FormData("metaData", "metaDataTest123"));
fds.setMultipart(true);
FormData fileRep = new FormData("file",
new FileRepresentation(new File("/Users/og/Documents/gump.jpg"),
MediaType.IMAGE_JPEG));
fds.getEntries().add(fileRep);
FormData fileRep2 = new FormData("associatedDoc",
new FileRepresentation(new File("/Users/og/Documents/gump.jpg"),
MediaType.IMAGE_JPEG));
fds.getEntries().add(fileRep2);
Representation r = null;
try{
r = cr.post(fds);
} catch (ResourceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println( "Got Context: " + cr.getContext() );
System.out.println( "Got Response: " + cr.getResponse());
System.out.println( "Got Resonse Attribute : " + cr.getResponseAttributes() );
System.out.println( "Got Resonse Entity: " + cr.getResponseEntity() );
System.out.println("Got response !! , response : " + r.getText());
System.out.println(r.getText());
}
I don't know what is exactly the error you encountered within your server application. I would be interesting if we could have a stacktrace.
That said, you can build programmatically HTML forms using the org.restlet.ext.html extension. For more details, you could read this blog post: http://restlet.com/blog/2015/10/27/implementing-file-upload-with-restlet-framework/.
At a first sight, the media type isn't correct since you don't send a multipart form but a simple form. So you should use MediaType.APPLICATION_WWW_FORM instead of MediaType.MULTIPART_FORM_DATA.
A sample for a form containing a file:
Form fileForm = new Form();
fileForm.add(Disposition.NAME_FILENAME, "myimage.png");
Disposition disposition = new Disposition(Disposition.TYPE_INLINE, fileForm);
FileRepresentation entity = new FileRepresentation(f, MediaType.IMAGE_PNG);
entity.setDisposition(disposition);
And for a simple form:
FormDataSet fds = new FormDataSet();
fds.setMultipart(true);
FormData fdFile = new FormData("fileToUpload", entity);
fds.getEntries().add(fdFile);
FormData fdValue = new FormData("field", "value");
fds.getEntries().add(fdValue);
Hope it helps you,
Thierry

How to send JSON data in request to rest web service

I have created a rest webservice which has a below code in one method:
#POST
#Path("/validUser")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public JSONObject validUserLogin(#QueryParam(value="userDetails") String userDetails){
JSONObject json = null;
try{
System.out.println("Service running from validUserLogin :"+userDetails);
json = new JSONObject(userDetails);
System.err.println("UserName : "+json.getString("userName")+" password : "+json.getString("password"));
json.put("httpStatus","OK");
return json;
}
catch(JSONException jsonException) {
return json;
}
}
I am using Apache API in the client code.And below client code is calling this service, by posting some user related data to this service:
public static String getUserAvailability(String userName){
JSONObject json=new JSONObject();
try{
HttpContext context = new BasicHttpContext();
HttpClient client = new DefaultHttpClient();
client.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.RFC_2109);
URI uri=new URIBuilder(BASE_URI+PATH_VALID_USER).build();
HttpPost request = new HttpPost(uri);
request.setHeader("Content-Type", "application/json");
json.put("userName", userName);
StringEntity stringEntity = new StringEntity(json.toString());
request.setEntity(stringEntity);
HttpResponse response = client.execute(request,context);
System.err.println("content type : \n"+EntityUtils.toString(response.getEntity()));
}catch(Exception exception){
System.err.println("Client Exception: \n"+exception.getStackTrace());
}
return "OK";
}
The problem is, I am able to call the service, but the parameter I passed in the request to service results in null.
Am I posting the data in a wrong way in the request. Also I want to return some JSON data in the response, but I am not able to get this.
With the help of Zack , some how i was able to resolve the problem,
I used jackson-core jar and changed the service code as below.
#POST
#Path("/validUser")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public JSONObject validUserLogin(String userDetails){
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readValue(userDetails, JsonNode.class);
System.out.println("Service running from validUserLogin :"+userDetails);
System.out.println(node.get("userName").getTextValue());
//node.("httpStatus","OK");
return Response.ok(true).build();
}

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.