services/sync/tests/unit/test_addons_store.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* Any copyright is dedicated to the Public Domain.
     2    http://creativecommons.org/publicdomain/zero/1.0/ */
     4 "use strict";
     6 Cu.import("resource://gre/modules/Preferences.jsm");
     7 Cu.import("resource://services-sync/addonutils.js");
     8 Cu.import("resource://services-sync/engines/addons.js");
     9 Cu.import("resource://services-sync/service.js");
    10 Cu.import("resource://services-sync/util.js");
    12 const HTTP_PORT = 8888;
    14 let prefs = new Preferences();
    16 prefs.set("extensions.getAddons.get.url", "http://localhost:8888/search/guid:%IDS%");
    17 loadAddonTestFunctions();
    18 startupManager();
    20 Service.engineManager.register(AddonsEngine);
    21 let engine     = Service.engineManager.get("addons");
    22 let tracker    = engine._tracker;
    23 let store      = engine._store;
    24 let reconciler = engine._reconciler;
    26 /**
    27  * Create a AddonsRec for this application with the fields specified.
    28  *
    29  * @param  id       Sync GUID of record
    30  * @param  addonId  ID of add-on
    31  * @param  enabled  Boolean whether record is enabled
    32  * @param  deleted  Boolean whether record was deleted
    33  */
    34 function createRecordForThisApp(id, addonId, enabled, deleted) {
    35   return {
    36     id:            id,
    37     addonID:       addonId,
    38     enabled:       enabled,
    39     deleted:       !!deleted,
    40     applicationID: Services.appinfo.ID,
    41     source:        "amo"
    42   };
    43 }
    45 function createAndStartHTTPServer(port) {
    46   try {
    47     let server = new HttpServer();
    49     let bootstrap1XPI = ExtensionsTestPath("/addons/test_bootstrap1_1.xpi");
    51     server.registerFile("/search/guid:bootstrap1%40tests.mozilla.org",
    52                         do_get_file("bootstrap1-search.xml"));
    53     server.registerFile("/bootstrap1.xpi", do_get_file(bootstrap1XPI));
    55     server.registerFile("/search/guid:missing-xpi%40tests.mozilla.org",
    56                         do_get_file("missing-xpi-search.xml"));
    58     server.start(port);
    60     return server;
    61   } catch (ex) {
    62     _("Got exception starting HTTP server on port " + port);
    63     _("Error: " + Utils.exceptionStr(ex));
    64     do_throw(ex);
    65   }
    66 }
    68 function run_test() {
    69   initTestLogging("Trace");
    70   Log.repository.getLogger("Sync.Engine.Addons").level = Log.Level.Trace;
    71   Log.repository.getLogger("Sync.AddonsRepository").level =
    72     Log.Level.Trace;
    74   reconciler.startListening();
    76   // Don't flush to disk in the middle of an event listener!
    77   // This causes test hangs on WinXP.
    78   reconciler._shouldPersist = false;
    80   run_next_test();
    81 }
    83 add_test(function test_remove() {
    84   _("Ensure removing add-ons from deleted records works.");
    86   let addon = installAddon("test_bootstrap1_1");
    87   let record = createRecordForThisApp(addon.syncGUID, addon.id, true, true);
    89   let failed = store.applyIncomingBatch([record]);
    90   do_check_eq(0, failed.length);
    92   let newAddon = getAddonFromAddonManagerByID(addon.id);
    93   do_check_eq(null, newAddon);
    95   run_next_test();
    96 });
    98 add_test(function test_apply_enabled() {
    99   _("Ensures that changes to the userEnabled flag apply.");
   101   let addon = installAddon("test_bootstrap1_1");
   102   do_check_true(addon.isActive);
   103   do_check_false(addon.userDisabled);
   105   _("Ensure application of a disable record works as expected.");
   106   let records = [];
   107   records.push(createRecordForThisApp(addon.syncGUID, addon.id, false, false));
   108   let failed = store.applyIncomingBatch(records);
   109   do_check_eq(0, failed.length);
   110   addon = getAddonFromAddonManagerByID(addon.id);
   111   do_check_true(addon.userDisabled);
   112   records = [];
   114   _("Ensure enable record works as expected.");
   115   records.push(createRecordForThisApp(addon.syncGUID, addon.id, true, false));
   116   failed = store.applyIncomingBatch(records);
   117   do_check_eq(0, failed.length);
   118   addon = getAddonFromAddonManagerByID(addon.id);
   119   do_check_false(addon.userDisabled);
   120   records = [];
   122   _("Ensure enabled state updates don't apply if the ignore pref is set.");
   123   records.push(createRecordForThisApp(addon.syncGUID, addon.id, false, false));
   124   Svc.Prefs.set("addons.ignoreUserEnabledChanges", true);
   125   failed = store.applyIncomingBatch(records);
   126   do_check_eq(0, failed.length);
   127   addon = getAddonFromAddonManagerByID(addon.id);
   128   do_check_false(addon.userDisabled);
   129   records = [];
   131   uninstallAddon(addon);
   132   Svc.Prefs.reset("addons.ignoreUserEnabledChanges");
   133   run_next_test();
   134 });
   136 add_test(function test_ignore_different_appid() {
   137   _("Ensure that incoming records with a different application ID are ignored.");
   139   // We test by creating a record that should result in an update.
   140   let addon = installAddon("test_bootstrap1_1");
   141   do_check_false(addon.userDisabled);
   143   let record = createRecordForThisApp(addon.syncGUID, addon.id, false, false);
   144   record.applicationID = "FAKE_ID";
   146   let failed = store.applyIncomingBatch([record]);
   147   do_check_eq(0, failed.length);
   149   let newAddon = getAddonFromAddonManagerByID(addon.id);
   150   do_check_false(addon.userDisabled);
   152   uninstallAddon(addon);
   154   run_next_test();
   155 });
   157 add_test(function test_ignore_unknown_source() {
   158   _("Ensure incoming records with unknown source are ignored.");
   160   let addon = installAddon("test_bootstrap1_1");
   162   let record = createRecordForThisApp(addon.syncGUID, addon.id, false, false);
   163   record.source = "DUMMY_SOURCE";
   165   let failed = store.applyIncomingBatch([record]);
   166   do_check_eq(0, failed.length);
   168   let newAddon = getAddonFromAddonManagerByID(addon.id);
   169   do_check_false(addon.userDisabled);
   171   uninstallAddon(addon);
   173   run_next_test();
   174 });
   176 add_test(function test_apply_uninstall() {
   177   _("Ensures that uninstalling an add-on from a record works.");
   179   let addon = installAddon("test_bootstrap1_1");
   181   let records = [];
   182   records.push(createRecordForThisApp(addon.syncGUID, addon.id, true, true));
   183   let failed = store.applyIncomingBatch(records);
   184   do_check_eq(0, failed.length);
   186   addon = getAddonFromAddonManagerByID(addon.id);
   187   do_check_eq(null, addon);
   189   run_next_test();
   190 });
   192 add_test(function test_addon_syncability() {
   193   _("Ensure isAddonSyncable functions properly.");
   195   Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
   196   Svc.Prefs.set("addons.trustedSourceHostnames",
   197                 "addons.mozilla.org,other.example.com");
   199   do_check_false(store.isAddonSyncable(null));
   201   let addon = installAddon("test_bootstrap1_1");
   202   do_check_true(store.isAddonSyncable(addon));
   204   let dummy = {};
   205   const KEYS = ["id", "syncGUID", "type", "scope", "foreignInstall"];
   206   for each (let k in KEYS) {
   207     dummy[k] = addon[k];
   208   }
   210   do_check_true(store.isAddonSyncable(dummy));
   212   dummy.type = "UNSUPPORTED";
   213   do_check_false(store.isAddonSyncable(dummy));
   214   dummy.type = addon.type;
   216   dummy.scope = 0;
   217   do_check_false(store.isAddonSyncable(dummy));
   218   dummy.scope = addon.scope;
   220   dummy.foreignInstall = true;
   221   do_check_false(store.isAddonSyncable(dummy));
   222   dummy.foreignInstall = false;
   224   uninstallAddon(addon);
   226   do_check_false(store.isSourceURITrusted(null));
   228   function createURI(s) {
   229     let service = Components.classes["@mozilla.org/network/io-service;1"]
   230                   .getService(Components.interfaces.nsIIOService);
   231     return service.newURI(s, null, null);
   232   }
   234   let trusted = [
   235     "https://addons.mozilla.org/foo",
   236     "https://other.example.com/foo"
   237   ];
   239   let untrusted = [
   240     "http://addons.mozilla.org/foo",     // non-https
   241     "ftps://addons.mozilla.org/foo",     // non-https
   242     "https://untrusted.example.com/foo", // non-trusted hostname`
   243   ];
   245   for each (let uri in trusted) {
   246     do_check_true(store.isSourceURITrusted(createURI(uri)));
   247   }
   249   for each (let uri in untrusted) {
   250     do_check_false(store.isSourceURITrusted(createURI(uri)));
   251   }
   253   Svc.Prefs.set("addons.trustedSourceHostnames", "");
   254   for each (let uri in trusted) {
   255     do_check_false(store.isSourceURITrusted(createURI(uri)));
   256   }
   258   Svc.Prefs.set("addons.trustedSourceHostnames", "addons.mozilla.org");
   259   do_check_true(store.isSourceURITrusted(createURI("https://addons.mozilla.org/foo")));
   261   Svc.Prefs.reset("addons.trustedSourceHostnames");
   263   run_next_test();
   264 });
   266 add_test(function test_ignore_hotfixes() {
   267   _("Ensure that hotfix extensions are ignored.");
   269   Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
   271   // A hotfix extension is one that has the id the same as the
   272   // extensions.hotfix.id pref.
   273   let prefs = new Preferences("extensions.");
   275   let addon = installAddon("test_bootstrap1_1");
   276   do_check_true(store.isAddonSyncable(addon));
   278   let dummy = {};
   279   const KEYS = ["id", "syncGUID", "type", "scope", "foreignInstall"];
   280   for each (let k in KEYS) {
   281     dummy[k] = addon[k];
   282   }
   284   // Basic sanity check.
   285   do_check_true(store.isAddonSyncable(dummy));
   287   prefs.set("hotfix.id", dummy.id);
   288   do_check_false(store.isAddonSyncable(dummy));
   290   // Verify that int values don't throw off checking.
   291   let prefSvc = Cc["@mozilla.org/preferences-service;1"]
   292                 .getService(Ci.nsIPrefService)
   293                 .getBranch("extensions.");
   294   // Need to delete pref before changing type.
   295   prefSvc.deleteBranch("hotfix.id");
   296   prefSvc.setIntPref("hotfix.id", 0xdeadbeef);
   298   do_check_true(store.isAddonSyncable(dummy));
   300   uninstallAddon(addon);
   302   Svc.Prefs.reset("addons.ignoreRepositoryChecking");
   303   prefs.reset("hotfix.id");
   305   run_next_test();
   306 });
   309 add_test(function test_get_all_ids() {
   310   _("Ensures that getAllIDs() returns an appropriate set.");
   312   Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
   314   _("Installing two addons.");
   315   let addon1 = installAddon("test_install1");
   316   let addon2 = installAddon("test_bootstrap1_1");
   318   _("Ensure they're syncable.");
   319   do_check_true(store.isAddonSyncable(addon1));
   320   do_check_true(store.isAddonSyncable(addon2));
   322   let ids = store.getAllIDs();
   324   do_check_eq("object", typeof(ids));
   325   do_check_eq(2, Object.keys(ids).length);
   326   do_check_true(addon1.syncGUID in ids);
   327   do_check_true(addon2.syncGUID in ids);
   329   addon1.install.cancel();
   330   uninstallAddon(addon2);
   332   Svc.Prefs.reset("addons.ignoreRepositoryChecking");
   333   run_next_test();
   334 });
   336 add_test(function test_change_item_id() {
   337   _("Ensures that changeItemID() works properly.");
   339   let addon = installAddon("test_bootstrap1_1");
   341   let oldID = addon.syncGUID;
   342   let newID = Utils.makeGUID();
   344   store.changeItemID(oldID, newID);
   346   let newAddon = getAddonFromAddonManagerByID(addon.id);
   347   do_check_neq(null, newAddon);
   348   do_check_eq(newID, newAddon.syncGUID);
   350   uninstallAddon(newAddon);
   352   run_next_test();
   353 });
   355 add_test(function test_create() {
   356   _("Ensure creating/installing an add-on from a record works.");
   358   // Set this so that getInstallFromSearchResult doesn't end up
   359   // failing the install due to an insecure source URI scheme.
   360   Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
   361   let server = createAndStartHTTPServer(HTTP_PORT);
   363   let addon = installAddon("test_bootstrap1_1");
   364   let id = addon.id;
   365   uninstallAddon(addon);
   367   let guid = Utils.makeGUID();
   368   let record = createRecordForThisApp(guid, id, true, false);
   370   let failed = store.applyIncomingBatch([record]);
   371   do_check_eq(0, failed.length);
   373   let newAddon = getAddonFromAddonManagerByID(id);
   374   do_check_neq(null, newAddon);
   375   do_check_eq(guid, newAddon.syncGUID);
   376   do_check_false(newAddon.userDisabled);
   378   uninstallAddon(newAddon);
   380   Svc.Prefs.reset("addons.ignoreRepositoryChecking");
   381   server.stop(run_next_test);
   382 });
   384 add_test(function test_create_missing_search() {
   385   _("Ensures that failed add-on searches are handled gracefully.");
   387   let server = createAndStartHTTPServer(HTTP_PORT);
   389   // The handler for this ID is not installed, so a search should 404.
   390   const id = "missing@tests.mozilla.org";
   391   let guid = Utils.makeGUID();
   392   let record = createRecordForThisApp(guid, id, true, false);
   394   let failed = store.applyIncomingBatch([record]);
   395   do_check_eq(1, failed.length);
   396   do_check_eq(guid, failed[0]);
   398   let addon = getAddonFromAddonManagerByID(id);
   399   do_check_eq(null, addon);
   401   server.stop(run_next_test);
   402 });
   404 add_test(function test_create_bad_install() {
   405   _("Ensures that add-ons without a valid install are handled gracefully.");
   407   let server = createAndStartHTTPServer(HTTP_PORT);
   409   // The handler returns a search result but the XPI will 404.
   410   const id = "missing-xpi@tests.mozilla.org";
   411   let guid = Utils.makeGUID();
   412   let record = createRecordForThisApp(guid, id, true, false);
   414   let failed = store.applyIncomingBatch([record]);
   415   do_check_eq(1, failed.length);
   416   do_check_eq(guid, failed[0]);
   418   let addon = getAddonFromAddonManagerByID(id);
   419   do_check_eq(null, addon);
   421   server.stop(run_next_test);
   422 });
   424 add_test(function test_wipe() {
   425   _("Ensures that wiping causes add-ons to be uninstalled.");
   427   let addon1 = installAddon("test_bootstrap1_1");
   429   Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
   430   store.wipe();
   432   let addon = getAddonFromAddonManagerByID(addon1.id);
   433   do_check_eq(null, addon);
   435   Svc.Prefs.reset("addons.ignoreRepositoryChecking");
   437   run_next_test();
   438 });
   440 add_test(function test_wipe_and_install() {
   441   _("Ensure wipe followed by install works.");
   443   // This tests the reset sync flow where remote data is replaced by local. The
   444   // receiving client will see a wipe followed by a record which should undo
   445   // the wipe.
   446   let installed = installAddon("test_bootstrap1_1");
   448   let record = createRecordForThisApp(installed.syncGUID, installed.id, true,
   449                                       false);
   451   Svc.Prefs.set("addons.ignoreRepositoryChecking", true);
   452   store.wipe();
   454   let deleted = getAddonFromAddonManagerByID(installed.id);
   455   do_check_null(deleted);
   457   // Re-applying the record can require re-fetching the XPI.
   458   let server = createAndStartHTTPServer(HTTP_PORT);
   460   store.applyIncoming(record);
   462   let fetched = getAddonFromAddonManagerByID(record.addonID);
   463   do_check_true(!!fetched);
   465   Svc.Prefs.reset("addons.ignoreRepositoryChecking");
   466   server.stop(run_next_test);
   467 });
   469 add_test(function cleanup() {
   470   // There's an xpcom-shutdown hook for this, but let's give this a shot.
   471   reconciler.stopListening();
   472   run_next_test();
   473 });

mercurial