/* * Copyright (C) 2014 SCVNGR, Inc. d/b/a LevelUp * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.scvngr.levelup.core.net.request.factory; import android.content.Context; import android.location.Location; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.test.suitebuilder.annotation.SmallTest; import com.scvngr.levelup.core.model.AccessToken; import com.scvngr.levelup.core.model.User; import com.scvngr.levelup.core.model.UserFixture; import com.scvngr.levelup.core.net.AbstractRequest; import com.scvngr.levelup.core.net.AbstractRequest.BadRequestException; import com.scvngr.levelup.core.net.HttpMethod; import com.scvngr.levelup.core.net.LevelUpRequest; import com.scvngr.levelup.core.net.MockAccessTokenRetriever; import com.scvngr.levelup.core.net.RequestUtils; import com.scvngr.levelup.core.net.request.factory.UserRequestFactory.UserInfoRequestBuilder; import com.scvngr.levelup.core.test.SupportAndroidTestCase; import com.scvngr.levelup.core.util.LogManager; import com.scvngr.levelup.core.util.NullUtils; import com.google.gson.JsonObject; import org.apache.http.protocol.HTTP; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.UnsupportedEncodingException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Tests {@link com.scvngr.levelup.core.net.request.factory.UserRequestFactory}. */ public final class UserRequestFactoryTest extends SupportAndroidTestCase { @NonNull private static final String EMAIL_EXAMPLE_COM = "email@example.com"; /** * Tests the constructor to make sure the object performs parameter checking. */ @SmallTest public void testConstructor() { new UserRequestFactory(getContext(), new MockAccessTokenRetriever()); try { new UserRequestFactory(null, new MockAccessTokenRetriever()); fail("null context should throw exception"); } catch (final AssertionError e) { // Expected exception } } /** * Tests the {@link com.scvngr.levelup.core.net.AbstractRequest} return from * {@link com.scvngr.levelup.core.net.request.factory.UserRequestFactory#buildForgotPasswordRequest}. * * @throws com.scvngr.levelup.core.net.AbstractRequest.BadRequestException from {@link com.scvngr.levelup.core.net.AbstractRequest#getUrl}. * @throws java.io.UnsupportedEncodingException from {@link java.net.URLEncoder#encode(String, String)}. */ @SmallTest public void testBuildForgotPasswordRequest_withValidArgument() throws BadRequestException, UnsupportedEncodingException { final LevelUpRequest request = (LevelUpRequest) new UserRequestFactory(getContext(), new MockAccessTokenRetriever()) .buildForgotPasswordRequest(EMAIL_EXAMPLE_COM); assertEquals(HttpMethod.POST, request.getMethod()); final String path = request.getUrl(getContext()).getPath(); assertTrue(path.endsWith("passwords")); assertTrue(path.startsWith("/v14")); final JsonObject expectedRequest = new JsonObject(); expectedRequest.addProperty("email", EMAIL_EXAMPLE_COM); assertEquals(expectedRequest.toString(), request.getBody(getContext())); assertEquals(RequestUtils.HEADER_CONTENT_TYPE_JSON, request.getRequestHeaders(getContext()) .get(HTTP.CONTENT_TYPE)); } @SmallTest public void testBuildFacebookConnectRequest() throws Exception { final AbstractRequest request = new UserRequestFactory(getContext(), new MockAccessTokenRetriever()) .buildFacebookConnectRequest("facebook_access_token"); assertEquals(HttpMethod.POST, request.getMethod()); assertTrue(request.getUrl(getContext()).getPath().endsWith("/facebook_connection")); final LevelUpRequest apiRequest = (LevelUpRequest) request; final JSONObject userObject = new JSONObject(apiRequest.getBody(getContext())) .getJSONObject(UserRequestFactory.OUTER_PARAM_USER); assertTrue(userObject.has(UserRequestFactory.PARAM_FACEBOOK_ACCESS_TOKEN)); assertEquals("facebook_access_token", userObject .getString(UserRequestFactory.PARAM_FACEBOOK_ACCESS_TOKEN)); // Make sure we can get the access token. assertNotNull(apiRequest.getAccessToken(getContext())); } @SmallTest public void testBuildFacebookDisconnectRequest() throws Exception { final AbstractRequest request = new UserRequestFactory(getContext(), new MockAccessTokenRetriever()) .buildFacebookDisconnectRequest(); final LevelUpRequest apiRequest = (LevelUpRequest) request; assertEquals(HttpMethod.DELETE, request.getMethod()); assertTrue(request.getUrl(getContext()).getPath().endsWith("/facebook_connection")); // Make sure we can get the access token. assertNotNull(apiRequest.getAccessToken(getContext())); } @SmallTest public void testBuildRegisterWithFacebookRequest() throws BadRequestException, JSONException { final LevelUpRequest request = (LevelUpRequest) new UserRequestFactory(getContext(), null) .buildFacebookRegisterRequest("facebook_access_token"); assertEquals(HttpMethod.POST, request.getMethod()); assertTrue(request.getUrl(getContext()).getPath() .contains(LevelUpRequest.API_VERSION_CODE_V14)); assertTrue(request.getUrl(getContext()).getPath().endsWith("users")); final JSONObject userObject = new JSONObject(request.getBody(getContext())) .getJSONObject(UserRequestFactory.OUTER_PARAM_USER); assertTrue(userObject.has(UserRequestFactory.PARAM_FACEBOOK_ACCESS_TOKEN)); assertEquals("facebook_access_token", userObject .getString(UserRequestFactory.PARAM_FACEBOOK_ACCESS_TOKEN)); } @SmallTest public void testBuildBuildGetUserInfoRequest() throws BadRequestException, JSONException { final LevelUpRequest request = (LevelUpRequest) new UserRequestFactory(getContext(), new MockAccessTokenRetriever()).buildGetUserInfoRequest(); assertEquals(HttpMethod.GET, request.getMethod()); assertTrue(request.getUrl(getContext()).getPath() .contains(LevelUpRequest.API_VERSION_CODE_V15)); assertTrue(request.getUrl(getContext()).getPath().endsWith("users")); } /** * Validates the {@link com.scvngr.levelup.core.net.AbstractRequest} returned by {@link com.scvngr.levelup.core.net.request.factory.UserRequestFactory.UserInfoRequestBuilder#build()} * after adding all of the possible parameters. * * @throws com.scvngr.levelup.core.net.AbstractRequest.BadRequestException Thrown from * {@link com.scvngr.levelup.core.net.AbstractRequest#getUrl(android.content.Context)}. * @throws org.json.JSONException */ @SmallTest public void testUserInfoRequestBuilder_withParameters() throws BadRequestException, JSONException { final UserInfoRequestBuilder builder = new UserInfoRequestBuilder(getContext(), new MockAccessTokenRetriever()); final User user = UserFixture.getFullModel(); builder.withBornAt(user.getBornAt()); builder.withEmail(user.getEmail()); builder.withFirstName(user.getFirstName()); builder.withGender(user.getGender().toString()); builder.withLastName(user.getLastName()); final Map<String, String> customAttributes = user.getCustomAttributes(); for (final String key : customAttributes.keySet()) { builder.withCustomAttribute(key, customAttributes.get(key)); } final String newPassword = "password123"; builder.withNewPassword(newPassword); final LevelUpRequest request = (LevelUpRequest) builder.build(); assertEquals(HttpMethod.PUT, request.getMethod()); assertTrue("hits users/ endpoint", request.getUrl(getContext()).getPath() .endsWith("users")); assertTrue("Url points to proper api version", request.getUrl(getContext()).getPath() .contains(LevelUpRequest.API_VERSION_CODE_V15)); validateAccessTokenHeader(request); final JSONObject postParams = new JSONObject(request.getBody(getContext())) .getJSONObject(UserRequestFactory.OUTER_PARAM_USER); assertEquals(7, postParams.length()); assertEquals(user.getBornAt(), postParams.get(UserRequestFactory.PARAM_BORN_AT)); assertEquals(user.getEmail(), postParams.get(UserRequestFactory.PARAM_EMAIL)); assertEquals(user.getFirstName(), postParams.get(UserRequestFactory.PARAM_FIRST_NAME)); assertEquals(user.getGender().toString(), postParams.get(UserRequestFactory.PARAM_GENDER)); assertEquals(user.getLastName(), postParams.get(UserRequestFactory.PARAM_LAST_NAME)); final JSONObject customAttributesJson = postParams.getJSONObject(UserRequestFactory.PARAM_CUSTOM_ATTRIBUTES); assertEquals(2, customAttributesJson.length()); for (final String key : customAttributes.keySet()) { assertEquals(customAttributes.get(key), customAttributesJson.get(key)); } assertEquals(newPassword, postParams.get(UserRequestFactory.PARAM_NEW_PASSWORD)); } /** * Validates the {@link AbstractRequest} returned by {@link UserInfoRequestBuilder#build()} * after adding all of the possible parameters. * * @throws BadRequestException Thrown from * {@link AbstractRequest#getUrl(android.content.Context)}. * @throws JSONException */ @SmallTest public void testUserInfoRequestBuilder_withEnterpriseToken() throws BadRequestException, JSONException { final UserInfoRequestBuilder builder = new UserInfoRequestBuilder(getContext(), new MockAccessTokenRetriever( new AccessToken("test_access_token"))); final User user = UserFixture.getFullModel(); builder.withBornAt(user.getBornAt()); builder.withEmail(user.getEmail()); builder.withFirstName(user.getFirstName()); builder.withGender(user.getGender().toString()); builder.withLastName(user.getLastName()); final Map<String, String> customAttributes = user.getCustomAttributes(); for (final String key : customAttributes.keySet()) { builder.withCustomAttribute(key, customAttributes.get(key)); } final String newPassword = "password123"; builder.withNewPassword(newPassword); final AbstractRequest request = builder.build(); assertEquals(HttpMethod.PUT, request.getMethod()); assertTrue("hits users/ endpoint", request.getUrl(getContext()).getPath() .endsWith("users")); } @SmallTest public void testUserInfoRequestBuilder_NoNullParameters() throws BadRequestException { final UserInfoRequestBuilder builder = new UserInfoRequestBuilder(getContext(), new MockAccessTokenRetriever()); builder.withBornAt(null); builder.withEmail(null); builder.withFirstName(null); builder.withGender(null); builder.withLastName(null); builder.withNewPassword(null); builder.withCustomAttribute("test", null); final AbstractRequest expected = new UserInfoRequestBuilder(getContext(), new MockAccessTokenRetriever()).build(); assertEquals(expected, builder.build()); } @SmallTest public void testUserInfoRequestBuilder_AllowEmptyParameters() throws BadRequestException, JSONException { final UserInfoRequestBuilder builder = new UserInfoRequestBuilder(getContext(), new MockAccessTokenRetriever()); builder.withBornAt(""); builder.withEmail(""); builder.withFirstName(""); builder.withGender(""); builder.withLastName(""); builder.withNewPassword(""); builder.withCustomAttribute("test", ""); final AbstractRequest expected = new UserInfoRequestBuilder(getContext(), new MockAccessTokenRetriever()).build(); final LevelUpRequest request = (LevelUpRequest) builder.build(); assertNotSame(expected, request); final JSONObject postParams = new JSONObject(request.getBody(getContext())) .getJSONObject(UserRequestFactory.OUTER_PARAM_USER); assertEquals(7, postParams.length()); final JSONObject customAttributesJson = postParams.getJSONObject(UserRequestFactory.PARAM_CUSTOM_ATTRIBUTES); assertEquals(1, customAttributesJson.length()); assertEquals("", customAttributesJson.getString("test")); } /** * Validates the {@link com.scvngr.levelup.core.net.AbstractRequest} returned by {@link com.scvngr.levelup.core.net.request.factory.UserRequestFactory.UserInfoRequestBuilder#build()}. * * @throws com.scvngr.levelup.core.net.AbstractRequest.BadRequestException Thrown from * {@link com.scvngr.levelup.core.net.AbstractRequest#getUrl(android.content.Context)}. */ @SmallTest public void testUserInfoRequestBuilder_withoutParameters() throws BadRequestException { final AbstractRequest request = new UserInfoRequestBuilder(getContext(), new MockAccessTokenRetriever()).build(); assertTrue("hits users endpoint", request.getUrl(getContext()).getPath() .endsWith("users")); validateAccessTokenHeader(request); } /** * Validates the presence of the access token query parameter in the {@link com.scvngr.levelup.core.net.AbstractRequest}. * * @param request The {@link com.scvngr.levelup.core.net.AbstractRequest} to validate. * @throws com.scvngr.levelup.core.net.AbstractRequest.BadRequestException thrown by {@link com.scvngr.levelup.core.net.AbstractRequest#getUrl(android.content.Context)}. */ private void validateAccessTokenHeader(@NonNull final AbstractRequest request) throws BadRequestException { final Map<String, String> headers = request.getRequestHeaders(getContext()); assertTrue(headers.containsKey(LevelUpRequest.HEADER_AUTHORIZATION)); assertTrue(headers.get(LevelUpRequest.HEADER_AUTHORIZATION).contains( "test_access_token")); } @SmallTest public void testBuildRegisterRequest_withoutLocation() throws BadRequestException { validateRegisterRequest(null); } @SmallTest public void testBuildRegisterRequest_withLocation() throws BadRequestException { final Location location = new Location("test"); location.setLatitude(10d); location.setLongitude(20d); validateRegisterRequest(location); } /** * Helper to validate the register request and json. * * @param location the {@link android.location.Location} to set on register. * @throws com.scvngr.levelup.core.net.AbstractRequest.BadRequestException */ private void validateRegisterRequest(@Nullable final Location location) throws BadRequestException { final Context context = getContext(); final LevelUpRequest request = (LevelUpRequest) new UserRequestFactory(context, null).buildRegisterRequest( "first_name", "last_name", "email@example.com", "password123", location); assertEquals(HttpMethod.POST, request.getMethod()); final URL url = request.getUrl(context); assertTrue("proper URL/api version", url.getPath().endsWith("v14/users")); final String body = request.getBody(context); assertNotNull(body); assertFalse(request.getRequestHeaders(context).containsKey( LevelUpRequest.HEADER_AUTHORIZATION)); assertEquals(getExpectedRegisterJson(location), body); } public void testBuildRegisterRequest_withPermissions() throws BadRequestException { final List<String> expectedPermissions = new ArrayList<String>(); expectedPermissions.add("permission1"); expectedPermissions.add("permission2"); final Context context = getContext(); final LevelUpRequest request = (LevelUpRequest) new UserRequestFactory(context, null).buildRegisterRequest( "first_name", "last_name", "email@example.com", expectedPermissions); assertEquals(HttpMethod.POST, request.getMethod()); final URL url = request.getUrl(context); assertTrue("proper URL/api version", url.getPath().endsWith("v15/users")); final String body = request.getBody(context); assertNotNull(body); assertFalse(request.getRequestHeaders(context).containsKey( LevelUpRequest.HEADER_AUTHORIZATION)); assertEquals(getExpectedRegisterJsonWithPermissions(), body); } /** * Helper to get the String representation of the JSON that we are expecting in the request. * * @param location the location sent in the request * @return the json that we are expecting the request to create. */ @NonNull private String getExpectedRegisterJson(@Nullable final Location location) { final JSONObject object = new JSONObject(); final JSONObject userObject = new JSONObject(); try { final Context context = NullUtils.nonNullContract(getContext()); RequestUtils.addApiKeyToRequestBody(context, object); userObject.put(UserRequestFactory.PARAM_FIRST_NAME, "first_name"); userObject.put(UserRequestFactory.PARAM_LAST_NAME, "last_name"); userObject.put(UserRequestFactory.PARAM_EMAIL, "email@example.com"); userObject.put(UserRequestFactory.PARAM_TERMS_ACCEPTED, true); userObject.put(UserRequestFactory.PARAM_PASSWORD, "password123"); RequestUtils.addDeviceIdToRequestBody(context, userObject); if (null != location) { userObject.put(UserRequestFactory.PARAM_LATITUDE, location.getLatitude()); userObject.put(UserRequestFactory.PARAM_LONGITUDE, location.getLongitude()); } object.put(UserRequestFactory.OUTER_PARAM_USER, userObject); } catch (final JSONException e) { LogManager.e("JSONException building register request", e); } return object.toString(); } /** * Helper to get the String representation of the JSON that we are expecting in the request. * * @return the json that we are expecting the request to create. */ @NonNull private String getExpectedRegisterJsonWithPermissions() { final JSONObject object = new JSONObject(); final JSONObject userObject = new JSONObject(); final JSONArray permissionObject = new JSONArray(); try { final Context context = NullUtils.nonNullContract(getContext()); RequestUtils.addApiKeyToRequestBody(context, object); userObject.put(UserRequestFactory.PARAM_FIRST_NAME, "first_name"); userObject.put(UserRequestFactory.PARAM_LAST_NAME, "last_name"); userObject.put(UserRequestFactory.PARAM_EMAIL, "email@example.com"); userObject.put(UserRequestFactory.PARAM_TERMS_ACCEPTED, true); permissionObject.put("permission1"); permissionObject.put("permission2"); object.put(UserRequestFactory.OUTER_PARAM_USER, userObject); object.put(UserRequestFactory.OUTER_PARAM_PERMISSION_KEYNAMES, permissionObject); } catch (final JSONException e) { LogManager.e("JSONException building register request", e); } return object.toString(); } }