/*
* Copyright (c) 2015-present, Parse, LLC.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.parse;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import bolts.Task;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@SuppressWarnings("unchecked")
public class CachedCurrentUserControllerTest extends ResetPluginsParseTest {
private static final String KEY_AUTH_DATA = "authData";
@Before
public void setUp() throws Exception {
super.setUp();
ParseObject.registerSubclass(ParseUser.class);
}
@After
public void tearDown() throws Exception {
super.tearDown();
ParseObject.unregisterSubclass(ParseUser.class);
}
//region testSetAsync
@Test
public void testSetAsyncWithOldInMemoryCurrentUser() throws Exception {
// Mock currentUser in memory
ParseUser oldCurrentUser = mock(ParseUser.class);
when(oldCurrentUser.logOutAsync(anyBoolean())).thenReturn(Task.<Void>forResult(null));
ParseUser.State state = new ParseUser.State.Builder()
.put("key", "value")
.build();
ParseUser currentUser = ParseObject.from(state);
ParseObjectStore<ParseUser> store =
(ParseObjectStore<ParseUser>) mock(ParseObjectStore.class);
when(store.setAsync(currentUser)).thenReturn(Task.<Void>forResult(null));
CachedCurrentUserController controller =
new CachedCurrentUserController(store);
controller.currentUser = oldCurrentUser;
ParseTaskUtils.wait(controller.setAsync(currentUser));
// Make sure oldCurrentUser logout
verify(oldCurrentUser, times(1)).logOutAsync(false);
// Verify it was persisted
verify(store, times(1)).setAsync(currentUser);
// TODO(mengyan): Find a way to verify user.synchronizeAllAuthData() is called
// Verify newUser is currentUser
assertTrue(currentUser.isCurrentUser());
// Make sure in memory currentUser is up to date
assertSame(currentUser, controller.currentUser);
assertTrue(controller.currentUserMatchesDisk);
}
@Test
public void testSetAsyncWithNoInMemoryCurrentUser() throws Exception {
ParseUser.State state = new ParseUser.State.Builder()
.put("key", "value")
.build();
ParseUser currentUser = ParseObject.from(state);
ParseObjectStore<ParseUser> store =
(ParseObjectStore<ParseUser>) mock(ParseObjectStore.class);
when(store.setAsync(currentUser)).thenReturn(Task.<Void>forResult(null));
CachedCurrentUserController controller =
new CachedCurrentUserController(store);
ParseTaskUtils.wait(controller.setAsync(currentUser));
// Verify it was persisted
verify(store, times(1)).setAsync(currentUser);
// TODO(mengyan): Find a way to verify user.synchronizeAllAuthData() is called
// Verify newUser is currentUser
assertTrue(currentUser.isCurrentUser());
// Make sure in memory currentUser is up to date
assertSame(currentUser, controller.currentUser);
assertTrue(controller.currentUserMatchesDisk);
}
@Test
public void testSetAsyncWithPersistFailure() throws Exception {
// Mock currentUser in memory
ParseUser oldCurrentUser = mock(ParseUser.class);
when(oldCurrentUser.logOutAsync(anyBoolean())).thenReturn(Task.<Void>forResult(null));
ParseUser currentUser = new ParseUser();
ParseObjectStore<ParseUser> store =
(ParseObjectStore<ParseUser>) mock(ParseObjectStore.class);
when(store.setAsync(currentUser))
.thenReturn(Task.<Void>forError(new RuntimeException("failure")));
CachedCurrentUserController controller =
new CachedCurrentUserController(store);
controller.currentUser = oldCurrentUser;
ParseTaskUtils.wait(controller.setAsync(currentUser));
// Make sure oldCurrentUser logout
verify(oldCurrentUser, times(1)).logOutAsync(false);
// Verify we tried to persist
verify(store, times(1)).setAsync(currentUser);
// TODO(mengyan): Find a way to verify user.synchronizeAllAuthData() is called
// Verify newUser is currentUser
assertTrue(currentUser.isCurrentUser());
// Make sure in memory currentUser is up to date
assertSame(currentUser, controller.currentUser);
// Make sure in currentUserMatchesDisk since we can not write to disk
assertFalse(controller.currentUserMatchesDisk);
}
//endregion
//region testGetAsync
@Test
public void testGetAsyncWithInMemoryCurrentUserSet() throws Exception {
ParseUser currentUserInMemory = new ParseUser();
CachedCurrentUserController controller =
new CachedCurrentUserController(null);
controller.currentUser = currentUserInMemory;
ParseUser currentUser = ParseTaskUtils.wait(controller.getAsync(false));
assertSame(currentUserInMemory, currentUser);
}
@Test
public void testGetAsyncWithNoInMemoryCurrentUserAndLazyLogin() throws Exception {
ParseObjectStore<ParseUser> store =
(ParseObjectStore<ParseUser>) mock(ParseObjectStore.class);
when(store.getAsync()).thenReturn(Task.<ParseUser>forResult(null));
CachedCurrentUserController controller =
new CachedCurrentUserController(store);
ParseCorePlugins.getInstance().registerCurrentUserController(controller);
// CurrentUser is null but currentUserMatchesDisk is true happens when a user logout
controller.currentUserMatchesDisk = true;
ParseUser currentUser = ParseTaskUtils.wait(controller.getAsync(true));
// We need to make sure the user is created by lazy login
assertTrue(currentUser.isLazy());
assertTrue(currentUser.isCurrentUser());
assertSame(controller.currentUser, currentUser);
assertFalse(controller.currentUserMatchesDisk);
// We do not test the lazy login auth data here, it is covered in lazyLogin() unit test
}
@Test
public void testGetAsyncWithNoInMemoryAndInDiskCurrentUserAndNoLazyLogin()
throws Exception {
ParseObjectStore<ParseUser> store =
(ParseObjectStore<ParseUser>) mock(ParseObjectStore.class);
when(store.getAsync()).thenReturn(Task.<ParseUser>forResult(null));
CachedCurrentUserController controller =
new CachedCurrentUserController(store);
// CurrentUser is null but currentUserMatchesDisk is true happens when a user logout
controller.currentUserMatchesDisk = true;
ParseUser currentUser = ParseTaskUtils.wait(controller.getAsync(false));
assertNull(currentUser);
}
@Test
public void testGetAsyncWithCurrentUserReadFromDiskSuccess() throws Exception {
ParseUser.State state = new ParseUser.State.Builder()
.put("key", "value")
.build();
ParseUser currentUserInDisk = ParseObject.from(state);
ParseObjectStore<ParseUser> store =
(ParseObjectStore<ParseUser>) mock(ParseObjectStore.class);
when(store.getAsync()).thenReturn(Task.forResult(currentUserInDisk));
CachedCurrentUserController controller =
new CachedCurrentUserController(store);
ParseUser currentUser = ParseTaskUtils.wait(controller.getAsync(false));
assertSame(currentUser, currentUserInDisk);
assertSame(currentUser, controller.currentUser);
assertTrue(controller.currentUserMatchesDisk);
assertTrue(currentUser.isCurrentUser());
assertEquals("value", currentUser.get("key"));
}
@Test
public void testGetAsyncAnonymousUser() throws Exception{
ParseUser.State state = new ParseUser.State.Builder()
.objectId("fake")
.putAuthData(ParseAnonymousUtils.AUTH_TYPE, new HashMap<String, String>())
.build();
ParseObjectStore<ParseUser> store =
(ParseObjectStore<ParseUser>) mock(ParseObjectStore.class);
when(store.getAsync()).thenReturn(Task.forResult(ParseObject.<ParseUser>from(state)));
CachedCurrentUserController controller =
new CachedCurrentUserController(store);
ParseUser user = ParseTaskUtils.wait(controller.getAsync(false));
assertFalse(user.isLazy());
}
@Test
public void testGetAsyncLazyAnonymousUser() throws Exception{
ParseUser.State state = new ParseUser.State.Builder()
.putAuthData(ParseAnonymousUtils.AUTH_TYPE, new HashMap<String, String>())
.build();
ParseObjectStore<ParseUser> store =
(ParseObjectStore<ParseUser>) mock(ParseObjectStore.class);
when(store.getAsync()).thenReturn(Task.forResult(ParseObject.<ParseUser>from(state)));
CachedCurrentUserController controller =
new CachedCurrentUserController(store);
ParseUser user = ParseTaskUtils.wait(controller.getAsync(false));
assertTrue(user.isLazy());
}
@Test
public void testGetAsyncWithCurrentUserReadFromDiskFailure() throws Exception {
ParseObjectStore<ParseUser> store =
(ParseObjectStore<ParseUser>) mock(ParseObjectStore.class);
when(store.getAsync()).thenReturn(Task.<ParseUser>forError(new RuntimeException("failure")));
CachedCurrentUserController controller =
new CachedCurrentUserController(store);
ParseUser currentUser = ParseTaskUtils.wait(controller.getAsync(false));
assertNull(currentUser);
}
@Test
public void testGetAsyncWithCurrentUserReadFromDiskFailureAndLazyLogin() throws Exception {
ParseObjectStore<ParseUser> store =
(ParseObjectStore<ParseUser>) mock(ParseObjectStore.class);
when(store.getAsync()).thenReturn(Task.<ParseUser>forError(new RuntimeException("failure")));
CachedCurrentUserController controller =
new CachedCurrentUserController(store);
ParseUser currentUser = ParseTaskUtils.wait(controller.getAsync(true));
// We need to make sure the user is created by lazy login
assertTrue(currentUser.isLazy());
assertTrue(currentUser.isCurrentUser());
assertSame(controller.currentUser, currentUser);
assertFalse(controller.currentUserMatchesDisk);
// We do not test the lazy login auth data here, it is covered in lazyLogin() unit test
}
//endregion
//region testLogoOutAsync
@Test
public void testLogOutAsyncWithDeleteInDiskCurrentUserSuccess() throws Exception {
ParseObjectStore<ParseUser> store =
(ParseObjectStore<ParseUser>) mock(ParseObjectStore.class);
when(store.deleteAsync()).thenReturn(Task.<Void>forResult(null));
CachedCurrentUserController controller =
new CachedCurrentUserController(store);
// We set the currentUser to make sure getAsync() return a mock user
ParseUser currentUser = mock(ParseUser.class);
when(currentUser.logOutAsync()).thenReturn(Task.<Void>forResult(null));
controller.currentUser = currentUser;
ParseTaskUtils.wait(controller.logOutAsync());
// Make sure currentUser.logout() is called
verify(currentUser, times(1)).logOutAsync();
// Make sure in disk currentUser is deleted
verify(store, times(1)).deleteAsync();
// Make sure controller state is correct
assertNull(controller.currentUser);
assertTrue(controller.currentUserMatchesDisk);
}
@Test
public void testLogOutAsyncWithDeleteInDiskCurrentUserFailure() throws Exception {
ParseObjectStore<ParseUser> store =
(ParseObjectStore<ParseUser>) mock(ParseObjectStore.class);
when(store.getAsync()).thenReturn(Task.<ParseUser>forResult(null));
when(store.deleteAsync()).thenReturn(Task.<Void>forError(new RuntimeException("failure")));
CachedCurrentUserController controller =
new CachedCurrentUserController(store);
ParseTaskUtils.wait(controller.logOutAsync());
// Make sure controller state is correct
assertNull(controller.currentUser);
assertFalse(controller.currentUserMatchesDisk);
}
//endregion
//region testLazyLogin
@Test
public void testLazyLogin() throws Exception {
CachedCurrentUserController controller =
new CachedCurrentUserController(null);
String authType = ParseAnonymousUtils.AUTH_TYPE;
Map<String, String> authData = new HashMap<>();
authData.put("sessionToken", "testSessionToken");
ParseUser user = controller.lazyLogIn(authType, authData);
// Make sure use is generated through lazyLogin
assertTrue(user.isLazy());
assertTrue(user.isCurrentUser());
Map<String, Map<String, String>> authPair = user.getMap(KEY_AUTH_DATA);
assertEquals(1, authPair.size());
Map<String, String> authDataAgain = authPair.get(authType);
assertEquals(1, authDataAgain.size());
assertEquals("testSessionToken", authDataAgain.get("sessionToken"));
// Make sure controller state is correct
assertSame(user, controller.currentUser);
assertFalse(controller.currentUserMatchesDisk);
}
//endregion
//region testGetCurrentSessionTokenAsync
@Test
public void testGetCurrentSessionTokenAsyncWithCurrentUserSet() throws Exception {
CachedCurrentUserController controller =
new CachedCurrentUserController(null);
// We set the currentUser to make sure getAsync() return a mock user
ParseUser currentUser = mock(ParseUser.class);
when(currentUser.getSessionToken()).thenReturn("sessionToken");
controller.currentUser = currentUser;
String sessionToken = ParseTaskUtils.wait(controller.getCurrentSessionTokenAsync());
assertEquals("sessionToken", sessionToken);
}
@Test
public void testGetCurrentSessionTokenAsyncWithNoCurrentUserSet() throws Exception {
ParseObjectStore<ParseUser> store =
(ParseObjectStore<ParseUser>) mock(ParseObjectStore.class);
when(store.getAsync()).thenReturn(Task.<ParseUser>forResult(null));
CachedCurrentUserController controller =
new CachedCurrentUserController(store);
String sessionToken = ParseTaskUtils.wait(controller.getCurrentSessionTokenAsync());
assertNull(sessionToken);
}
//endregion
//region testClearFromMemory
@Test
public void testClearFromMemory() throws Exception {
CachedCurrentUserController controller =
new CachedCurrentUserController(null);
controller.currentUser = mock(ParseUser.class);
controller.clearFromMemory();
assertNull(controller.currentUser);
assertFalse(controller.currentUserMatchesDisk);
}
//endregion
//region testClearFromDisk()
@Test
public void testClearFromDisk() throws Exception {
ParseObjectStore<ParseUser> store =
(ParseObjectStore<ParseUser>) mock(ParseObjectStore.class);
when(store.deleteAsync()).thenReturn(Task.<Void>forResult(null));
CachedCurrentUserController controller =
new CachedCurrentUserController(store);
controller.currentUser = new ParseUser();
controller.clearFromDisk();
assertNull(controller.currentUser);
assertFalse(controller.currentUserMatchesDisk);
verify(store, times(1)).deleteAsync();
}
//endregion
//region testExistsAsync()
@Test
public void testExistsAsyncWithInMemoryCurrentUserSet() throws Exception {
CachedCurrentUserController controller =
new CachedCurrentUserController(null);
controller.currentUser = new ParseUser();
assertTrue(ParseTaskUtils.wait(controller.existsAsync()));
}
@Test
public void testExistsAsyncWithInDiskCurrentUserSet() throws Exception {
ParseObjectStore<ParseUser> store =
(ParseObjectStore<ParseUser>) mock(ParseObjectStore.class);
when(store.existsAsync()).thenReturn(Task.forResult(true));
CachedCurrentUserController controller =
new CachedCurrentUserController(store);
assertTrue(ParseTaskUtils.wait(controller.existsAsync()));
}
@Test
public void testExistsAsyncWithNoInMemoryAndInDiskCurrentUserSet() throws Exception {
ParseObjectStore<ParseUser> store =
(ParseObjectStore<ParseUser>) mock(ParseObjectStore.class);
when(store.existsAsync()).thenReturn(Task.forResult(false));
CachedCurrentUserController controller =
new CachedCurrentUserController(store);
assertFalse(ParseTaskUtils.wait(controller.existsAsync()));
}
//endregion
//region testIsCurrent
@Test
public void testIsCurrent() throws Exception {
CachedCurrentUserController controller =
new CachedCurrentUserController(null);
ParseUser currentUser = new ParseUser();
controller.currentUser = currentUser;
assertTrue(controller.isCurrent(currentUser));
assertFalse(controller.isCurrent(new ParseUser()));
}
//endregion
}