1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/tests/background/junit3/src/sync/TestResetting.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,205 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + http://creativecommons.org/publicdomain/zero/1.0/ */ 1.6 + 1.7 +package org.mozilla.gecko.background.sync; 1.8 + 1.9 +import java.io.IOException; 1.10 + 1.11 +import org.json.simple.parser.ParseException; 1.12 +import org.mozilla.gecko.background.helpers.AndroidSyncTestCase; 1.13 +import org.mozilla.gecko.background.testhelpers.BaseMockServerSyncStage; 1.14 +import org.mozilla.gecko.background.testhelpers.DefaultGlobalSessionCallback; 1.15 +import org.mozilla.gecko.background.testhelpers.MockRecord; 1.16 +import org.mozilla.gecko.background.testhelpers.MockSharedPreferences; 1.17 +import org.mozilla.gecko.background.testhelpers.WBORepository; 1.18 +import org.mozilla.gecko.background.testhelpers.WaitHelper; 1.19 +import org.mozilla.gecko.sync.EngineSettings; 1.20 +import org.mozilla.gecko.sync.GlobalSession; 1.21 +import org.mozilla.gecko.sync.MetaGlobalException; 1.22 +import org.mozilla.gecko.sync.NonObjectJSONException; 1.23 +import org.mozilla.gecko.sync.SyncConfiguration; 1.24 +import org.mozilla.gecko.sync.SyncConfigurationException; 1.25 +import org.mozilla.gecko.sync.SynchronizerConfiguration; 1.26 +import org.mozilla.gecko.sync.crypto.CryptoException; 1.27 +import org.mozilla.gecko.sync.crypto.KeyBundle; 1.28 +import org.mozilla.gecko.sync.delegates.GlobalSessionCallback; 1.29 +import org.mozilla.gecko.sync.net.AuthHeaderProvider; 1.30 +import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider; 1.31 +import org.mozilla.gecko.sync.repositories.domain.Record; 1.32 +import org.mozilla.gecko.sync.stage.NoSuchStageException; 1.33 +import org.mozilla.gecko.sync.synchronizer.Synchronizer; 1.34 + 1.35 +import android.content.SharedPreferences; 1.36 + 1.37 +/** 1.38 + * Test the on-device side effects of reset operations on a stage. 1.39 + * 1.40 + * See also "TestResetCommands" in the unit test suite. 1.41 + */ 1.42 +public class TestResetting extends AndroidSyncTestCase { 1.43 + private static final String TEST_USERNAME = "johndoe"; 1.44 + private static final String TEST_PASSWORD = "password"; 1.45 + private static final String TEST_SYNC_KEY = "abcdeabcdeabcdeabcdeabcdea"; 1.46 + 1.47 + @Override 1.48 + public void setUp() { 1.49 + assertTrue(WaitHelper.getTestWaiter().isIdle()); 1.50 + } 1.51 + 1.52 + /** 1.53 + * Set up a mock stage that synchronizes two mock repositories. Apply various 1.54 + * reset/sync/wipe permutations and check state. 1.55 + */ 1.56 + public void testResetAndWipeStage() throws Exception { 1.57 + 1.58 + final long startTime = System.currentTimeMillis(); 1.59 + final GlobalSessionCallback callback = createGlobalSessionCallback(); 1.60 + final GlobalSession session = createDefaultGlobalSession(callback); 1.61 + 1.62 + final ExecutableMockServerSyncStage stage = new ExecutableMockServerSyncStage() { 1.63 + @Override 1.64 + public void onSynchronized(Synchronizer synchronizer) { 1.65 + try { 1.66 + assertTrue(startTime <= synchronizer.bundleA.getTimestamp()); 1.67 + assertTrue(startTime <= synchronizer.bundleB.getTimestamp()); 1.68 + 1.69 + // Call up to allow the usual persistence etc. to happen. 1.70 + super.onSynchronized(synchronizer); 1.71 + } catch (Throwable e) { 1.72 + performNotify(e); 1.73 + return; 1.74 + } 1.75 + performNotify(); 1.76 + } 1.77 + }; 1.78 + 1.79 + final boolean bumpTimestamps = true; 1.80 + WBORepository local = new WBORepository(bumpTimestamps); 1.81 + WBORepository remote = new WBORepository(bumpTimestamps); 1.82 + 1.83 + stage.name = "mock"; 1.84 + stage.collection = "mock"; 1.85 + stage.local = local; 1.86 + stage.remote = remote; 1.87 + 1.88 + stage.executeSynchronously(session); 1.89 + 1.90 + // Verify the persisted values. 1.91 + assertConfigTimestampsGreaterThan(stage.leakConfig(), startTime, startTime); 1.92 + 1.93 + // Reset. 1.94 + stage.resetLocal(session); 1.95 + 1.96 + // Verify that they're gone. 1.97 + assertConfigTimestampsEqual(stage.leakConfig(), 0, 0); 1.98 + 1.99 + // Now sync data, ensure that timestamps come back. 1.100 + final long afterReset = System.currentTimeMillis(); 1.101 + final String recordGUID = "abcdefghijkl"; 1.102 + local.wbos.put(recordGUID, new MockRecord(recordGUID, "mock", startTime, false)); 1.103 + 1.104 + // Sync again with data and verify timestamps and data. 1.105 + stage.executeSynchronously(session); 1.106 + 1.107 + assertConfigTimestampsGreaterThan(stage.leakConfig(), afterReset, afterReset); 1.108 + assertEquals(1, remote.wbos.size()); 1.109 + assertEquals(1, local.wbos.size()); 1.110 + 1.111 + Record remoteRecord = remote.wbos.get(recordGUID); 1.112 + assertNotNull(remoteRecord); 1.113 + assertNotNull(local.wbos.get(recordGUID)); 1.114 + assertEquals(recordGUID, remoteRecord.guid); 1.115 + assertTrue(afterReset <= remoteRecord.lastModified); 1.116 + 1.117 + // Reset doesn't clear data. 1.118 + stage.resetLocal(session); 1.119 + assertConfigTimestampsEqual(stage.leakConfig(), 0, 0); 1.120 + assertEquals(1, remote.wbos.size()); 1.121 + assertEquals(1, local.wbos.size()); 1.122 + remoteRecord = remote.wbos.get(recordGUID); 1.123 + assertNotNull(remoteRecord); 1.124 + assertNotNull(local.wbos.get(recordGUID)); 1.125 + 1.126 + // Wipe does. Recover from reset... 1.127 + final long beforeWipe = System.currentTimeMillis(); 1.128 + stage.executeSynchronously(session); 1.129 + assertEquals(1, remote.wbos.size()); 1.130 + assertEquals(1, local.wbos.size()); 1.131 + assertConfigTimestampsGreaterThan(stage.leakConfig(), beforeWipe, beforeWipe); 1.132 + 1.133 + // ... then wipe. 1.134 + stage.wipeLocal(session); 1.135 + assertConfigTimestampsEqual(stage.leakConfig(), 0, 0); 1.136 + assertEquals(1, remote.wbos.size()); // We don't wipe the server. 1.137 + assertEquals(0, local.wbos.size()); // We do wipe local. 1.138 + } 1.139 + 1.140 + /** 1.141 + * A stage that joins two Repositories with no wrapping. 1.142 + */ 1.143 + public class ExecutableMockServerSyncStage extends BaseMockServerSyncStage { 1.144 + /** 1.145 + * Run this stage synchronously. 1.146 + */ 1.147 + public void executeSynchronously(final GlobalSession session) { 1.148 + final BaseMockServerSyncStage self = this; 1.149 + performWait(new Runnable() { 1.150 + @Override 1.151 + public void run() { 1.152 + try { 1.153 + self.execute(session); 1.154 + } catch (NoSuchStageException e) { 1.155 + performNotify(e); 1.156 + } 1.157 + } 1.158 + }); 1.159 + } 1.160 + } 1.161 + 1.162 + private GlobalSession createDefaultGlobalSession(final GlobalSessionCallback callback) throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException { 1.163 + 1.164 + final KeyBundle keyBundle = new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY); 1.165 + final AuthHeaderProvider authHeaderProvider = new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD); 1.166 + final SharedPreferences prefs = new MockSharedPreferences(); 1.167 + final SyncConfiguration config = new SyncConfiguration(TEST_USERNAME, authHeaderProvider, prefs); 1.168 + config.syncKeyBundle = keyBundle; 1.169 + return new GlobalSession(config, callback, getApplicationContext(), null, callback) { 1.170 + @Override 1.171 + public boolean isEngineRemotelyEnabled(String engineName, 1.172 + EngineSettings engineSettings) 1.173 + throws MetaGlobalException { 1.174 + return true; 1.175 + } 1.176 + 1.177 + @Override 1.178 + public void advance() { 1.179 + // So we don't proceed and run other stages. 1.180 + } 1.181 + }; 1.182 + } 1.183 + 1.184 + private static GlobalSessionCallback createGlobalSessionCallback() { 1.185 + return new DefaultGlobalSessionCallback() { 1.186 + 1.187 + @Override 1.188 + public void handleAborted(GlobalSession globalSession, String reason) { 1.189 + performNotify(new Exception("Aborted")); 1.190 + } 1.191 + 1.192 + @Override 1.193 + public void handleError(GlobalSession globalSession, Exception ex) { 1.194 + performNotify(ex); 1.195 + } 1.196 + }; 1.197 + } 1.198 + 1.199 + private static void assertConfigTimestampsGreaterThan(SynchronizerConfiguration config, long local, long remote) { 1.200 + assertTrue(local <= config.localBundle.getTimestamp()); 1.201 + assertTrue(remote <= config.remoteBundle.getTimestamp()); 1.202 + } 1.203 + 1.204 + private static void assertConfigTimestampsEqual(SynchronizerConfiguration config, long local, long remote) { 1.205 + assertEquals(local, config.localBundle.getTimestamp()); 1.206 + assertEquals(remote, config.remoteBundle.getTimestamp()); 1.207 + } 1.208 +}