Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
michael@0 | 1 | /* Any copyright is dedicated to the Public Domain. |
michael@0 | 2 | http://creativecommons.org/publicdomain/zero/1.0/ */ |
michael@0 | 3 | |
michael@0 | 4 | package org.mozilla.gecko.background.sync; |
michael@0 | 5 | |
michael@0 | 6 | import java.util.Map; |
michael@0 | 7 | |
michael@0 | 8 | import org.mozilla.gecko.background.common.GlobalConstants; |
michael@0 | 9 | import org.mozilla.gecko.background.helpers.AndroidSyncTestCase; |
michael@0 | 10 | import org.mozilla.gecko.background.testhelpers.MockSharedPreferences; |
michael@0 | 11 | import org.mozilla.gecko.sync.ExtendedJSONObject; |
michael@0 | 12 | import org.mozilla.gecko.sync.PrefsBackoffHandler; |
michael@0 | 13 | import org.mozilla.gecko.sync.SyncConfiguration; |
michael@0 | 14 | import org.mozilla.gecko.sync.SyncConstants; |
michael@0 | 15 | import org.mozilla.gecko.sync.Utils; |
michael@0 | 16 | import org.mozilla.gecko.sync.config.ConfigurationMigrator; |
michael@0 | 17 | import org.mozilla.gecko.sync.setup.SyncAccounts; |
michael@0 | 18 | import org.mozilla.gecko.sync.setup.SyncAccounts.SyncAccountParameters; |
michael@0 | 19 | |
michael@0 | 20 | import android.accounts.Account; |
michael@0 | 21 | import android.accounts.AccountManager; |
michael@0 | 22 | import android.content.Context; |
michael@0 | 23 | import android.content.SharedPreferences; |
michael@0 | 24 | import android.content.SharedPreferences.Editor; |
michael@0 | 25 | |
michael@0 | 26 | public class TestConfigurationMigrator extends AndroidSyncTestCase { |
michael@0 | 27 | /** |
michael@0 | 28 | * A migrator that makes public certain protected static functions for testing. |
michael@0 | 29 | */ |
michael@0 | 30 | protected static class PublicMigrator extends ConfigurationMigrator { |
michael@0 | 31 | public static int upgradeGlobals0to1(final SharedPreferences from, final SharedPreferences to) throws Exception { |
michael@0 | 32 | return ConfigurationMigrator.upgradeGlobals0to1(from, to); |
michael@0 | 33 | } |
michael@0 | 34 | |
michael@0 | 35 | public static int downgradeGlobals1to0(final SharedPreferences from, final SharedPreferences to) throws Exception { |
michael@0 | 36 | return ConfigurationMigrator.downgradeGlobals1to0(from, to); |
michael@0 | 37 | } |
michael@0 | 38 | |
michael@0 | 39 | public static int upgradeShared0to1(final SharedPreferences from, final SharedPreferences to) { |
michael@0 | 40 | return ConfigurationMigrator.upgradeShared0to1(from, to); |
michael@0 | 41 | } |
michael@0 | 42 | |
michael@0 | 43 | public static int downgradeShared1to0(final SharedPreferences from, final SharedPreferences to) { |
michael@0 | 44 | return ConfigurationMigrator.downgradeShared1to0(from, to); |
michael@0 | 45 | } |
michael@0 | 46 | |
michael@0 | 47 | public static int upgradeAndroidAccount0to1(final AccountManager accountManager, final Account account, final SharedPreferences to) throws Exception { |
michael@0 | 48 | return ConfigurationMigrator.upgradeAndroidAccount0to1(accountManager, account, to); |
michael@0 | 49 | } |
michael@0 | 50 | |
michael@0 | 51 | public static int downgradeAndroidAccount1to0(final SharedPreferences from, final AccountManager accountManager, final Account account) throws Exception { |
michael@0 | 52 | return ConfigurationMigrator.downgradeAndroidAccount1to0(from, accountManager, account); |
michael@0 | 53 | } |
michael@0 | 54 | }; |
michael@0 | 55 | |
michael@0 | 56 | public static final String TEST_USERNAME = "test@mozilla.com"; |
michael@0 | 57 | public static final String TEST_SYNCKEY = "testSyncKey"; |
michael@0 | 58 | public static final String TEST_PASSWORD = "testPassword"; |
michael@0 | 59 | public static final String TEST_SERVERURL = null; |
michael@0 | 60 | public static final String TEST_PROFILE = "default"; |
michael@0 | 61 | public static final String TEST_PRODUCT = GlobalConstants.BROWSER_INTENT_PACKAGE; |
michael@0 | 62 | |
michael@0 | 63 | public static final String TEST_GUID = "testGuid"; |
michael@0 | 64 | public static final String TEST_CLIENT_NAME = "test's Nightly on test"; |
michael@0 | 65 | public static final long TEST_NUM_CLIENTS = 2; |
michael@0 | 66 | |
michael@0 | 67 | protected static void putJSON(final Editor editor, final String name, final String JSON) throws Exception { |
michael@0 | 68 | editor.putString(name, ExtendedJSONObject.parseJSONObject(JSON).toJSONString()); |
michael@0 | 69 | } |
michael@0 | 70 | |
michael@0 | 71 | /** |
michael@0 | 72 | * Write a complete set of unversioned account prefs suitable for testing forward migration. |
michael@0 | 73 | * @throws Exception |
michael@0 | 74 | */ |
michael@0 | 75 | public void populateAccountSharedPrefs(final SharedPreferences to) throws Exception { |
michael@0 | 76 | final Editor editor = to.edit(); |
michael@0 | 77 | |
michael@0 | 78 | putJSON(editor, "forms.remote", "{\"timestamp\":1340402010180}"); |
michael@0 | 79 | putJSON(editor, "forms.local", "{\"timestamp\":1340402018565}"); |
michael@0 | 80 | editor.putString("forms.syncID", "JKAkk-wUEUpX"); |
michael@0 | 81 | |
michael@0 | 82 | putJSON(editor, "tabs.remote", "{\"timestamp\":1340401964300}"); |
michael@0 | 83 | putJSON(editor, "tabs.local", "{\"timestamp\":1340401970533}"); |
michael@0 | 84 | editor.putString("tabs.syncID", "604bXkw7dnUq"); |
michael@0 | 85 | |
michael@0 | 86 | putJSON(editor, "passwords.remote", "{\"timestamp\":1340401965150}"); |
michael@0 | 87 | putJSON(editor, "passwords.local", "{\"timestamp\":1340402005243}"); |
michael@0 | 88 | editor.putString("passwords.syncID", "VkTH0QiVj6dD"); |
michael@0 | 89 | |
michael@0 | 90 | putJSON(editor, "history.remote", "{\"timestamp\":1340402003640}"); |
michael@0 | 91 | putJSON(editor, "history.local", "{\"timestamp\":1340402015381}"); |
michael@0 | 92 | editor.putString("history.syncID", "fs1241n-JyWh"); |
michael@0 | 93 | |
michael@0 | 94 | putJSON(editor, "bookmarks.remote", "{\"timestamp\":1340402003370}"); |
michael@0 | 95 | putJSON(editor, "bookmarks.local", "{\"timestamp\":1340402008397}"); |
michael@0 | 96 | editor.putString("bookmarks.syncID", "P8gG8ERuJ4H1"); |
michael@0 | 97 | |
michael@0 | 98 | editor.putLong("metaGlobalLastModified", 1340401961960L); |
michael@0 | 99 | putJSON(editor, "metaGlobalServerResponseBody", "{\"ttl\":31536000,\"id\":\"global\",\"payload\":\"{\\\"storageVersion\\\":5,\\\"syncID\\\":\\\"Z2RopSDg-0bE\\\",\\\"engines\\\":{\\\"history\\\":{\\\"syncID\\\":\\\"fs1241n-JyWh\\\",\\\"version\\\":1},\\\"bookmarks\\\":{\\\"syncID\\\":\\\"P8gG8ERuJ4H1\\\",\\\"version\\\":2},\\\"passwords\\\":{\\\"syncID\\\":\\\"VkTH0QiVj6dD\\\",\\\"version\\\":1},\\\"prefs\\\":{\\\"syncID\\\":\\\"4lESgyoYPXYI\\\",\\\"version\\\":2},\\\"addons\\\":{\\\"syncID\\\":\\\"yCkJKkH-okoS\\\",\\\"version\\\":1},\\\"forms\\\":{\\\"syncID\\\":\\\"JKAkk-wUEUpX\\\",\\\"version\\\":1},\\\"clients\\\":{\\\"syncID\\\":\\\"KfANCdkZNOFJ\\\",\\\"version\\\":1},\\\"tabs\\\":{\\\"syncID\\\":\\\"604bXkw7dnUq\\\",\\\"version\\\":1}}}\"}"); |
michael@0 | 100 | |
michael@0 | 101 | editor.putLong("crypto5KeysLastModified", 1340401962760L); |
michael@0 | 102 | putJSON(editor, "crypto5KeysServerResponseBody", "{\"ttl\":31536000,\"id\":\"keys\",\"payload\":\"{\\\"ciphertext\\\":\\\"+ZH6AaMhnKOWS7OzpdMfT5X2C7AYgax5JRd2HY4BHAFNPDv8\\\\\\/TwQIJgFDuNjASo0WEujjdkFot39qeQ24RLAz4D11rG\\\\\\/FZwo8FEUB9aSfec1N6sao6KzWkSamdqiJSRjpsUKexp2it1HvwqRDEBH\\\\\\/lgue11axv51u1MAV3ZfX2fdzVIiGTqF1YJAvENZtol3pyEh2HI4FZlv+oLW250nV4w1vAfDNGLVbbjXbdR+kec=\\\",\\\"IV\\\":\\\"bHqF\\\\\\/4PshKt2GQ\\\\\\/njGj2Jw==\\\",\\\"hmac\\\":\\\"f97c20d5c0a141f62a1571a108de1bad4b854b29c8d4b2b0d36da73421e4becc\\\"}\"}"); |
michael@0 | 103 | |
michael@0 | 104 | editor.putString("syncID", "Z2RopSDg-0bE"); |
michael@0 | 105 | editor.putString("clusterURL", "https://scl2-sync3.services.mozilla.com/"); |
michael@0 | 106 | putJSON(editor, "enabledEngineNames", "{\"history\":0,\"bookmarks\":0,\"passwords\":0,\"prefs\":0,\"addons\":0,\"forms\":0,\"clients\":0,\"tabs\":0}"); |
michael@0 | 107 | |
michael@0 | 108 | editor.putLong("serverClientsTimestamp", 1340401963950L); |
michael@0 | 109 | editor.putLong("serverClientRecordTimestamp", 1340401963950L); |
michael@0 | 110 | |
michael@0 | 111 | editor.commit(); |
michael@0 | 112 | } |
michael@0 | 113 | |
michael@0 | 114 | /** |
michael@0 | 115 | * Write a complete set of unversioned global prefs suitable for testing forward migration. |
michael@0 | 116 | * @throws Exception |
michael@0 | 117 | */ |
michael@0 | 118 | public void populateGlobalSharedPrefs(final SharedPreferences to) throws Exception { |
michael@0 | 119 | final Editor editor = to.edit(); |
michael@0 | 120 | |
michael@0 | 121 | editor.putLong("earliestnextsync", 1340402318649L); |
michael@0 | 122 | editor.putBoolean("clusterurlisstale", false); |
michael@0 | 123 | |
michael@0 | 124 | editor.commit(); |
michael@0 | 125 | } |
michael@0 | 126 | |
michael@0 | 127 | /** |
michael@0 | 128 | * Write a complete set of unversioned Account data suitable for testing forward migration. |
michael@0 | 129 | * @throws Exception |
michael@0 | 130 | */ |
michael@0 | 131 | public void populateAccountData(final AccountManager accountManager, final Account account) throws Exception { |
michael@0 | 132 | accountManager.setUserData(account, "account.guid", TEST_GUID); |
michael@0 | 133 | accountManager.setUserData(account, "account.clientName", TEST_CLIENT_NAME); |
michael@0 | 134 | accountManager.setUserData(account, "account.numClients", Long.valueOf(TEST_NUM_CLIENTS).toString()); |
michael@0 | 135 | } |
michael@0 | 136 | |
michael@0 | 137 | public void testMigrateGlobals0and1() throws Exception { |
michael@0 | 138 | final SharedPreferences v0a = new MockSharedPreferences(); |
michael@0 | 139 | final SharedPreferences v1a = new MockSharedPreferences(); |
michael@0 | 140 | final SharedPreferences v0b = new MockSharedPreferences(); |
michael@0 | 141 | final SharedPreferences v1b = new MockSharedPreferences(); |
michael@0 | 142 | |
michael@0 | 143 | populateGlobalSharedPrefs(v0a); |
michael@0 | 144 | |
michael@0 | 145 | final int NUM_GLOBALS = 2; |
michael@0 | 146 | assertEquals(NUM_GLOBALS, v0a.getAll().size()); |
michael@0 | 147 | assertEquals(NUM_GLOBALS, PublicMigrator.upgradeGlobals0to1(v0a, v1a)); |
michael@0 | 148 | assertEquals(NUM_GLOBALS, PublicMigrator.downgradeGlobals1to0(v1a, v0b)); |
michael@0 | 149 | assertEquals(NUM_GLOBALS, PublicMigrator.upgradeGlobals0to1(v0b, v1b)); |
michael@0 | 150 | assertEquals(v0a.getAll(), v0b.getAll()); |
michael@0 | 151 | assertEquals(v1a.getAll(), v1b.getAll()); |
michael@0 | 152 | } |
michael@0 | 153 | |
michael@0 | 154 | public void testMigrateShared0and1() throws Exception { |
michael@0 | 155 | final SharedPreferences v0a = new MockSharedPreferences(); |
michael@0 | 156 | final SharedPreferences v1a = new MockSharedPreferences(); |
michael@0 | 157 | final SharedPreferences v0b = new MockSharedPreferences(); |
michael@0 | 158 | final SharedPreferences v1b = new MockSharedPreferences(); |
michael@0 | 159 | |
michael@0 | 160 | populateAccountSharedPrefs(v0a); |
michael@0 | 161 | |
michael@0 | 162 | final int NUM_GLOBALS = 24; |
michael@0 | 163 | assertEquals(NUM_GLOBALS, v0a.getAll().size()); |
michael@0 | 164 | assertEquals(NUM_GLOBALS, PublicMigrator.upgradeShared0to1(v0a, v1a)); |
michael@0 | 165 | assertEquals(NUM_GLOBALS, PublicMigrator.downgradeShared1to0(v1a, v0b)); |
michael@0 | 166 | assertEquals(NUM_GLOBALS, PublicMigrator.upgradeShared0to1(v0b, v1b)); |
michael@0 | 167 | assertEquals(v0a.getAll(), v0b.getAll()); |
michael@0 | 168 | assertEquals(v1a.getAll(), v1b.getAll()); |
michael@0 | 169 | } |
michael@0 | 170 | |
michael@0 | 171 | public void testMigrateAccount0and1() throws Exception { |
michael@0 | 172 | final Context context = getApplicationContext(); |
michael@0 | 173 | final AccountManager accountManager = AccountManager.get(context); |
michael@0 | 174 | final SyncAccountParameters syncAccount = new SyncAccountParameters(context, null, |
michael@0 | 175 | TEST_USERNAME, TEST_SYNCKEY, TEST_PASSWORD, null); |
michael@0 | 176 | |
michael@0 | 177 | Account account = null; |
michael@0 | 178 | try { |
michael@0 | 179 | account = SyncAccounts.createSyncAccount(syncAccount, false); |
michael@0 | 180 | populateAccountData(accountManager, account); |
michael@0 | 181 | |
michael@0 | 182 | final int NUM_ACCOUNTS = 3; |
michael@0 | 183 | final SharedPreferences a = new MockSharedPreferences(); |
michael@0 | 184 | final SharedPreferences b = new MockSharedPreferences(); |
michael@0 | 185 | |
michael@0 | 186 | assertEquals(NUM_ACCOUNTS, PublicMigrator.upgradeAndroidAccount0to1(accountManager, account, a)); |
michael@0 | 187 | assertEquals(NUM_ACCOUNTS, a.getAll().size()); |
michael@0 | 188 | assertEquals(NUM_ACCOUNTS, PublicMigrator.downgradeAndroidAccount1to0(a, accountManager, account)); |
michael@0 | 189 | |
michael@0 | 190 | TestSyncAccounts.deleteAccount(this, accountManager, account); |
michael@0 | 191 | account = SyncAccounts.createSyncAccount(syncAccount, false); |
michael@0 | 192 | |
michael@0 | 193 | assertEquals(NUM_ACCOUNTS, PublicMigrator.downgradeAndroidAccount1to0(a, accountManager, account)); |
michael@0 | 194 | assertEquals(NUM_ACCOUNTS, PublicMigrator.upgradeAndroidAccount0to1(accountManager, account, b)); |
michael@0 | 195 | assertEquals(a.getAll(), b.getAll()); |
michael@0 | 196 | } finally { |
michael@0 | 197 | if (account != null) { |
michael@0 | 198 | TestSyncAccounts.deleteAccount(this, accountManager, account); |
michael@0 | 199 | } |
michael@0 | 200 | } |
michael@0 | 201 | } |
michael@0 | 202 | |
michael@0 | 203 | public void testMigrate0to1() throws Exception { |
michael@0 | 204 | final Context context = getApplicationContext(); |
michael@0 | 205 | |
michael@0 | 206 | final String ACCOUNT_SHARED_PREFS_NAME = "sync.prefs.3qyu5zoqpuu4zhdiv5l2qthsiter3vop"; |
michael@0 | 207 | final String GLOBAL_SHARED_PREFS_NAME = "sync.prefs.global"; |
michael@0 | 208 | |
michael@0 | 209 | final String path = Utils.getPrefsPath(TEST_PRODUCT, TEST_USERNAME, TEST_SERVERURL, TEST_PROFILE, 0); |
michael@0 | 210 | assertEquals(ACCOUNT_SHARED_PREFS_NAME, path); |
michael@0 | 211 | final SharedPreferences accountPrefs = context.getSharedPreferences(ACCOUNT_SHARED_PREFS_NAME, Utils.SHARED_PREFERENCES_MODE); |
michael@0 | 212 | final SharedPreferences globalPrefs = context.getSharedPreferences(GLOBAL_SHARED_PREFS_NAME, Utils.SHARED_PREFERENCES_MODE); |
michael@0 | 213 | |
michael@0 | 214 | accountPrefs.edit().clear().commit(); |
michael@0 | 215 | globalPrefs.edit().clear().commit(); |
michael@0 | 216 | // Clear prefs we're about to write into. |
michael@0 | 217 | final SharedPreferences existingPrefs = Utils.getSharedPreferences(context, TEST_PRODUCT, TEST_USERNAME, TEST_SERVERURL, TEST_PROFILE, 1); |
michael@0 | 218 | existingPrefs.edit().clear().commit(); |
michael@0 | 219 | |
michael@0 | 220 | final AccountManager accountManager = AccountManager.get(context); |
michael@0 | 221 | final SyncAccountParameters syncAccount = new SyncAccountParameters(context, null, |
michael@0 | 222 | TEST_USERNAME, TEST_SYNCKEY, TEST_PASSWORD, null); |
michael@0 | 223 | |
michael@0 | 224 | Account account = null; |
michael@0 | 225 | try { |
michael@0 | 226 | account = SyncAccounts.createSyncAccount(syncAccount, false); // Wipes prefs. |
michael@0 | 227 | |
michael@0 | 228 | populateAccountSharedPrefs(accountPrefs); |
michael@0 | 229 | populateGlobalSharedPrefs(globalPrefs); |
michael@0 | 230 | populateAccountData(accountManager, account); |
michael@0 | 231 | |
michael@0 | 232 | ConfigurationMigrator.upgrade0to1(context, accountManager, account, TEST_PRODUCT, TEST_USERNAME, TEST_SERVERURL, TEST_PROFILE); |
michael@0 | 233 | } finally { |
michael@0 | 234 | if (account != null) { |
michael@0 | 235 | TestSyncAccounts.deleteAccount(this, accountManager, account); |
michael@0 | 236 | } |
michael@0 | 237 | } |
michael@0 | 238 | |
michael@0 | 239 | Map<String, ?> origAccountPrefs = accountPrefs.getAll(); |
michael@0 | 240 | Map<String, ?> origGlobalPrefs = globalPrefs.getAll(); |
michael@0 | 241 | assertFalse(origAccountPrefs.isEmpty()); |
michael@0 | 242 | assertFalse(origGlobalPrefs.isEmpty()); |
michael@0 | 243 | |
michael@0 | 244 | final SharedPreferences newPrefs = Utils.getSharedPreferences(context, TEST_PRODUCT, TEST_USERNAME, TEST_SERVERURL, TEST_PROFILE, 1); |
michael@0 | 245 | |
michael@0 | 246 | // Some global stuff. |
michael@0 | 247 | assertEquals(false, newPrefs.getBoolean(SyncConfiguration.PREF_CLUSTER_URL_IS_STALE, true)); |
michael@0 | 248 | assertEquals(1340402318649L, newPrefs.getLong(PrefsBackoffHandler.PREF_EARLIEST_NEXT + SyncConstants.BACKOFF_PREF_SUFFIX_11, 111)); |
michael@0 | 249 | // Some per-Sync account stuff. |
michael@0 | 250 | assertEquals("{\"timestamp\":1340402003370}", newPrefs.getString("bookmarks.remote", null)); |
michael@0 | 251 | assertEquals("{\"timestamp\":1340402008397}", newPrefs.getString("bookmarks.local", null)); |
michael@0 | 252 | assertEquals("P8gG8ERuJ4H1", newPrefs.getString("bookmarks.syncID", null)); |
michael@0 | 253 | assertEquals(1340401961960L, newPrefs.getLong("metaGlobalLastModified", 0)); |
michael@0 | 254 | // Some per-Android account stuff. |
michael@0 | 255 | assertEquals(TEST_GUID, newPrefs.getString(SyncConfiguration.PREF_ACCOUNT_GUID, null)); |
michael@0 | 256 | assertEquals(TEST_CLIENT_NAME, newPrefs.getString(SyncConfiguration.PREF_CLIENT_NAME, null)); |
michael@0 | 257 | assertEquals(TEST_NUM_CLIENTS, newPrefs.getLong(SyncConfiguration.PREF_NUM_CLIENTS, -1L)); |
michael@0 | 258 | |
michael@0 | 259 | // Now try to downgrade. |
michael@0 | 260 | accountPrefs.edit().clear().commit(); |
michael@0 | 261 | globalPrefs.edit().clear().commit(); |
michael@0 | 262 | |
michael@0 | 263 | account = null; |
michael@0 | 264 | try { |
michael@0 | 265 | account = SyncAccounts.createSyncAccount(syncAccount, false); |
michael@0 | 266 | |
michael@0 | 267 | ConfigurationMigrator.downgrade1to0(context, accountManager, account, TEST_PRODUCT, TEST_USERNAME, TEST_SERVERURL, TEST_PROFILE); |
michael@0 | 268 | |
michael@0 | 269 | final String V0_PREF_ACCOUNT_GUID = "account.guid"; |
michael@0 | 270 | final String V0_PREF_CLIENT_NAME = "account.clientName"; |
michael@0 | 271 | final String V0_PREF_NUM_CLIENTS = "account.numClients"; |
michael@0 | 272 | |
michael@0 | 273 | assertEquals(TEST_GUID, accountManager.getUserData(account, V0_PREF_ACCOUNT_GUID)); |
michael@0 | 274 | assertEquals(TEST_CLIENT_NAME, accountManager.getUserData(account, V0_PREF_CLIENT_NAME)); |
michael@0 | 275 | assertEquals(Long.valueOf(TEST_NUM_CLIENTS).toString(), accountManager.getUserData(account, V0_PREF_NUM_CLIENTS)); |
michael@0 | 276 | } finally { |
michael@0 | 277 | if (account != null) { |
michael@0 | 278 | TestSyncAccounts.deleteAccount(this, accountManager, account); |
michael@0 | 279 | } |
michael@0 | 280 | } |
michael@0 | 281 | |
michael@0 | 282 | // Check re-constituted prefs against old prefs. |
michael@0 | 283 | assertEquals(origAccountPrefs, accountPrefs.getAll()); |
michael@0 | 284 | assertEquals(origGlobalPrefs, globalPrefs.getAll()); |
michael@0 | 285 | } |
michael@0 | 286 | } |