package com.auth0.net;
import com.auth0.client.MockServer;
import com.auth0.exception.Auth0Exception;
import com.auth0.exception.APIException;
import com.auth0.json.auth.TokenHolder;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.mockwebserver.RecordedRequest;
import org.hamcrest.Matchers;
import org.junit.*;
import org.junit.rules.ExpectedException;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import static com.auth0.client.MockServer.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class CustomRequestTest {
private MockServer server;
private OkHttpClient client;
@Rule
public ExpectedException exception = ExpectedException.none();
private TypeReference<TokenHolder> tokenHolderType;
private TypeReference<List> listType;
private TypeReference<Void> voidType;
@Before
public void setUp() throws Exception {
server = new MockServer();
client = new OkHttpClient();
tokenHolderType = new TypeReference<TokenHolder>() {
};
listType = new TypeReference<List>() {
};
voidType = new TypeReference<Void>() {
};
}
@After
public void tearDown() throws Exception {
server.stop();
}
@Test
public void shouldCreateGETRequest() throws Exception {
CustomRequest<TokenHolder> request = new CustomRequest<>(client, server.getBaseUrl(), "GET", tokenHolderType);
assertThat(request, is(notNullValue()));
server.jsonResponse(AUTH_TOKENS, 200);
TokenHolder execute = request.execute();
RecordedRequest recordedRequest = server.takeRequest();
Assert.assertThat(recordedRequest.getMethod(), is("GET"));
Assert.assertThat(execute, is(notNullValue()));
}
@Test
public void shouldCreatePOSTRequest() throws Exception {
CustomRequest<TokenHolder> request = new CustomRequest<>(client, server.getBaseUrl(), "POST", tokenHolderType);
assertThat(request, is(notNullValue()));
request.addParameter("non_empty", "body");
server.jsonResponse(AUTH_TOKENS, 200);
TokenHolder execute = request.execute();
RecordedRequest recordedRequest = server.takeRequest();
Assert.assertThat(recordedRequest.getMethod(), is("POST"));
Assert.assertThat(execute, is(notNullValue()));
}
@Test
public void shouldAddParameters() throws Exception {
CustomRequest<TokenHolder> request = new CustomRequest<>(client, server.getBaseUrl(), "POST", tokenHolderType);
Map mapValue = mock(Map.class);
request.addParameter("key", "value");
request.addParameter("map", mapValue);
server.jsonResponse(AUTH_TOKENS, 200);
request.execute();
RecordedRequest recordedRequest = server.takeRequest();
Map<String, Object> values = bodyFromRequest(recordedRequest);
assertThat(values, hasEntry("key", (Object) "value"));
assertThat(values, hasEntry("map", (Object) mapValue));
}
@Test
public void shouldAddHeaders() throws Exception {
CustomRequest<TokenHolder> request = new CustomRequest<>(client, server.getBaseUrl(), "POST", tokenHolderType);
request.addParameter("non_empty", "body");
request.addHeader("Content-Type", "application/json");
request.addHeader("Authorization", "Bearer my_access_token");
server.jsonResponse(AUTH_TOKENS, 200);
request.execute();
RecordedRequest recordedRequest = server.takeRequest();
assertThat(recordedRequest.getHeader("Content-Type"), is("application/json"));
assertThat(recordedRequest.getHeader("Authorization"), is("Bearer my_access_token"));
}
@Test
public void shouldThrowOnExecuteFailure() throws Exception {
exception.expect(Auth0Exception.class);
exception.expectCause(Matchers.<Throwable>instanceOf(IOException.class));
exception.expectMessage("Failed to execute request");
OkHttpClient client = mock(OkHttpClient.class);
Call call = mock(Call.class);
when(client.newCall(any(okhttp3.Request.class))).thenReturn(call);
when(call.execute()).thenThrow(IOException.class);
CustomRequest<Void> request = new CustomRequest<>(client, server.getBaseUrl(), "GET", voidType);
request.execute();
}
@Test
public void shouldThrowOnBodyCreationFailure() throws Exception {
ObjectMapper mapper = mock(ObjectMapper.class);
when(mapper.writeValueAsBytes(any(Object.class))).thenThrow(JsonProcessingException.class);
CustomRequest request = new CustomRequest<>(client, server.getBaseUrl(), "POST", mapper, voidType);
request.addParameter("name", "value");
exception.expect(Auth0Exception.class);
exception.expectCause(Matchers.<Throwable>instanceOf(JsonProcessingException.class));
exception.expectMessage("Couldn't create the request body.");
request.execute();
}
@Test
public void shouldParseSuccessfulResponse() throws Exception {
CustomRequest<TokenHolder> request = new CustomRequest<>(client, server.getBaseUrl(), "GET", tokenHolderType);
server.jsonResponse(AUTH_TOKENS, 200);
TokenHolder response = request.execute();
server.takeRequest();
assertThat(response, is(notNullValue()));
assertThat(response.getAccessToken(), not(isEmptyOrNullString()));
assertThat(response.getIdToken(), not(isEmptyOrNullString()));
assertThat(response.getRefreshToken(), not(isEmptyOrNullString()));
assertThat(response.getTokenType(), not(isEmptyOrNullString()));
assertThat(response.getExpiresIn(), is(notNullValue()));
}
@Test
public void shouldThrowOnParseInvalidSuccessfulResponse() throws Exception {
CustomRequest<List> request = new CustomRequest<>(client, server.getBaseUrl(), "GET", listType);
server.jsonResponse(AUTH_TOKENS, 200);
Exception exception = null;
try {
request.execute();
server.takeRequest();
} catch (Exception e) {
exception = e;
}
assertThat(exception, is(notNullValue()));
assertThat(exception, is(instanceOf(APIException.class)));
assertThat(exception.getCause(), is(instanceOf(JsonMappingException.class)));
assertThat(exception.getMessage(), is("Request failed with status code 200: Failed to parse json body"));
APIException authException = (APIException) exception;
assertThat(authException.getDescription(), is("Failed to parse json body"));
assertThat(authException.getError(), is(nullValue()));
assertThat(authException.getStatusCode(), is(200));
}
@Test
public void shouldParseJSONErrorResponseWithErrorDescription() throws Exception {
CustomRequest<List> request = new CustomRequest<>(client, server.getBaseUrl(), "GET", listType);
server.jsonResponse(AUTH_ERROR_WITH_ERROR_DESCRIPTION, 400);
Exception exception = null;
try {
request.execute();
server.takeRequest();
} catch (Exception e) {
exception = e;
}
assertThat(exception, is(notNullValue()));
assertThat(exception, is(instanceOf(APIException.class)));
assertThat(exception.getCause(), is(nullValue()));
assertThat(exception.getMessage(), is("Request failed with status code 400: the connection was not found"));
APIException authException = (APIException) exception;
assertThat(authException.getDescription(), is("the connection was not found"));
assertThat(authException.getError(), is("invalid_request"));
assertThat(authException.getStatusCode(), is(400));
}
@Test
public void shouldParseJSONErrorResponseWithError() throws Exception {
CustomRequest<List> request = new CustomRequest<>(client, server.getBaseUrl(), "GET", listType);
server.jsonResponse(AUTH_ERROR_WITH_ERROR, 400);
Exception exception = null;
try {
request.execute();
server.takeRequest();
} catch (Exception e) {
exception = e;
}
assertThat(exception, is(notNullValue()));
assertThat(exception, is(instanceOf(APIException.class)));
assertThat(exception.getCause(), is(nullValue()));
assertThat(exception.getMessage(), is("Request failed with status code 400: missing username for Username-Password-Authentication connection with requires_username enabled"));
APIException authException = (APIException) exception;
assertThat(authException.getDescription(), is("missing username for Username-Password-Authentication connection with requires_username enabled"));
assertThat(authException.getError(), is("missing username for Username-Password-Authentication connection with requires_username enabled"));
assertThat(authException.getStatusCode(), is(400));
}
@Test
public void shouldParseJSONErrorResponseWithDescription() throws Exception {
CustomRequest<List> request = new CustomRequest<>(client, server.getBaseUrl(), "GET", listType);
server.jsonResponse(AUTH_ERROR_WITH_DESCRIPTION, 400);
Exception exception = null;
try {
request.execute();
server.takeRequest();
} catch (Exception e) {
exception = e;
}
assertThat(exception, is(notNullValue()));
assertThat(exception, is(instanceOf(APIException.class)));
assertThat(exception.getCause(), is(nullValue()));
assertThat(exception.getMessage(), is("Request failed with status code 400: The user already exists."));
APIException authException = (APIException) exception;
assertThat(authException.getDescription(), is("The user already exists."));
assertThat(authException.getError(), is("user_exists"));
assertThat(authException.getStatusCode(), is(400));
}
@Test
public void shouldParseJSONErrorResponseWithMessage() throws Exception {
CustomRequest<List> request = new CustomRequest<>(client, server.getBaseUrl(), "GET", listType);
server.jsonResponse(MGMT_ERROR_WITH_MESSAGE, 400);
Exception exception = null;
try {
request.execute();
server.takeRequest();
} catch (Exception e) {
exception = e;
}
assertThat(exception, is(notNullValue()));
assertThat(exception, is(instanceOf(APIException.class)));
assertThat(exception.getCause(), is(nullValue()));
assertThat(exception.getMessage(), is("Request failed with status code 400: Query validation error: 'String 'invalid_field' does not match pattern. Must be a comma separated list of the following values: allowed_logout_urls,change_password."));
APIException authException = (APIException) exception;
assertThat(authException.getDescription(), is("Query validation error: 'String 'invalid_field' does not match pattern. Must be a comma separated list of the following values: allowed_logout_urls,change_password."));
assertThat(authException.getError(), is("invalid_query_string"));
assertThat(authException.getStatusCode(), is(400));
}
@Test
public void shouldParsePlainTextErrorResponse() throws Exception {
CustomRequest<List> request = new CustomRequest<>(client, server.getBaseUrl(), "GET", listType);
server.textResponse(AUTH_ERROR_PLAINTEXT, 400);
Exception exception = null;
try {
request.execute();
server.takeRequest();
} catch (Exception e) {
exception = e;
}
assertThat(exception, is(notNullValue()));
assertThat(exception, is(instanceOf(APIException.class)));
assertThat(exception.getCause(), is(instanceOf(JsonParseException.class)));
assertThat(exception.getMessage(), is("Request failed with status code 400: A plain-text error response"));
APIException authException = (APIException) exception;
assertThat(authException.getDescription(), is("A plain-text error response"));
assertThat(authException.getError(), is(nullValue()));
assertThat(authException.getStatusCode(), is(400));
}
}