michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: "use strict"; michael@0: michael@0: Cu.import("resource://gre/modules/AddonManager.jsm"); michael@0: Cu.import("resource://services-sync/addonsreconciler.js"); michael@0: Cu.import("resource://services-sync/engines/addons.js"); michael@0: Cu.import("resource://services-sync/service.js"); michael@0: Cu.import("resource://services-sync/util.js"); michael@0: michael@0: loadAddonTestFunctions(); michael@0: startupManager(); michael@0: michael@0: function run_test() { michael@0: initTestLogging("Trace"); michael@0: Log.repository.getLogger("Sync.AddonsReconciler").level = Log.Level.Trace; michael@0: Log.repository.getLogger("Sync.AddonsReconciler").level = michael@0: Log.Level.Trace; michael@0: michael@0: Svc.Prefs.set("engine.addons", true); michael@0: Service.engineManager.register(AddonsEngine); michael@0: michael@0: run_next_test(); michael@0: } michael@0: michael@0: add_test(function test_defaults() { michael@0: _("Ensure new objects have reasonable defaults."); michael@0: michael@0: let reconciler = new AddonsReconciler(); michael@0: michael@0: do_check_false(reconciler._listening); michael@0: do_check_eq("object", typeof(reconciler.addons)); michael@0: do_check_eq(0, Object.keys(reconciler.addons).length); michael@0: do_check_eq(0, reconciler._changes.length); michael@0: do_check_eq(0, reconciler._listeners.length); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: add_test(function test_load_state_empty_file() { michael@0: _("Ensure loading from a missing file results in defaults being set."); michael@0: michael@0: let reconciler = new AddonsReconciler(); michael@0: michael@0: reconciler.loadState(null, function(error, loaded) { michael@0: do_check_eq(null, error); michael@0: do_check_false(loaded); michael@0: michael@0: do_check_eq("object", typeof(reconciler.addons)); michael@0: do_check_eq(0, Object.keys(reconciler.addons).length); michael@0: do_check_eq(0, reconciler._changes.length); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: }); michael@0: michael@0: add_test(function test_install_detection() { michael@0: _("Ensure that add-on installation results in appropriate side-effects."); michael@0: michael@0: let reconciler = new AddonsReconciler(); michael@0: reconciler.startListening(); michael@0: michael@0: let before = new Date(); michael@0: let addon = installAddon("test_bootstrap1_1"); michael@0: let after = new Date(); michael@0: michael@0: do_check_eq(1, Object.keys(reconciler.addons).length); michael@0: do_check_true(addon.id in reconciler.addons); michael@0: let record = reconciler.addons[addon.id]; michael@0: michael@0: const KEYS = ["id", "guid", "enabled", "installed", "modified", "type", michael@0: "scope", "foreignInstall"]; michael@0: for each (let key in KEYS) { michael@0: do_check_true(key in record); michael@0: do_check_neq(null, record[key]); michael@0: } michael@0: michael@0: do_check_eq(addon.id, record.id); michael@0: do_check_eq(addon.syncGUID, record.guid); michael@0: do_check_true(record.enabled); michael@0: do_check_true(record.installed); michael@0: do_check_true(record.modified >= before && record.modified <= after); michael@0: do_check_eq("extension", record.type); michael@0: do_check_false(record.foreignInstall); michael@0: michael@0: do_check_eq(1, reconciler._changes.length); michael@0: let change = reconciler._changes[0]; michael@0: do_check_true(change[0] >= before && change[1] <= after); michael@0: do_check_eq(CHANGE_INSTALLED, change[1]); michael@0: do_check_eq(addon.id, change[2]); michael@0: michael@0: uninstallAddon(addon); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: add_test(function test_uninstall_detection() { michael@0: _("Ensure that add-on uninstallation results in appropriate side-effects."); michael@0: michael@0: let reconciler = new AddonsReconciler(); michael@0: reconciler.startListening(); michael@0: michael@0: reconciler._addons = {}; michael@0: reconciler._changes = []; michael@0: michael@0: let addon = installAddon("test_bootstrap1_1"); michael@0: let id = addon.id; michael@0: let guid = addon.syncGUID; michael@0: michael@0: reconciler._changes = []; michael@0: uninstallAddon(addon); michael@0: michael@0: do_check_eq(1, Object.keys(reconciler.addons).length); michael@0: do_check_true(id in reconciler.addons); michael@0: michael@0: let record = reconciler.addons[id]; michael@0: do_check_false(record.installed); michael@0: michael@0: do_check_eq(1, reconciler._changes.length); michael@0: let change = reconciler._changes[0]; michael@0: do_check_eq(CHANGE_UNINSTALLED, change[1]); michael@0: do_check_eq(id, change[2]); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: add_test(function test_load_state_future_version() { michael@0: _("Ensure loading a file from a future version results in no data loaded."); michael@0: michael@0: const FILENAME = "TEST_LOAD_STATE_FUTURE_VERSION"; michael@0: michael@0: let reconciler = new AddonsReconciler(); michael@0: michael@0: // First we populate our new file. michael@0: let state = {version: 100, addons: {foo: {}}, changes: [[1, 1, "foo"]]}; michael@0: let cb = Async.makeSyncCallback(); michael@0: michael@0: // jsonSave() expects an object with ._log, so we give it a reconciler michael@0: // instance. michael@0: Utils.jsonSave(FILENAME, reconciler, state, cb); michael@0: Async.waitForSyncCallback(cb); michael@0: michael@0: reconciler.loadState(FILENAME, function(error, loaded) { michael@0: do_check_eq(null, error); michael@0: do_check_false(loaded); michael@0: michael@0: do_check_eq("object", typeof(reconciler.addons)); michael@0: do_check_eq(1, Object.keys(reconciler.addons).length); michael@0: do_check_eq(1, reconciler._changes.length); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: }); michael@0: michael@0: add_test(function test_prune_changes_before_date() { michael@0: _("Ensure that old changes are pruned properly."); michael@0: michael@0: let reconciler = new AddonsReconciler(); michael@0: reconciler._ensureStateLoaded(); michael@0: reconciler._changes = []; michael@0: michael@0: let now = new Date(); michael@0: const HOUR_MS = 1000 * 60 * 60; michael@0: michael@0: _("Ensure pruning an empty changes array works."); michael@0: reconciler.pruneChangesBeforeDate(now); michael@0: do_check_eq(0, reconciler._changes.length); michael@0: michael@0: let old = new Date(now.getTime() - HOUR_MS); michael@0: let young = new Date(now.getTime() - 1000); michael@0: reconciler._changes.push([old, CHANGE_INSTALLED, "foo"]); michael@0: reconciler._changes.push([young, CHANGE_INSTALLED, "bar"]); michael@0: do_check_eq(2, reconciler._changes.length); michael@0: michael@0: _("Ensure pruning with an old time won't delete anything."); michael@0: let threshold = new Date(old.getTime() - 1); michael@0: reconciler.pruneChangesBeforeDate(threshold); michael@0: do_check_eq(2, reconciler._changes.length); michael@0: michael@0: _("Ensure pruning a single item works."); michael@0: let threshold = new Date(young.getTime() - 1000); michael@0: reconciler.pruneChangesBeforeDate(threshold); michael@0: do_check_eq(1, reconciler._changes.length); michael@0: do_check_neq(undefined, reconciler._changes[0]); michael@0: do_check_eq(young, reconciler._changes[0][0]); michael@0: do_check_eq("bar", reconciler._changes[0][2]); michael@0: michael@0: _("Ensure pruning all changes works."); michael@0: reconciler._changes.push([old, CHANGE_INSTALLED, "foo"]); michael@0: reconciler.pruneChangesBeforeDate(now); michael@0: do_check_eq(0, reconciler._changes.length); michael@0: michael@0: run_next_test(); michael@0: });