Java tutorial
/* * Copyright (c) 2015 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.uber.sdk.rides.client.internal; import com.google.api.client.auth.oauth2.BearerToken; import com.google.api.client.auth.oauth2.ClientParametersAuthentication; import com.google.api.client.auth.oauth2.Credential; import com.google.api.client.http.GenericUrl; import com.google.api.client.http.javanet.NetHttpTransport; import com.google.api.client.json.jackson2.JacksonFactory; import com.google.common.io.Files; import com.google.common.util.concurrent.SettableFuture; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.mockwebserver.MockResponse; import com.squareup.okhttp.mockwebserver.MockWebServer; import com.squareup.okhttp.mockwebserver.RecordedRequest; import com.squareup.okhttp.mockwebserver.SocketPolicy; import com.uber.sdk.rides.auth.OAuth2Helper; import com.uber.sdk.rides.client.Callback; import com.uber.sdk.rides.client.Response; import com.uber.sdk.rides.client.Session; import com.uber.sdk.rides.client.UberRidesAsyncService; import com.uber.sdk.rides.client.UberRidesServices; import com.uber.sdk.rides.client.UberRidesSyncService; import com.uber.sdk.rides.client.error.ApiException; import com.uber.sdk.rides.client.error.ClientError; import com.uber.sdk.rides.client.error.NetworkException; import com.uber.sdk.rides.client.error.UberError; import com.uber.sdk.rides.client.model.Product; import com.uber.sdk.rides.client.model.ProductsResponse; import com.uber.sdk.rides.client.model.Ride; import com.uber.sdk.rides.client.model.RideEstimate; import com.uber.sdk.rides.client.model.RideRequestParameters; import com.uber.sdk.rides.client.model.SandboxProductRequestParameters; import com.uber.sdk.rides.client.model.UserProfile; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import java.io.File; import java.io.IOException; import java.net.HttpURLConnection; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Locale; import java.util.concurrent.TimeUnit; import static com.uber.sdk.rides.client.Session.Environment.PRODUCTION; import static com.uber.sdk.rides.client.Session.Environment.SANDBOX; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.hasProperty; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; /** * Integration test for the Uber API client. */ public class RetrofitUberRidesClientIntegrationTest { private static final String ACCESS_TOKEN = "accessToken"; private static final String REFRESH_TOKEN = "refreshToken"; private static final float START_LAT = 37.613f; private static final float START_LONG = -122.477f; private static final float END_LAT = 37.808f; private static final float END_LONG = -122.416f; @Rule public ExpectedException exception = ExpectedException.none(); private Credential credential; private Session sandboxSession; private MockWebServer server; private OkHttpClient okHttpClient; private String endpointHost; private UberRidesAsyncService uberApiAsyncService; private UberRidesSyncService uberApiSyncService; @Before public void setUp() throws Exception { server = new MockWebServer(); server.start(); endpointHost = server.url("").toString(); credential = new Credential.Builder(BearerToken.authorizationHeaderAccessMethod()) .setTransport(new NetHttpTransport()).setJsonFactory(new JacksonFactory()) .setClientAuthentication(new ClientParametersAuthentication("CLIENT_ID", "CLIENT_SECRET")) .setTokenServerUrl(new GenericUrl(endpointHost)).build(); credential.setAccessToken(ACCESS_TOKEN); credential.setRefreshToken(REFRESH_TOKEN); credential.setExpiresInSeconds(3600L); sandboxSession = new Session.Builder().setCredential(credential).setEnvironment(SANDBOX).build(); okHttpClient = new OkHttpClient(); uberApiAsyncService = RetrofitUberRidesClient.getUberApiService(sandboxSession, new OAuth2Helper(), UberRidesServices.LogLevel.FULL, endpointHost, okHttpClient, RetrofitUberRidesService.class); uberApiSyncService = (UberRidesSyncService) uberApiAsyncService; } @After public void tearDown() throws IOException { server.shutdown(); } @Test public void onGet_whenAsyncHappyPath_shouldSucceed() throws Exception { String body = readFile("src/test/resources/mockresponses/get_products_response"); server.enqueue(new MockResponse().setBody(body)); SettableFuture<SettableResponse<ProductsResponse>> future = SettableFuture.create(); uberApiAsyncService.getProducts(37.613f, -122.477f, new SettableFutureCallback<>(future)); SettableResponse<ProductsResponse> response = future.get(1, TimeUnit.SECONDS); assertProductsWithCredential(server.takeRequest(), response.response, response.apiException, response.networkException); } @Test public void onGet_whenSyncHappyPath_shouldSucceed() throws Exception { String body = readFile("src/test/resources/mockresponses/get_products_response"); server.enqueue(new MockResponse().setBody(body)); Response<ProductsResponse> response = uberApiSyncService.getProducts(37.613f, -122.477f); assertProductsWithCredential(server.takeRequest(), response, null, null); } private static void assertProductsWithCredential(RecordedRequest request, Response<ProductsResponse> response, ApiException apiException, NetworkException networkException) { assertNotNull(response); assertNull(apiException); assertNull(networkException); ProductsResponse productsResponse = response.getBody(); assertNotNull(productsResponse); assertEquals("Request Path does not match", "/v1/products?latitude=37.613&longitude=-122.477", request.getPath()); assertEquals("Authorization Header not found", "Bearer accessToken", request.getHeader("Authorization")); assertEquals("Request method does not match", "GET", request.getMethod()); assertEquals("Response code does not match", HttpURLConnection.HTTP_OK, response.getStatus()); assertEquals("Response reason does not match", "OK", response.getReason()); List<Product> products = productsResponse.getProducts(); assertThat("Request body does not match", products, Matchers.<Product>hasItems( allOf(hasProperty("productId", is("04a497f5-380d-47f2-bf1b-ad4cfdcb51f2")), hasProperty("displayName", is("uberX")), hasProperty("description", is("uberX")), hasProperty("capacity", is(4))), allOf(hasProperty("productId", is("b5e6755e-05dd-44cc-903d-94bdaa7ffc78")), hasProperty("displayName", is("uberXL")), hasProperty("description", is("Low-cost rides for large groups")), hasProperty("capacity", is(6))), allOf(hasProperty("productId", is("d4abaae7-f4d6-4152-91cc-77523e8165a4")), hasProperty("displayName", is("UberBLACK")), hasProperty("description", is("The original Uber")), hasProperty("capacity", is(4))), allOf(hasProperty("productId", is("8920cb5e-51a4-4fa4-acdf-dd86c5e18ae0")), hasProperty("displayName", is("UberSUV")), hasProperty("description", is("Room for everyone")), hasProperty("capacity", is(6))), allOf(hasProperty("productId", is("4057d8cc-f0f5-43fa-b448-1cd891b0fc66")), hasProperty("displayName", is("ASSIST")), hasProperty("description", is("ASSIST")), hasProperty("capacity", is(4))), allOf(hasProperty("productId", is("2832a1f5-cfc0-48bb-ab76-7ea7a62060e7")), hasProperty("displayName", is("uberWAV")), hasProperty("description", is("Wheelchair Accessible Vehicles")), hasProperty("capacity", is(4))))); } @Test public void onGet_whenAsyncInvalidProductId_shouldFail() throws Exception { String body = readFile("src/test/resources/mockresponses/get_product_error"); server.enqueue(new MockResponse().setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_NOT_FOUND + " Not Found") .setBody(body)); final SettableFuture<SettableResponse<Product>> future = SettableFuture.create(); uberApiAsyncService.getProduct("thisIsNotAProductId", new SettableFutureCallback<>(future)); SettableResponse response = future.get(1, TimeUnit.SECONDS); assertProductError(server.takeRequest(), response.response, response.apiException, response.networkException); } @Test public void onGet_whenSyncInvalidProductId_shouldFail() throws Exception { String body = readFile("src/test/resources/mockresponses/get_product_error"); server.enqueue(new MockResponse().setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_NOT_FOUND + " Not Found") .setBody(body)); ApiException exception = null; Response<Product> response = null; try { response = uberApiSyncService.getProduct("thisIsNotAProductId"); } catch (ApiException e) { exception = e; } assertProductError(server.takeRequest(), response, exception, null); } private static void assertProductError(RecordedRequest request, Response<Product> response, ApiException apiException, NetworkException networkException) { assertNull(response); assertNull(networkException); assertEquals("Request path does not match", "/v1/products/thisIsNotAProductId", request.getPath()); assertEquals("Authorization Header not found", "Bearer accessToken", request.getHeader("Authorization")); assertEquals("Request method does not match", "GET", request.getMethod()); assertEquals("Response code does not match", HttpURLConnection.HTTP_NOT_FOUND, apiException.getResponse().getStatus()); assertEquals("Response reason does not match", "Not Found", apiException.getResponse().getReason()); List<UberError> errors = apiException.getErrors(); assertEquals("More than one error", 1, errors.size()); UberError uberError = errors.get(0); assertTrue("Error is not a ClientError", uberError instanceof ClientError); ClientError clientError = (ClientError) uberError; assertEquals("Error code did not match body", "not_found", clientError.getCode()); assertEquals("Error message did not match body", "Unable to find product thisIsNotAProductId", clientError.getMessage()); } @Test public void onGet_withLanguage() throws Exception { Session localizedSandboxSession = new Session.Builder().setAcceptLanguage(new Locale("sv", "SE")) .setCredential(credential).setEnvironment(Session.Environment.SANDBOX).build(); UberRidesSyncService localizedUberApiSyncService = RetrofitUberRidesClient.getUberApiService( localizedSandboxSession, new OAuth2Helper(), UberRidesServices.LogLevel.FULL, endpointHost, okHttpClient, RetrofitUberRidesService.class); String body = readFile("src/test/resources/mockresponses/get_localized_products_response"); server.enqueue(new MockResponse().setBody(body)); Response<ProductsResponse> response = localizedUberApiSyncService.getProducts(37.613f, -122.477f); assertLocalizedProducts(server.takeRequest(), response, null, null); } private static void assertLocalizedProducts(RecordedRequest request, Response<ProductsResponse> response, ApiException apiException, NetworkException networkException) { assertNotNull(response); assertNull(apiException); assertNull(networkException); ProductsResponse productsResponse = response.getBody(); assertNotNull(productsResponse); assertEquals("Accept-Language Header not found", "sv", request.getHeader("Accept-Language")); assertEquals("Response code does not match", HttpURLConnection.HTTP_OK, response.getStatus()); assertEquals("Response reason does not match", "OK", response.getReason()); List<Product> products = productsResponse.getProducts(); assertThat("Request body does not match", products, Matchers.<Product>hasItems(allOf( hasProperty("productId", is("a1111c8c-c720-46c3-8534-2fcdd730040d")), hasProperty("displayName", is("uberX")), hasProperty("description", is("Den billigare Ubern"))))); } @Test public void onPut_whenAsyncHappyPath_shouldSucceed() throws Exception { server.enqueue( new MockResponse().setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_NO_CONTENT + " NO CONTENT")); SandboxProductRequestParameters sandboxProductRequestParameters = new SandboxProductRequestParameters.Builder() .setDriversAvailable(true).setSurgeMultiplier(2.4f).build(); SettableFuture<SettableResponse<Void>> future = SettableFuture.create(); uberApiAsyncService.updateSandboxProduct("d4abaae7-f4d6-4152-91cc-77523e8165a4", sandboxProductRequestParameters, new SettableFutureCallback<>(future)); SettableResponse<Void> response = future.get(1, TimeUnit.SECONDS); assertSandboxProduct(server.takeRequest(), response.response, response.apiException, response.networkException); } @Test public void onPut_whenSyncHappyPath_shouldSucceed() throws Exception { server.enqueue( new MockResponse().setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_NO_CONTENT + " NO CONTENT")); SandboxProductRequestParameters sandboxProductRequestParameters = new SandboxProductRequestParameters.Builder() .setDriversAvailable(true).setSurgeMultiplier(2.4f).build(); Response<Void> response = uberApiSyncService.updateSandboxProduct("d4abaae7-f4d6-4152-91cc-77523e8165a4", sandboxProductRequestParameters); assertSandboxProduct(server.takeRequest(), response, null, null); } private static void assertSandboxProduct(RecordedRequest request, Response<Void> response, ApiException apiException, NetworkException networkException) { assertNotNull(response); assertNull(response.getBody()); assertNull(apiException); assertNull(networkException); assertEquals("Request Path does not match", "/v1/sandbox/products/d4abaae7-f4d6-4152-91cc-77523e8165a4", request.getPath()); assertEquals("Authorization Header not found", "Bearer accessToken", request.getHeader("Authorization")); assertEquals("Request method does not match", "PUT", request.getMethod()); assertEquals("Request body does not match", "{\"surge_multiplier\":2.4,\"drivers_available\":true}", request.getBody().readUtf8()); assertEquals("Response code does not match", HttpURLConnection.HTTP_NO_CONTENT, response.getStatus()); assertEquals("Response reason does not match", "NO CONTENT", response.getReason()); } @Test public void onPut_whenAsyncInvalidProductId_shouldFail() throws Exception { String body = readFile("src/test/resources/mockresponses/put_sandbox_params_no_product_id_response"); server.enqueue(new MockResponse().setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_NOT_FOUND + " Not Found") .setBody(body)); SandboxProductRequestParameters sandboxProductRequestParameters = new SandboxProductRequestParameters.Builder() .setDriversAvailable(true).setSurgeMultiplier(2.4f).build(); SettableFuture<SettableResponse<Void>> future = SettableFuture.create(); uberApiAsyncService.updateSandboxProduct("thisIsNotAProductId", sandboxProductRequestParameters, new SettableFutureCallback<>(future)); SettableResponse<Void> response = future.get(1, TimeUnit.SECONDS); assertSandboxProductError(server.takeRequest(), response.response, response.apiException, response.networkException); } @Test public void onPut_whenSyncInvalidProductId_shouldFail() throws Exception { String body = readFile("src/test/resources/mockresponses/put_sandbox_params_no_product_id_response"); server.enqueue(new MockResponse().setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_NOT_FOUND + " Not Found") .setBody(body)); SandboxProductRequestParameters sandboxProductRequestParameters = new SandboxProductRequestParameters.Builder() .setDriversAvailable(true).setSurgeMultiplier(2.4f).build(); ApiException exception = null; Response<Void> response = null; try { response = uberApiSyncService.updateSandboxProduct("thisIsNotAProductId", sandboxProductRequestParameters); } catch (ApiException e) { exception = e; } assertSandboxProductError(server.takeRequest(), response, exception, null); } private static void assertSandboxProductError(RecordedRequest request, Response<Void> response, ApiException apiException, NetworkException networkException) { assertNull(response); assertNull(networkException); assertEquals("Request path does not match", "/v1/sandbox/products/thisIsNotAProductId", request.getPath()); assertEquals("Authorization Header not found", "Bearer accessToken", request.getHeader("Authorization")); assertEquals("Request method does not match", "PUT", request.getMethod()); assertEquals("Response code does not match", HttpURLConnection.HTTP_NOT_FOUND, apiException.getResponse().getStatus()); assertEquals("Response reason does not match", "Not Found", apiException.getResponse().getReason()); } @Test public void onPost_whenAsyncHappyPath_shouldSucceed() throws Exception { String body = readFile("src/test/resources/mockresponses/post_ride_request"); server.enqueue(new MockResponse().setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_ACCEPTED + " Accepted") .setBody(body)); RideRequestParameters rideRequestParameters = new RideRequestParameters.Builder() .setPickupCoordinates(START_LAT, START_LONG).setDropoffCoordinates(END_LAT, END_LONG) .setProductId("d4abaae7-f4d6-4152-91cc-77523e8165a4").build(); SettableFuture<SettableResponse<Ride>> future = SettableFuture.create(); uberApiAsyncService.requestRide(rideRequestParameters, new SettableFutureCallback<>(future)); SettableResponse<Ride> response = future.get(1, TimeUnit.SECONDS); assertRideRequest(server.takeRequest(), response.response, null, null); } @Test public void onPost_whenSyncHappyPath_shouldSucceed() throws Exception { String body = readFile("src/test/resources/mockresponses/post_ride_request"); server.enqueue(new MockResponse().setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_ACCEPTED + " Accepted") .setBody(body)); RideRequestParameters rideRequestParameters = new RideRequestParameters.Builder() .setPickupCoordinates(START_LAT, START_LONG).setDropoffCoordinates(END_LAT, END_LONG) .setProductId("d4abaae7-f4d6-4152-91cc-77523e8165a4").build(); Response<Ride> response = uberApiSyncService.requestRide(rideRequestParameters); assertRideRequest(server.takeRequest(), response, null, null); } private static void assertRideRequest(RecordedRequest request, Response<Ride> response, ApiException apiException, NetworkException networkException) { assertNotNull(response); assertNotNull(response.getBody()); assertNull(apiException); assertNull(networkException); assertEquals("Request Path does not match", "/v1/requests", request.getPath()); assertEquals("Authorization Header not found", "Bearer accessToken", request.getHeader("Authorization")); assertEquals("Request method does not match", "POST", request.getMethod()); assertEquals("Request body does not match", "{\"product_id\":\"d4abaae7-f4d6-4152-91cc-77523e8165a4\",\"start_latitude\":37.613,\"start_longitude\":-122.477,\"end_latitude\":37.808,\"end_longitude\":-122.416}", request.getBody().readUtf8()); assertNotNull(response); assertEquals("Response code does not match", HttpURLConnection.HTTP_ACCEPTED, response.getStatus()); assertEquals("Response reason does not match", "Accepted", response.getReason()); assertThat("Request body does not match", response.getBody(), allOf(hasProperty("rideId", is("1033c525-746e-48ab-8eee-ab983e039e78")), hasProperty("status", is("processing")), hasProperty("driver", nullValue()), hasProperty("eta", is(13)), hasProperty("surgeMultiplier", is(1.0f)), hasProperty("location", nullValue()), hasProperty("vehicle", nullValue()))); } @Test public void onPost_whenAysncInvalidProductId_shouldFail() throws Exception { String body = readFile("src/test/resources/mockresponses/post_ride_error"); server.enqueue(new MockResponse().setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_NOT_FOUND + " Not Found") .setBody(body)); RideRequestParameters rideRequestParameters = new RideRequestParameters.Builder() .setPickupCoordinates(START_LAT, START_LONG).setDropoffCoordinates(END_LAT, END_LONG) .setProductId("thisIsNotAProductId").build(); SettableFuture<SettableResponse<Ride>> future = SettableFuture.create(); uberApiAsyncService.requestRide(rideRequestParameters, new SettableFutureCallback<>(future)); SettableResponse response = future.get(1, TimeUnit.SECONDS); assertRideRequestError(server.takeRequest(), response.response, response.apiException, response.networkException); } @Test public void onPost_whenSyncInvalidProductId_shouldFail() throws Exception { String body = readFile("src/test/resources/mockresponses/post_ride_error"); server.enqueue(new MockResponse().setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_NOT_FOUND + " Not Found") .setBody(body)); RideRequestParameters rideRequestParameters = new RideRequestParameters.Builder() .setPickupCoordinates(START_LAT, START_LONG).setDropoffCoordinates(END_LAT, END_LONG) .setProductId("thisIsNotAProductId").build(); ApiException exception = null; Response<Ride> response = null; try { response = uberApiSyncService.requestRide(rideRequestParameters); } catch (ApiException e) { exception = e; } assertRideRequestError(server.takeRequest(), response, exception, null); } private static void assertRideRequestError(RecordedRequest request, Response<Ride> response, ApiException apiException, NetworkException networkException) { assertNull(response); assertNull(networkException); assertEquals("Request path does not match", "/v1/requests", request.getPath()); assertEquals("Authorization Header not found", "Bearer accessToken", request.getHeader("Authorization")); assertEquals("Request method does not match", "POST", request.getMethod()); assertEquals("Response code does not match", HttpURLConnection.HTTP_NOT_FOUND, apiException.getResponse().getStatus()); assertEquals("Response reason does not match", "Not Found", apiException.getResponse().getReason()); List<UberError> errors = apiException.getErrors(); assertEquals("More than one error", 1, errors.size()); UberError uberError = errors.get(0); assertTrue("Error is not a ClientError", uberError instanceof ClientError); ClientError clientError = (ClientError) uberError; assertEquals("Error code did not match body", "not_found", clientError.getCode()); assertEquals("Error message did not match body", "Invalid product \"thisIsNotAProductId\". " + "Available: d4abaae7-f4d6-4152-91cc-77523e8165a4, 8920cb5e-51a4-4fa4-acdf-dd86c5e18ae0, " + "04a497f5-380d-47f2-bf1b-ad4cfdcb51f2, 2832a1f5-cfc0-48bb-ab76-7ea7a62060e7, " + "4057d8cc-f0f5-43fa-b448-1cd891b0fc66, b5e6755e-05dd-44cc-903d-94bdaa7ffc78", clientError.getMessage()); } @Test public void onDelete_whenAsyncHappyPath_shouldSucceed() throws Exception { server.enqueue( new MockResponse().setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_NO_CONTENT + " NO CONTENT")); String rideId = "542498f1-5096-418e-96c0-0cba096cb70c"; SettableFuture<SettableResponse<Void>> future = SettableFuture.create(); uberApiAsyncService.cancelRide(rideId, new SettableFutureCallback<>(future)); SettableResponse<Void> response = future.get(1, TimeUnit.SECONDS); assertDeleteRide(server.takeRequest(), response.response); } private static void assertDeleteRide(RecordedRequest request, Response<Void> response) { assertNotNull(request); assertNotNull(response); assertEquals("Request Path does not match", "/v1/requests/542498f1-5096-418e-96c0-0cba096cb70c", request.getPath()); assertEquals("Authorization Header not found", "Bearer accessToken", request.getHeader("Authorization")); assertEquals("Request method does not match", "DELETE", request.getMethod()); assertEquals("Response code does not match", HttpURLConnection.HTTP_NO_CONTENT, response.getStatus()); assertEquals("Response reason does not match", "NO CONTENT", response.getReason()); } @Test public void onCall_whenAsyncCredentialNeedsRefresh_shouldRefreshCredential() throws Exception { String refreshResponseBody = readFile("src/test/resources/mockresponses/post_refresh_token_response"); server.enqueue(new MockResponse().setBody(refreshResponseBody)); String getProfileResponseBody = readFile("src/test/resources/mockresponses/get_user_profile_response"); server.enqueue(new MockResponse().setBody(getProfileResponseBody)); credential.setExpiresInSeconds(OAuth2Helper.DEFAULT_REFRESH_WINDOW - 60L); SettableFuture<SettableResponse<UserProfile>> future = SettableFuture.create(); uberApiAsyncService.getUserProfile(new SettableFutureCallback<>(future)); SettableResponse<UserProfile> response = future.get(1, TimeUnit.SECONDS); assertCredentialRefresh(response.response, response.responseObject, response.apiException, response.networkException); } @Test public void onCall_whenSyncCredentialNeedsRefresh_shouldRefreshCredential() throws Exception { String refreshResponseBody = readFile("src/test/resources/mockresponses/post_refresh_token_response"); server.enqueue(new MockResponse().setBody(refreshResponseBody)); String getProfileResponseBody = readFile("src/test/resources/mockresponses/get_user_profile_response"); server.enqueue(new MockResponse().setBody(getProfileResponseBody)); credential.setExpiresInSeconds(OAuth2Helper.DEFAULT_REFRESH_WINDOW - 60L); Response<UserProfile> response = uberApiSyncService.getUserProfile(); assertCredentialRefresh(response, response.getBody(), null, null); } private void assertCredentialRefresh(Response response, UserProfile userProfile, ApiException apiException, NetworkException networkException) throws InterruptedException { assertNotNull(response); assertNotNull(userProfile); assertNull(apiException); assertNull(networkException); RecordedRequest refreshRequest = server.takeRequest(); assertEquals("Refresh request body does not match", "grant_type=refresh_token&refresh_token=refreshToken&client_id=CLIENT_ID&client_secret=CLIENT_SECRET", refreshRequest.getBody().readUtf8()); assertEquals("Refresh request method does not match", "POST", refreshRequest.getMethod()); RecordedRequest getProfileRequest = server.takeRequest(); assertEquals("Get Profile Request path does not match", "/v1/me", getProfileRequest.getPath()); assertEquals("Authorization Header does not match", "Bearer accessToken2", getProfileRequest.getHeader("Authorization")); assertEquals("Get Profile Request method does not match", "GET", getProfileRequest.getMethod()); assertEquals("accessToken2", credential.getAccessToken()); assertEquals("refreshToken2", credential.getRefreshToken()); } @Test public void onCall_whenAsyncServerToken_shouldSendServerToken() throws Exception { Session session = new Session.Builder().setEnvironment(PRODUCTION).setServerToken("serverToken").build(); uberApiAsyncService = RetrofitUberRidesClient.getUberApiService(session, new OAuth2Helper(), UberRidesServices.LogLevel.FULL, endpointHost, okHttpClient, RetrofitUberRidesService.class); String body = readFile("src/test/resources/mockresponses/get_products_response"); server.enqueue(new MockResponse().setBody(body)); SettableFuture<SettableResponse<ProductsResponse>> future = SettableFuture.create(); uberApiAsyncService.getProducts(37.613f, -122.477f, new SettableFutureCallback<>(future)); SettableResponse<ProductsResponse> response = future.get(1, TimeUnit.SECONDS); assertProductsWithServerToken(server.takeRequest(), response.response, response.responseObject, response.apiException, response.networkException); } @Test public void onCall_whenSyncServerToken_shouldSendServerToken() throws Exception { Session session = new Session.Builder().setEnvironment(PRODUCTION).setServerToken("serverToken").build(); uberApiSyncService = RetrofitUberRidesClient.getUberApiService(session, new OAuth2Helper(), UberRidesServices.LogLevel.FULL, endpointHost, okHttpClient, RetrofitUberRidesService.class); String body = readFile("src/test/resources/mockresponses/get_products_response"); server.enqueue(new MockResponse().setBody(body)); Response<ProductsResponse> response = uberApiSyncService.getProducts(37.613f, -122.477f); assertProductsWithServerToken(server.takeRequest(), response, response.getBody(), null, null); } private void assertProductsWithServerToken(RecordedRequest request, Response response, ProductsResponse productsResponse, ApiException apiException, NetworkException networkException) { assertNotNull(productsResponse); assertNotNull(response); assertNull(apiException); assertNull(networkException); assertEquals("Request Path does not match", "/v1/products?latitude=37.613&longitude=-122.477", request.getPath()); assertEquals("Authorization Header not found", "Token serverToken", request.getHeader("Authorization")); assertEquals("Request method does not match", "GET", request.getMethod()); assertEquals("Response code does not match", HttpURLConnection.HTTP_OK, response.getStatus()); assertEquals("Response reason does not match", "OK", response.getReason()); List<Product> products = productsResponse.getProducts(); assertThat("Request body does not match", products, Matchers.<Product>hasItems( allOf(hasProperty("productId", is("04a497f5-380d-47f2-bf1b-ad4cfdcb51f2")), hasProperty("displayName", is("uberX")), hasProperty("description", is("uberX")), hasProperty("capacity", is(4))), allOf(hasProperty("productId", is("b5e6755e-05dd-44cc-903d-94bdaa7ffc78")), hasProperty("displayName", is("uberXL")), hasProperty("description", is("Low-cost rides for large groups")), hasProperty("capacity", is(6))), allOf(hasProperty("productId", is("d4abaae7-f4d6-4152-91cc-77523e8165a4")), hasProperty("displayName", is("UberBLACK")), hasProperty("description", is("The original Uber")), hasProperty("capacity", is(4))), allOf(hasProperty("productId", is("8920cb5e-51a4-4fa4-acdf-dd86c5e18ae0")), hasProperty("displayName", is("UberSUV")), hasProperty("description", is("Room for everyone")), hasProperty("capacity", is(6))), allOf(hasProperty("productId", is("4057d8cc-f0f5-43fa-b448-1cd891b0fc66")), hasProperty("displayName", is("ASSIST")), hasProperty("description", is("ASSIST")), hasProperty("capacity", is(4))), allOf(hasProperty("productId", is("2832a1f5-cfc0-48bb-ab76-7ea7a62060e7")), hasProperty("displayName", is("uberWAV")), hasProperty("description", is("Wheelchair Accessible Vehicles")), hasProperty("capacity", is(4))))); } @Test public void onCall_whenSyncTimeout_shouldThrowException() throws Exception { okHttpClient.setConnectTimeout(1, TimeUnit.MILLISECONDS); okHttpClient.setReadTimeout(1, TimeUnit.MILLISECONDS); exception.expect(NetworkException.class); server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.NO_RESPONSE)); uberApiSyncService.getUserProfile(); } @Test public void onCall_whenAsyncTimeout_shouldThrowException() throws Exception { okHttpClient.setConnectTimeout(1, TimeUnit.MILLISECONDS); okHttpClient.setReadTimeout(1, TimeUnit.MILLISECONDS); server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.NO_RESPONSE)); SettableFuture<SettableResponse<UserProfile>> future = SettableFuture.create(); uberApiAsyncService.getUserProfile(new SettableFutureCallback<>(future)); SettableResponse<UserProfile> response = future.get(); assertNotNull(response.networkException); } @Test public void onCall_whenSyncUnexpectedException_shouldThrowException() throws Exception { exception.expect(RuntimeException.class); server.enqueue(new MockResponse().setBody("Not JSON")); uberApiSyncService.getUserProfile(); } @Test public void onCall_whenAsyncUnexpectedException_shouldThrowException() throws Exception { server.enqueue(new MockResponse().setBody("Not JSON")); SettableFuture<SettableResponse<UserProfile>> future = SettableFuture.create(); uberApiAsyncService.getUserProfile(new SettableFutureCallback<>(future)); SettableResponse<UserProfile> response = future.get(); assertNotNull(response.unknownException); } @Test public void onCall_whenAsyncHappyPath_shouldHaveHeaders() throws Exception { String refreshResponseBody = readFile("src/test/resources/mockresponses/post_refresh_token_response"); server.enqueue(new MockResponse().setBody(refreshResponseBody)); uberApiAsyncService.getUserProfile( new SettableFutureCallback<>(SettableFuture.<SettableResponse<UserProfile>>create())); assertHeaders(server.takeRequest(1, TimeUnit.SECONDS)); } @Test public void onCall_whenSyncHappyPath_shouldHaveHeaders() throws Exception { String refreshResponseBody = readFile("src/test/resources/mockresponses/post_refresh_token_response"); server.enqueue(new MockResponse().setBody(refreshResponseBody)); uberApiSyncService.getUserProfile(); assertHeaders(server.takeRequest()); } @Test public void onCall_whenAsyncRedirect_shouldAutomaticallyRedirectAndPreserveHeaders() throws Exception { String redirectedResponseBody = readFile("src/test/resources/mockresponses/estimate_ride_redirected"); MockWebServer redirectServer = new MockWebServer(); redirectServer.enqueue(new MockResponse().setBody(redirectedResponseBody)); String redirectResponseBody = readFile("src/test/resources/mockresponses/estimate_ride_redirect"); server.enqueue(new MockResponse().setBody(redirectResponseBody) .setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_MOVED_TEMP + " Found") .setHeader("Location", redirectServer.getUrl("/v1/requests/estimate"))); RideRequestParameters rideRequestParameters = new RideRequestParameters.Builder() .setPickupCoordinates(START_LAT, START_LONG).setProductId("2832a1f5-cfc0-48bb-ab76-7ea7a62060e7") .setDropoffCoordinates(END_LAT, END_LONG).build(); uberApiAsyncService = RetrofitUberRidesClient.getUberApiService(sandboxSession, new OAuth2Helper(), UberRidesServices.LogLevel.FULL, endpointHost, null, RetrofitUberRidesService.class); uberApiAsyncService.estimateRide(rideRequestParameters, new SettableFutureCallback<>(SettableFuture.<SettableResponse<RideEstimate>>create())); RecordedRequest firstRequest = server.takeRequest(1, TimeUnit.SECONDS); assertHeaders(firstRequest); RecordedRequest redirectedRequest = redirectServer.takeRequest(1, TimeUnit.SECONDS); assertHeaders(redirectedRequest); assertEquals("Redirected Request Line does not match", "POST /v1/requests/estimate HTTP/1.1", redirectedRequest.getRequestLine()); } @Test public void onCall_whenSyncRedirect_shouldAutomaticallyRedirectAndPreserveHeaders() throws Exception { String redirectedResponseBody = readFile("src/test/resources/mockresponses/estimate_ride_redirected"); MockWebServer redirectServer = new MockWebServer(); redirectServer.enqueue(new MockResponse().setBody(redirectedResponseBody)); String redirectResponseBody = readFile("src/test/resources/mockresponses/estimate_ride_redirect"); server.enqueue(new MockResponse().setBody(redirectResponseBody) .setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_MOVED_TEMP + " Found") .setHeader("Location", redirectServer.getUrl("/v1/requests/estimate"))); RideRequestParameters rideRequestParameters = new RideRequestParameters.Builder() .setPickupCoordinates(START_LAT, START_LONG).setProductId("2832a1f5-cfc0-48bb-ab76-7ea7a62060e7") .setDropoffCoordinates(END_LAT, END_LONG).build(); uberApiSyncService = RetrofitUberRidesClient.getUberApiService(sandboxSession, new OAuth2Helper(), UberRidesServices.LogLevel.FULL, endpointHost, null, RetrofitUberRidesService.class); uberApiSyncService.estimateRide(rideRequestParameters); RecordedRequest firstRequest = server.takeRequest(); assertHeaders(firstRequest); RecordedRequest redirectedRequest = redirectServer.takeRequest(); assertHeaders(redirectedRequest); assertEquals("Redirected Request Line does not match", "POST /v1/requests/estimate HTTP/1.1", redirectedRequest.getRequestLine()); } private static void assertHeaders(RecordedRequest request) { assertEquals("Authorization Header not found", "Bearer accessToken", request.getHeader("Authorization")); assertEquals("User Agent Header not found", "Java Rides SDK v" + RetrofitUberRidesClient.LIB_VERSION, request.getHeader("X-Uber-User-Agent")); } private String readFile(String path) throws IOException { File file = new File(path); if (!file.exists()) { file = new File("sdk/" + path); } return Files.toString(file, StandardCharsets.UTF_8); } private static class SettableFutureCallback<T> implements Callback<T> { private SettableFuture<SettableResponse<T>> settableFuture; public SettableFutureCallback(SettableFuture<SettableResponse<T>> settableFuture) { this.settableFuture = settableFuture; } @Override public void success(T obj, Response<T> response) { settableFuture.set(new SettableResponse<>(obj, response, null, null, null)); } @Override public void failure(NetworkException exception) { settableFuture.set(new SettableResponse<T>(null, null, exception, null, null)); } @Override public void failure(ApiException exception) { settableFuture.set(new SettableResponse<T>(null, null, null, exception, null)); } @Override public void failure(Throwable exception) { settableFuture.set(new SettableResponse<T>(null, null, null, null, exception)); } } private static class SettableResponse<T> { T responseObject; Response response; NetworkException networkException; ApiException apiException; Throwable unknownException; public SettableResponse(T responseObject, Response response, NetworkException networkException, ApiException apiException, Throwable unknownException) { this.responseObject = responseObject; this.response = response; this.networkException = networkException; this.apiException = apiException; this.unknownException = unknownException; } } }