Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(47)

Unified Diff: chrome/android/junit/src/org/chromium/chrome/browser/ChromeBackupAgentTest.java

Issue 2511713002: Implement Android key/value backup (Closed)
Patch Set: Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/junit/src/org/chromium/chrome/browser/ChromeBackupAgentTest.java
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ChromeBackupAgentTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ChromeBackupAgentTest.java
index 3d95fdbe23ae0308cfc1abf9306ef1cdc14e9419..3ae9e03651a2ee685cbe14824d9ac70aa0b44ab5 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ChromeBackupAgentTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ChromeBackupAgentTest.java
@@ -4,181 +4,379 @@
package org.chromium.chrome.browser;
-import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.CoreMatchers.nullValue;
-
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
import android.content.Context;
import android.content.SharedPreferences;
+import android.os.ParcelFileDescriptor;
-import org.chromium.base.ContextUtils;
-import org.chromium.testing.local.LocalRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
+import org.chromium.base.BaseChromiumApplication;
+import org.chromium.base.ContextUtils;
+import org.chromium.base.library_loader.ProcessInitException;
+import org.chromium.chrome.browser.firstrun.FirstRunSignInProcessor;
+import org.chromium.chrome.browser.firstrun.FirstRunStatus;
+import org.chromium.components.signin.ChromeSigninController;
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
/**
* Unit tests for {@link org.chromium.chrome.browser.ChromeBackupAgent}.
*/
@RunWith(LocalRobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
+@Config(manifest = Config.NONE, application = BaseChromiumApplication.class)
public class ChromeBackupAgentTest {
-
- static class ChromeTestBackupAgent extends ChromeBackupAgent {
-
- private ByteArrayInputStream mInputStream;
- private ByteArrayOutputStream mOutputStream;
-
- ChromeTestBackupAgent(byte[] mChromeInputPrefs) {
- // This is protected in ContextWrapper, so can only be called within a derived
- // class.
- attachBaseContext(RuntimeEnvironment.application);
- mInputStream = new ByteArrayInputStream(mChromeInputPrefs);
- mOutputStream = new ByteArrayOutputStream();
- }
-
- @Override
- protected InputStream openInputStream(File prefsFile) throws FileNotFoundException {
- return mInputStream;
-
- }
-
- @Override
- protected OutputStream openOutputStream(File prefsFile) throws FileNotFoundException {
- return mOutputStream;
- }
-
- @Override
- public File getDir(String name, int mode) {
- return null;
- }
-
- @Override
- protected long getFileLength(File prefsFile) {
- return mInputStream.available();
- }
-
- byte[] getOutputData() {
- return mOutputStream.toByteArray();
- }
+ private Context mContext;
+ private ChromeBackupAgent mAgent;
+
+ private void setUpTestPrefs(SharedPreferences prefs) {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(FirstRunStatus.FIRST_RUN_FLOW_COMPLETE, true);
+ editor.putBoolean(FirstRunSignInProcessor.FIRST_RUN_FLOW_SIGNIN_SETUP, false);
+ editor.putString(ChromeSigninController.SIGNED_IN_ACCOUNT_KEY, "user1");
+ editor.apply();
}
@Before
- public void setUp() throws Exception {
- ContextUtils.initApplicationContextForTests(RuntimeEnvironment.application);
- AccountManager manager = (AccountManager) RuntimeEnvironment.application.getSystemService(
- Context.ACCOUNT_SERVICE);
- manager.addAccountExplicitly(new Account("user1", "dummy"), null, null);
- manager.addAccountExplicitly(new Account("user2", "dummy"), null, null);
+ public void setUp() throws ProcessInitException {
+ // Set up the context.
+ mContext = RuntimeEnvironment.application.getApplicationContext();
+ ContextUtils.initApplicationContextForTests(mContext);
+
+ // Override the native calls.
+ mAgent = spy(new ChromeBackupAgent());
+ doReturn(new String[] {"pref1"}).when(mAgent).nativeGetBoolBackupNames();
+ doReturn(new boolean[] {true}).when(mAgent).nativeGetBoolBackupValues();
+ doNothing().when(mAgent).nativeSetBoolBackupPrefs(
+ any(String[].class), any(boolean[].class));
+
+ // Mock initializing the browser
+ doReturn(true).when(mAgent).initializeBrowser(any(Context.class));
}
+ /**
+ * Test method for {@link ChromeBackupAgent#onBackup} testing first backup
+ *
+ * @throws ProcessInitException
+ */
@Test
- public void testOnRestoreFinished() throws UnsupportedEncodingException {
- SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences();
- SharedPreferences.Editor editor = sharedPrefs.edit();
- editor.putBoolean("metrics_reporting", false);
- editor.putString("google.services.username", "user1");
- editor.putString("junk", "junk");
- editor.apply();
-
- String chromeInputPrefs =
- "{\"junk1\":\"abc\", "
- + "\"sync\":{ \"has_setup_completed\":\"true\", "
- + " \"keep_everything_synced\":\"false\", "
- + " \"junk2\":\"xxx\""
- + " }}";
- byte[] chromePrefsBuffer = chromeInputPrefs.getBytes("UTF-8");
- ChromeTestBackupAgent chromeTestBackupAgent = new ChromeTestBackupAgent(chromePrefsBuffer);
- chromeTestBackupAgent.onRestoreFinished();
-
- String chromeOutputPrefs = new String(chromeTestBackupAgent.getOutputData(), "UTF-8");
+ @SuppressWarnings("unchecked")
+ public void testOnBackup_firstBackup() throws FileNotFoundException, IOException,
+ ClassNotFoundException, ProcessInitException {
+ // Mock the backup data.
+ BackupDataOutput backupData = mock(BackupDataOutput.class);
+
+ // Create a state file.
+ File stateFile1 = File.createTempFile("Test", "");
+ ParcelFileDescriptor newState =
+ ParcelFileDescriptor.open(stateFile1, ParcelFileDescriptor.parseMode("w"));
+
+ // Set up some preferences to back up.
+ SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
+ setUpTestPrefs(prefs);
+
+ // Run the test function.
+ mAgent.onBackup(null, backupData, newState);
+
+ // Check that the right things were written to the backup
+ verify(backupData).writeEntityHeader("native.pref1", 1);
+ verify(backupData)
+ .writeEntityHeader("AndroidDefault." + FirstRunStatus.FIRST_RUN_FLOW_COMPLETE, 1);
+ verify(backupData, times(2)).writeEntityData(new byte[] {1}, 1);
+ verify(backupData)
+ .writeEntityHeader(
+ "AndroidDefault." + FirstRunSignInProcessor.FIRST_RUN_FLOW_SIGNIN_SETUP, 1);
+ verify(backupData).writeEntityData(new byte[] {0}, 1);
+ byte[] unameBytes = "user1".getBytes();
+ verify(backupData)
+ .writeEntityHeader("AndroidDefault." + ChromeSigninController.SIGNED_IN_ACCOUNT_KEY,
+ unameBytes.length);
+ verify(backupData).writeEntityData(unameBytes, unameBytes.length);
+
+ newState.close();
+
+ // Check that the state was saved correctly
+ ObjectInputStream newStateStream = new ObjectInputStream(new FileInputStream(stateFile1));
+ ArrayList<String> names = (ArrayList<String>) newStateStream.readObject();
+ assertThat(names.size(), equalTo(4));
+ assertThat(names, hasItem("native.pref1"));
+ assertThat(names, hasItem("AndroidDefault." + FirstRunStatus.FIRST_RUN_FLOW_COMPLETE));
+ assertThat(names,
+ hasItem("AndroidDefault." + FirstRunSignInProcessor.FIRST_RUN_FLOW_SIGNIN_SETUP));
+ assertThat(
+ names, hasItem("AndroidDefault." + ChromeSigninController.SIGNED_IN_ACCOUNT_KEY));
+ ArrayList<byte[]> values = (ArrayList<byte[]>) newStateStream.readObject();
+ assertThat(values.size(), equalTo(4));
+ assertThat(values, hasItem(unameBytes));
+ assertThat(values, hasItem(new byte[] {0}));
+ assertThat(values, hasItem(new byte[] {1}));
+ // Make sure that there are no extra objects.
+ assertThat(newStateStream.available(), equalTo(0));
+
+ // Tidy up.
+ newStateStream.close();
+ stateFile1.delete();
+ }
- // Check that we have only restored the correct Chrome preferences
- assertThat(chromeOutputPrefs, containsString("\"has_setup_completed\":\"true\""));
- assertThat(chromeOutputPrefs, containsString("\"keep_everything_synced\":\"false\""));
- assertThat(chromeOutputPrefs, not(containsString("junk")));
+ /**
+ * Test method for {@link ChromeBackupAgent#onBackup} a second backup with the same data
+ */
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testOnBackup_duplicateBackup()
+ throws FileNotFoundException, IOException, ClassNotFoundException {
+ // Mock the backup data.
+ BackupDataOutput backupData = mock(BackupDataOutput.class);
+
+ // Create a state file.
+ File stateFile1 = File.createTempFile("Test", "");
+ ParcelFileDescriptor newState =
+ ParcelFileDescriptor.open(stateFile1, ParcelFileDescriptor.parseMode("w"));
+
+ // Set up some preferences to back up.
+ SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
+ setUpTestPrefs(prefs);
+
+ // Do a first backup.
+ mAgent.onBackup(null, backupData, newState);
+
+ // Minimal check on first backup, this isn't the test here.
+ verify(backupData, times(4)).writeEntityHeader(anyString(), anyInt());
+ verify(backupData, times(4)).writeEntityData(any(byte[].class), anyInt());
+
+ newState.close();
+
+ ParcelFileDescriptor oldState =
+ ParcelFileDescriptor.open(stateFile1, ParcelFileDescriptor.parseMode("r"));
+ File stateFile2 = File.createTempFile("Test", "");
+ newState = ParcelFileDescriptor.open(stateFile2, ParcelFileDescriptor.parseMode("w"));
+
+ // Try a second backup without changing any data
+ mAgent.onBackup(oldState, backupData, newState);
+
+ // Check that the second backup didn't write anything.
+ verifyNoMoreInteractions(backupData);
+
+ oldState.close();
+ newState.close();
+
+ // The two state files should contain identical data.
+ ObjectInputStream oldStateStream = new ObjectInputStream(new FileInputStream(stateFile1));
+ ArrayList<String> oldNames = (ArrayList<String>) oldStateStream.readObject();
+ ArrayList<byte[]> oldValues = (ArrayList<byte[]>) oldStateStream.readObject();
+ ObjectInputStream newStateStream = new ObjectInputStream(new FileInputStream(stateFile2));
+ ArrayList<String> newNames = (ArrayList<String>) newStateStream.readObject();
+ ArrayList<byte[]> newValues = (ArrayList<byte[]>) newStateStream.readObject();
+ assertThat(newNames, equalTo(oldNames));
+ assertTrue(Arrays.deepEquals(newValues.toArray(), oldValues.toArray()));
+ assertThat(newStateStream.available(), equalTo(0));
+
+ // Tidy up.
+ oldStateStream.close();
+ newStateStream.close();
+ stateFile1.delete();
+ stateFile2.delete();
+ }
+ /**
+ * Test method for {@link ChromeBackupAgent#onBackup} a second backup with different data
+ */
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testOnBackup_dataChanged()
+ throws FileNotFoundException, IOException, ClassNotFoundException {
+ // Mock the backup data.
+ BackupDataOutput backupData = mock(BackupDataOutput.class);
+
+ // Create a state file.
+ File stateFile1 = File.createTempFile("Test", "");
+ ParcelFileDescriptor newState =
+ ParcelFileDescriptor.open(stateFile1, ParcelFileDescriptor.parseMode("w"));
+
+ // Set up some preferences to back up.
+ SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
+ setUpTestPrefs(prefs);
+
+ // Do a first backup.
+ mAgent.onBackup(null, backupData, newState);
+
+ // Minimal check on first backup, this isn't the test here.
+ verify(backupData, times(4)).writeEntityHeader(anyString(), anyInt());
+ verify(backupData, times(4)).writeEntityData(any(byte[].class), anyInt());
+
+ newState.close();
+
+ ParcelFileDescriptor oldState =
+ ParcelFileDescriptor.open(stateFile1, ParcelFileDescriptor.parseMode("r"));
+ File stateFile2 = File.createTempFile("Test", "");
+ newState = ParcelFileDescriptor.open(stateFile2, ParcelFileDescriptor.parseMode("w"));
+
+ // Change some data.
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(FirstRunSignInProcessor.FIRST_RUN_FLOW_SIGNIN_SETUP, true);
+ editor.apply();
- // Check that we have only restored the correct Android preferences
- assertThat(sharedPrefs.getBoolean("metrics_reporting", true), equalTo(false));
- assertThat(sharedPrefs.getString("google.services.username", null), nullValue());
- assertThat(sharedPrefs.getString("junk", null), nullValue());
+ // Do a second backup.
+ mAgent.onBackup(oldState, backupData, newState);
+
+ // Check that the second backup wrote something.
+ verify(backupData, times(8)).writeEntityHeader(anyString(), anyInt());
+ verify(backupData, times(8)).writeEntityData(any(byte[].class), anyInt());
+
+ oldState.close();
+ newState.close();
+
+ // the two state files should contain different data (although the names are unchanged).
+ ObjectInputStream oldStateStream = new ObjectInputStream(new FileInputStream(stateFile1));
+ ArrayList<String> oldNames = (ArrayList<String>) oldStateStream.readObject();
+ ArrayList<byte[]> oldValues = (ArrayList<byte[]>) oldStateStream.readObject();
+ ObjectInputStream newStateStream = new ObjectInputStream(new FileInputStream(stateFile2));
+ ArrayList<String> newNames = (ArrayList<String>) newStateStream.readObject();
+ ArrayList<byte[]> newValues = (ArrayList<byte[]>) newStateStream.readObject();
+ assertThat(newNames, equalTo(oldNames));
+ assertFalse(Arrays.deepEquals(newValues.toArray(), oldValues.toArray()));
+ assertThat(newStateStream.available(), equalTo(0));
+
+ // Tidy up.
+ oldStateStream.close();
+ newStateStream.close();
+ stateFile1.delete();
+ stateFile2.delete();
+ }
- // Check that the preferences for which there is special code are correct
- assertThat(sharedPrefs.getString("first_run_signin_account_name", null), equalTo("user1"));
+ private BackupDataInput createMockBackupData() throws IOException {
+ // Mock the backup data
+ BackupDataInput backupData = mock(BackupDataInput.class);
+
+ final String[] keys = {"native.pref1", "native.pref2",
+ "AndroidDefault." + FirstRunStatus.FIRST_RUN_FLOW_COMPLETE, "AndroidDefault.junk",
+ "AndroidDefault." + ChromeSigninController.SIGNED_IN_ACCOUNT_KEY};
+ byte[] unameBytes = "user1".getBytes();
+ final byte[][] values = {{0}, {1}, {1}, {23, 42}, unameBytes};
+ when(backupData.getKey()).thenAnswer(new Answer<String>() {
+ private int mPos = 0;
+
+ @Override
+ public String answer(InvocationOnMock invocation) throws Throwable {
+ return keys[mPos++];
+ }
+ });
+
+ when(backupData.getDataSize()).thenAnswer(new Answer<Integer>() {
+ private int mPos = 0;
+
+ @Override
+ public Integer answer(InvocationOnMock invocation) throws Throwable {
+ return values[mPos++].length;
+ }
+ });
+
+ when(backupData.readEntityData(any(byte[].class), anyInt(), anyInt()))
+ .thenAnswer(new Answer<Integer>() {
+ private int mPos = 0;
+
+ @Override
+ public Integer answer(InvocationOnMock invocation) throws Throwable {
+ // TODO(aberent): Auto-generated method stub
+ byte[] buffer = invocation.getArgument(0);
+ for (int i = 0; i < values[mPos].length; i++) {
+ buffer[i] = values[mPos][i];
+ }
+ return values[mPos++].length;
+ }
+ });
+
+ when(backupData.readNextHeader()).thenAnswer(new Answer<Boolean>() {
+ private int mPos = 0;
+
+ @Override
+ public Boolean answer(InvocationOnMock invocation) throws Throwable {
+ return mPos++ < 5;
+ }
+ });
+ return backupData;
}
+ /**
+ * Test method for {@link ChromeBackupAgent#onRestore}.
+ *
+ * @throws IOException
+ * @throws ClassNotFoundException
+ */
@Test
- public void testOnRestoreFinishedNoUser() throws UnsupportedEncodingException {
- SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences();
- SharedPreferences.Editor editor = sharedPrefs.edit();
- editor.putBoolean("metrics_reporting", false);
- editor.putString("junk", "junk");
- editor.apply();
-
- String chromeInputPrefs =
- "{\"junk1\":\"abc\", "
- + "\"sync\":{ \"has_setup_completed\":\"true\", "
- + " \"keep_everything_synced\":\"false\", "
- + " \"junk2\":\"xxx\""
- + " }}";
- byte[] chromePrefsBuffer = chromeInputPrefs.getBytes("UTF-8");
- ChromeTestBackupAgent chromeTestBackupAgent = new ChromeTestBackupAgent(chromePrefsBuffer);
- chromeTestBackupAgent.onRestoreFinished();
-
- // Check that we haven't restored any Chrome preferences
- String chromeOutputPrefs = new String(chromeTestBackupAgent.getOutputData(), "UTF-8");
- assertThat(chromeOutputPrefs, equalTo(""));
-
- // Check that we haven't restored any Android preferences
- assertThat(sharedPrefs.getBoolean("metrics_reporting", true), equalTo(true));
- assertThat(sharedPrefs.getString("google.services.username", null), nullValue());
- assertThat(sharedPrefs.getString("junk", null), nullValue());
- assertThat(sharedPrefs.getString("first_run_signin_account_name", null), nullValue());
+ public void testOnRestore_normal() throws IOException, ClassNotFoundException {
+ BackupDataInput backupData = createMockBackupData();
+
+ doReturn(true).when(mAgent).accountExistsOnDevice(any(String.class));
+
+ // Create a state file.
+ File stateFile = File.createTempFile("Test", "");
+ ParcelFileDescriptor newState =
+ ParcelFileDescriptor.open(stateFile, ParcelFileDescriptor.parseMode("w"));
+
+ // Do a restore.
+ mAgent.onRestore(backupData, 0, newState);
+ SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
+ assertTrue(prefs.getBoolean(FirstRunStatus.FIRST_RUN_FLOW_COMPLETE, false));
+ assertFalse(prefs.contains("junk"));
+ verify(mAgent).nativeSetBoolBackupPrefs(
+ new String[] {"pref1", "pref2"}, new boolean[] {false, true});
}
+ /**
+ * Test method for {@link ChromeBackupAgent#onRestore} for a user that doesn't exist on the
+ * device
+ *
+ * @throws IOException
+ * @throws ClassNotFoundException
+ */
@Test
- public void testOnRestoreFinishedWrongUser() throws UnsupportedEncodingException {
- SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences();
- SharedPreferences.Editor editor = sharedPrefs.edit();
- editor.putBoolean("metrics_reporting", false);
- editor.putString("google.services.username", "wrong_user");
- editor.putString("junk", "junk");
- editor.apply();
+ public void testOnRestore_badUser() throws IOException, ClassNotFoundException {
+ BackupDataInput backupData = createMockBackupData();
+
+ doReturn(false).when(mAgent).accountExistsOnDevice(any(String.class));
+
+ // Create a state file.
+ File stateFile = File.createTempFile("Test", "");
+ ParcelFileDescriptor newState =
+ ParcelFileDescriptor.open(stateFile, ParcelFileDescriptor.parseMode("w"));
- String chromeInputPrefs =
- "{\"junk1\":\"abc\", "
- + "\"sync\":{ \"has_setup_completed\":\"true\", "
- + " \"keep_everything_synced\":\"false\", "
- + " \"junk2\":\"xxx\""
- + " }}";
- byte[] chromePrefsBuffer = chromeInputPrefs.getBytes("UTF-8");
- ChromeTestBackupAgent chromeTestBackupAgent = new ChromeTestBackupAgent(chromePrefsBuffer);
- chromeTestBackupAgent.onRestoreFinished();
-
- // Check that we haven't restored any Chrome preferences
- String chromeOutputPrefs = new String(chromeTestBackupAgent.getOutputData(), "UTF-8");
- assertThat(chromeOutputPrefs, equalTo(""));
-
- // Check that we haven't restored any Android preferences
- assertThat(sharedPrefs.getBoolean("metrics_reporting", true), equalTo(true));
- assertThat(sharedPrefs.getString("google.services.username", null), nullValue());
- assertThat(sharedPrefs.getString("junk", null), nullValue());
- assertThat(sharedPrefs.getString("first_run_signin_account_name", null), nullValue());
+ // Do a restore.
+ mAgent.onRestore(backupData, 0, newState);
+ SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
+ assertFalse(prefs.contains(FirstRunStatus.FIRST_RUN_FLOW_COMPLETE));
+ verify(mAgent, never()).nativeSetBoolBackupPrefs(any(String[].class), any(boolean[].class));
}
}
« no previous file with comments | « chrome/android/javatests/src/org/chromium/chrome/browser/ChromeBackupIntegrationTest.java ('k') | chrome/browser/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698