Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
michael@0 | 1 | package org.mozilla.gecko.tests; |
michael@0 | 2 | |
michael@0 | 3 | import java.io.File; |
michael@0 | 4 | import java.io.FileOutputStream; |
michael@0 | 5 | import java.io.InputStream; |
michael@0 | 6 | import java.io.OutputStream; |
michael@0 | 7 | |
michael@0 | 8 | import org.json.JSONArray; |
michael@0 | 9 | import org.json.JSONException; |
michael@0 | 10 | import org.json.JSONObject; |
michael@0 | 11 | import org.mozilla.gecko.Actions; |
michael@0 | 12 | import org.mozilla.gecko.Distribution; |
michael@0 | 13 | import org.mozilla.gecko.db.BrowserContract; |
michael@0 | 14 | import org.mozilla.gecko.util.ThreadUtils; |
michael@0 | 15 | |
michael@0 | 16 | import android.app.Activity; |
michael@0 | 17 | import android.content.SharedPreferences; |
michael@0 | 18 | |
michael@0 | 19 | /** |
michael@0 | 20 | * Tests distribution customization. |
michael@0 | 21 | * mock-package.zip should contain the following directory structure: |
michael@0 | 22 | * |
michael@0 | 23 | * distribution/ |
michael@0 | 24 | * preferences.json |
michael@0 | 25 | * bookmarks.json |
michael@0 | 26 | * searchplugins/ |
michael@0 | 27 | * common/ |
michael@0 | 28 | * engine.xml |
michael@0 | 29 | */ |
michael@0 | 30 | public class testDistribution extends ContentProviderTest { |
michael@0 | 31 | private static final String MOCK_PACKAGE = "mock-package.zip"; |
michael@0 | 32 | private static final int PREF_REQUEST_ID = 0x7357; |
michael@0 | 33 | |
michael@0 | 34 | private Activity mActivity; |
michael@0 | 35 | |
michael@0 | 36 | /** |
michael@0 | 37 | * This is a hack. |
michael@0 | 38 | * |
michael@0 | 39 | * Startup results in us writing prefs -- we fetch the Distribution, which |
michael@0 | 40 | * caches its state. Our tests try to wipe those prefs, but apparently |
michael@0 | 41 | * sometimes race with startup, which leads to us not getting one of our |
michael@0 | 42 | * expected messages. The test fails. |
michael@0 | 43 | * |
michael@0 | 44 | * This hack waits for any existing background tasks -- such as the one that |
michael@0 | 45 | * writes prefs -- to finish before we begin the test. |
michael@0 | 46 | */ |
michael@0 | 47 | private void waitForBackgroundHappiness() { |
michael@0 | 48 | final Object signal = new Object(); |
michael@0 | 49 | final Runnable done = new Runnable() { |
michael@0 | 50 | @Override |
michael@0 | 51 | public void run() { |
michael@0 | 52 | synchronized (signal) { |
michael@0 | 53 | signal.notify(); |
michael@0 | 54 | } |
michael@0 | 55 | } |
michael@0 | 56 | }; |
michael@0 | 57 | synchronized (signal) { |
michael@0 | 58 | ThreadUtils.postToBackgroundThread(done); |
michael@0 | 59 | try { |
michael@0 | 60 | signal.wait(); |
michael@0 | 61 | } catch (InterruptedException e) { |
michael@0 | 62 | mAsserter.ok(false, "InterruptedException waiting on background thread.", e.toString()); |
michael@0 | 63 | } |
michael@0 | 64 | } |
michael@0 | 65 | mAsserter.dumpLog("Background task completed. Proceeding."); |
michael@0 | 66 | } |
michael@0 | 67 | |
michael@0 | 68 | public void testDistribution() { |
michael@0 | 69 | mActivity = getActivity(); |
michael@0 | 70 | |
michael@0 | 71 | String mockPackagePath = getMockPackagePath(); |
michael@0 | 72 | |
michael@0 | 73 | // Wait for any startup-related background distribution shenanigans to |
michael@0 | 74 | // finish. This reduces the chance of us racing with startup pref writes. |
michael@0 | 75 | waitForBackgroundHappiness(); |
michael@0 | 76 | |
michael@0 | 77 | // Pre-clear distribution pref, run basic preferences and en-US localized preferences Tests |
michael@0 | 78 | clearDistributionPref(); |
michael@0 | 79 | setTestLocale("en-US"); |
michael@0 | 80 | initDistribution(mockPackagePath); |
michael@0 | 81 | checkPreferences(); |
michael@0 | 82 | checkLocalizedPreferences("en-US"); |
michael@0 | 83 | checkSearchPlugin(); |
michael@0 | 84 | |
michael@0 | 85 | // Pre-clear distribution pref, and run es-MX localized preferences Test |
michael@0 | 86 | clearDistributionPref(); |
michael@0 | 87 | setTestLocale("es-MX"); |
michael@0 | 88 | initDistribution(mockPackagePath); |
michael@0 | 89 | checkLocalizedPreferences("es-MX"); |
michael@0 | 90 | } |
michael@0 | 91 | |
michael@0 | 92 | // Initialize the distribution from the mock package. |
michael@0 | 93 | private void initDistribution(String aPackagePath) { |
michael@0 | 94 | // Call Distribution.init with the mock package. |
michael@0 | 95 | Actions.EventExpecter distributionSetExpecter = mActions.expectGeckoEvent("Distribution:Set:OK"); |
michael@0 | 96 | Distribution.init(mActivity, aPackagePath, "prefs-" + System.currentTimeMillis()); |
michael@0 | 97 | distributionSetExpecter.blockForEvent(); |
michael@0 | 98 | distributionSetExpecter.unregisterListener(); |
michael@0 | 99 | } |
michael@0 | 100 | |
michael@0 | 101 | // Test distribution and preferences values stored in preferences.json |
michael@0 | 102 | private void checkPreferences() { |
michael@0 | 103 | String prefID = "distribution.id"; |
michael@0 | 104 | String prefAbout = "distribution.about"; |
michael@0 | 105 | String prefVersion = "distribution.version"; |
michael@0 | 106 | String prefTestBoolean = "distribution.test.boolean"; |
michael@0 | 107 | String prefTestString = "distribution.test.string"; |
michael@0 | 108 | String prefTestInt = "distribution.test.int"; |
michael@0 | 109 | |
michael@0 | 110 | try { |
michael@0 | 111 | final String[] prefNames = { prefID, |
michael@0 | 112 | prefAbout, |
michael@0 | 113 | prefVersion, |
michael@0 | 114 | prefTestBoolean, |
michael@0 | 115 | prefTestString, |
michael@0 | 116 | prefTestInt }; |
michael@0 | 117 | |
michael@0 | 118 | Actions.RepeatedEventExpecter eventExpecter = mActions.expectGeckoEvent("Preferences:Data"); |
michael@0 | 119 | mActions.sendPreferencesGetEvent(PREF_REQUEST_ID, prefNames); |
michael@0 | 120 | |
michael@0 | 121 | JSONObject data = null; |
michael@0 | 122 | int requestId = -1; |
michael@0 | 123 | |
michael@0 | 124 | // Wait until we get the correct "Preferences:Data" event |
michael@0 | 125 | while (requestId != PREF_REQUEST_ID) { |
michael@0 | 126 | data = new JSONObject(eventExpecter.blockForEventData()); |
michael@0 | 127 | requestId = data.getInt("requestId"); |
michael@0 | 128 | } |
michael@0 | 129 | eventExpecter.unregisterListener(); |
michael@0 | 130 | |
michael@0 | 131 | JSONArray preferences = data.getJSONArray("preferences"); |
michael@0 | 132 | for (int i = 0; i < preferences.length(); i++) { |
michael@0 | 133 | JSONObject pref = (JSONObject) preferences.get(i); |
michael@0 | 134 | String name = pref.getString("name"); |
michael@0 | 135 | |
michael@0 | 136 | if (name.equals(prefID)) { |
michael@0 | 137 | mAsserter.is(pref.getString("value"), "test-partner", "check " + prefID); |
michael@0 | 138 | } else if (name.equals(prefAbout)) { |
michael@0 | 139 | mAsserter.is(pref.getString("value"), "Test Partner", "check " + prefAbout); |
michael@0 | 140 | } else if (name.equals(prefVersion)) { |
michael@0 | 141 | mAsserter.is(pref.getInt("value"), 1, "check " + prefVersion); |
michael@0 | 142 | } else if (name.equals(prefTestBoolean)) { |
michael@0 | 143 | mAsserter.is(pref.getBoolean("value"), true, "check " + prefTestBoolean); |
michael@0 | 144 | } else if (name.equals(prefTestString)) { |
michael@0 | 145 | mAsserter.is(pref.getString("value"), "test", "check " + prefTestString); |
michael@0 | 146 | } else if (name.equals(prefTestInt)) { |
michael@0 | 147 | mAsserter.is(pref.getInt("value"), 5, "check " + prefTestInt); |
michael@0 | 148 | } |
michael@0 | 149 | } |
michael@0 | 150 | |
michael@0 | 151 | } catch (JSONException e) { |
michael@0 | 152 | mAsserter.ok(false, "exception getting preferences", e.toString()); |
michael@0 | 153 | } |
michael@0 | 154 | } |
michael@0 | 155 | |
michael@0 | 156 | private void checkSearchPlugin() { |
michael@0 | 157 | Actions.RepeatedEventExpecter eventExpecter = mActions.expectGeckoEvent("SearchEngines:Data"); |
michael@0 | 158 | mActions.sendGeckoEvent("SearchEngines:GetVisible", null); |
michael@0 | 159 | |
michael@0 | 160 | try { |
michael@0 | 161 | JSONObject data = new JSONObject(eventExpecter.blockForEventData()); |
michael@0 | 162 | eventExpecter.unregisterListener(); |
michael@0 | 163 | JSONArray searchEngines = data.getJSONArray("searchEngines"); |
michael@0 | 164 | boolean foundEngine = false; |
michael@0 | 165 | for (int i = 0; i < searchEngines.length(); i++) { |
michael@0 | 166 | JSONObject engine = (JSONObject) searchEngines.get(i); |
michael@0 | 167 | String name = engine.getString("name"); |
michael@0 | 168 | if (name.equals("Test search engine")) { |
michael@0 | 169 | foundEngine = true; |
michael@0 | 170 | break; |
michael@0 | 171 | } |
michael@0 | 172 | } |
michael@0 | 173 | mAsserter.ok(foundEngine, "check search plugin", "found test search plugin"); |
michael@0 | 174 | } catch (JSONException e) { |
michael@0 | 175 | mAsserter.ok(false, "exception getting search plugins", e.toString()); |
michael@0 | 176 | } |
michael@0 | 177 | } |
michael@0 | 178 | |
michael@0 | 179 | // Sets the distribution locale preference for the test |
michael@0 | 180 | private void setTestLocale(String aLocale) { |
michael@0 | 181 | String prefUseragentLocale = "general.useragent.locale"; |
michael@0 | 182 | |
michael@0 | 183 | JSONObject jsonPref = new JSONObject(); |
michael@0 | 184 | try { |
michael@0 | 185 | // Request the pref change to the locale. |
michael@0 | 186 | jsonPref.put("name", prefUseragentLocale); |
michael@0 | 187 | jsonPref.put("type", "string"); |
michael@0 | 188 | jsonPref.put("value", aLocale); |
michael@0 | 189 | mActions.sendGeckoEvent("Preferences:Set", jsonPref.toString()); |
michael@0 | 190 | |
michael@0 | 191 | // Wait for confirmation of the pref change. |
michael@0 | 192 | final String[] prefNames = { prefUseragentLocale }; |
michael@0 | 193 | |
michael@0 | 194 | Actions.RepeatedEventExpecter eventExpecter = mActions.expectGeckoEvent("Preferences:Data"); |
michael@0 | 195 | mActions.sendPreferencesGetEvent(PREF_REQUEST_ID, prefNames); |
michael@0 | 196 | |
michael@0 | 197 | JSONObject data = null; |
michael@0 | 198 | int requestId = -1; |
michael@0 | 199 | |
michael@0 | 200 | // Wait until we get the correct "Preferences:Data" event |
michael@0 | 201 | while (requestId != PREF_REQUEST_ID) { |
michael@0 | 202 | data = new JSONObject(eventExpecter.blockForEventData()); |
michael@0 | 203 | requestId = data.getInt("requestId"); |
michael@0 | 204 | } |
michael@0 | 205 | eventExpecter.unregisterListener(); |
michael@0 | 206 | |
michael@0 | 207 | } catch (Exception e) { |
michael@0 | 208 | mAsserter.ok(false, "exception setting test locale", e.toString()); |
michael@0 | 209 | } |
michael@0 | 210 | } |
michael@0 | 211 | |
michael@0 | 212 | // Test localized distribution and preferences values stored in preferences.json |
michael@0 | 213 | private void checkLocalizedPreferences(String aLocale) { |
michael@0 | 214 | String prefAbout = "distribution.about"; |
michael@0 | 215 | String prefLocalizeable = "distribution.test.localizeable"; |
michael@0 | 216 | String prefLocalizeableOverride = "distribution.test.localizeable-override"; |
michael@0 | 217 | |
michael@0 | 218 | try { |
michael@0 | 219 | final String[] prefNames = { prefAbout, prefLocalizeable, prefLocalizeableOverride }; |
michael@0 | 220 | |
michael@0 | 221 | Actions.RepeatedEventExpecter eventExpecter = mActions.expectGeckoEvent("Preferences:Data"); |
michael@0 | 222 | mActions.sendPreferencesGetEvent(PREF_REQUEST_ID, prefNames); |
michael@0 | 223 | |
michael@0 | 224 | JSONObject data = null; |
michael@0 | 225 | int requestId = -1; |
michael@0 | 226 | |
michael@0 | 227 | // Wait until we get the correct "Preferences:Data" event |
michael@0 | 228 | while (requestId != PREF_REQUEST_ID) { |
michael@0 | 229 | data = new JSONObject(eventExpecter.blockForEventData()); |
michael@0 | 230 | requestId = data.getInt("requestId"); |
michael@0 | 231 | } |
michael@0 | 232 | eventExpecter.unregisterListener(); |
michael@0 | 233 | |
michael@0 | 234 | JSONArray preferences = data.getJSONArray("preferences"); |
michael@0 | 235 | for (int i = 0; i < preferences.length(); i++) { |
michael@0 | 236 | JSONObject pref = (JSONObject) preferences.get(i); |
michael@0 | 237 | String name = pref.getString("name"); |
michael@0 | 238 | |
michael@0 | 239 | if (name.equals(prefAbout)) { |
michael@0 | 240 | if (aLocale.equals("en-US")) { |
michael@0 | 241 | mAsserter.is(pref.getString("value"), "Test Partner", "check " + prefAbout); |
michael@0 | 242 | } else if (aLocale.equals("es-MX")) { |
michael@0 | 243 | mAsserter.is(pref.getString("value"), "Afiliado de Prueba", "check " + prefAbout); |
michael@0 | 244 | } |
michael@0 | 245 | } else if (name.equals(prefLocalizeable)) { |
michael@0 | 246 | if (aLocale.equals("en-US")) { |
michael@0 | 247 | mAsserter.is(pref.getString("value"), "http://test.org/en-US/en-US/", "check " + prefLocalizeable); |
michael@0 | 248 | } else if (aLocale.equals("es-MX")) { |
michael@0 | 249 | mAsserter.is(pref.getString("value"), "http://test.org/es-MX/es-MX/", "check " + prefLocalizeable); |
michael@0 | 250 | } |
michael@0 | 251 | } else if (name.equals(prefLocalizeableOverride)) { |
michael@0 | 252 | if (aLocale.equals("en-US")) { |
michael@0 | 253 | mAsserter.is(pref.getString("value"), "http://cheese.com", "check " + prefLocalizeableOverride); |
michael@0 | 254 | } else if (aLocale.equals("es-MX")) { |
michael@0 | 255 | mAsserter.is(pref.getString("value"), "http://test.org/es-MX/", "check " + prefLocalizeableOverride); |
michael@0 | 256 | } |
michael@0 | 257 | } |
michael@0 | 258 | } |
michael@0 | 259 | |
michael@0 | 260 | } catch (JSONException e) { |
michael@0 | 261 | mAsserter.ok(false, "exception getting preferences", e.toString()); |
michael@0 | 262 | } |
michael@0 | 263 | } |
michael@0 | 264 | |
michael@0 | 265 | // Copies the mock package to the data directory and returns the file path to it. |
michael@0 | 266 | private String getMockPackagePath() { |
michael@0 | 267 | String mockPackagePath = ""; |
michael@0 | 268 | |
michael@0 | 269 | try { |
michael@0 | 270 | InputStream inStream = getAsset(MOCK_PACKAGE); |
michael@0 | 271 | File dataDir = new File(mActivity.getApplicationInfo().dataDir); |
michael@0 | 272 | File outFile = new File(dataDir, MOCK_PACKAGE); |
michael@0 | 273 | |
michael@0 | 274 | OutputStream outStream = new FileOutputStream(outFile); |
michael@0 | 275 | int b; |
michael@0 | 276 | while ((b = inStream.read()) != -1) { |
michael@0 | 277 | outStream.write(b); |
michael@0 | 278 | } |
michael@0 | 279 | inStream.close(); |
michael@0 | 280 | outStream.close(); |
michael@0 | 281 | |
michael@0 | 282 | mockPackagePath = outFile.getPath(); |
michael@0 | 283 | |
michael@0 | 284 | } catch (Exception e) { |
michael@0 | 285 | mAsserter.ok(false, "exception copying mock distribution package to data directory", e.toString()); |
michael@0 | 286 | } |
michael@0 | 287 | |
michael@0 | 288 | return mockPackagePath; |
michael@0 | 289 | } |
michael@0 | 290 | |
michael@0 | 291 | // Clears the distribution pref to return distribution state to STATE_UNKNOWN |
michael@0 | 292 | private void clearDistributionPref() { |
michael@0 | 293 | mAsserter.dumpLog("Clearing distribution pref."); |
michael@0 | 294 | SharedPreferences settings = mActivity.getSharedPreferences("GeckoApp", Activity.MODE_PRIVATE); |
michael@0 | 295 | String keyName = mActivity.getPackageName() + ".distribution_state"; |
michael@0 | 296 | settings.edit().remove(keyName).commit(); |
michael@0 | 297 | } |
michael@0 | 298 | |
michael@0 | 299 | @Override |
michael@0 | 300 | public void setUp() throws Exception { |
michael@0 | 301 | // TODO: Set up the content provider after setting the distribution. |
michael@0 | 302 | super.setUp(sBrowserProviderCallable, BrowserContract.AUTHORITY, "browser.db"); |
michael@0 | 303 | } |
michael@0 | 304 | |
michael@0 | 305 | private void delete(File file) throws Exception { |
michael@0 | 306 | if (file.isDirectory()) { |
michael@0 | 307 | File[] files = file.listFiles(); |
michael@0 | 308 | for (File f : files) { |
michael@0 | 309 | delete(f); |
michael@0 | 310 | } |
michael@0 | 311 | } |
michael@0 | 312 | mAsserter.ok(file.delete(), "clean up distribution files", "deleted " + file.getPath()); |
michael@0 | 313 | } |
michael@0 | 314 | |
michael@0 | 315 | @Override |
michael@0 | 316 | public void tearDown() throws Exception { |
michael@0 | 317 | File dataDir = new File(mActivity.getApplicationInfo().dataDir); |
michael@0 | 318 | |
michael@0 | 319 | // Delete mock package from data directory. |
michael@0 | 320 | File mockPackage = new File(dataDir, MOCK_PACKAGE); |
michael@0 | 321 | mAsserter.ok(mockPackage.delete(), "clean up mock package", "deleted " + mockPackage.getPath()); |
michael@0 | 322 | |
michael@0 | 323 | // Recursively delete distribution files that Distribution.init copied to data directory. |
michael@0 | 324 | File distDir = new File(dataDir, "distribution"); |
michael@0 | 325 | delete(distDir); |
michael@0 | 326 | |
michael@0 | 327 | clearDistributionPref(); |
michael@0 | 328 | |
michael@0 | 329 | super.tearDown(); |
michael@0 | 330 | } |
michael@0 | 331 | } |