зеркало из https://github.com/mozilla/gecko-dev.git
328 строки
9.3 KiB
JavaScript
328 строки
9.3 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
ChromeUtils.import("resource://services-sync/engines/tabs.js");
|
|
const { Service } = ChromeUtils.import("resource://services-sync/service.js");
|
|
|
|
const { SyncScheduler } = ChromeUtils.import(
|
|
"resource://services-sync/policies.js"
|
|
);
|
|
|
|
const { ExperimentFakes } = ChromeUtils.import(
|
|
"resource://testing-common/NimbusTestUtils.jsm"
|
|
);
|
|
|
|
const { ExperimentAPI } = ChromeUtils.import(
|
|
"resource://nimbus/ExperimentAPI.jsm"
|
|
);
|
|
|
|
var scheduler = new SyncScheduler(Service);
|
|
let clientsEngine;
|
|
|
|
async function setupForExperimentFeature() {
|
|
const sandbox = sinon.createSandbox();
|
|
const manager = ExperimentFakes.manager();
|
|
await manager.onStartup();
|
|
|
|
sandbox.stub(ExperimentAPI, "_store").get(() => manager.store);
|
|
|
|
return { sandbox, manager };
|
|
}
|
|
|
|
add_task(async function setup() {
|
|
await Service.promiseInitialized;
|
|
clientsEngine = Service.clientsEngine;
|
|
|
|
scheduler.setDefaults();
|
|
});
|
|
|
|
function fakeSvcWinMediator() {
|
|
// actions on windows are captured in logs
|
|
let logs = [];
|
|
delete Services.wm;
|
|
|
|
function getNext() {
|
|
let elt = { addTopics: [], remTopics: [], numAPL: 0, numRPL: 0 };
|
|
logs.push(elt);
|
|
return {
|
|
addEventListener(topic) {
|
|
elt.addTopics.push(topic);
|
|
},
|
|
removeEventListener(topic) {
|
|
elt.remTopics.push(topic);
|
|
},
|
|
gBrowser: {
|
|
addProgressListener() {
|
|
elt.numAPL++;
|
|
},
|
|
removeProgressListener() {
|
|
elt.numRPL++;
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
Services.wm = {
|
|
getEnumerator() {
|
|
return [getNext(), getNext()];
|
|
},
|
|
};
|
|
return logs;
|
|
}
|
|
|
|
add_task(async function run_test() {
|
|
let engine = Service.engineManager.get("tabs");
|
|
|
|
_("We assume that tabs have changed at startup.");
|
|
let tracker = engine._tracker;
|
|
|
|
Assert.ok(tracker.modified);
|
|
Assert.ok(
|
|
Utils.deepEquals(Object.keys(await engine.getChangedIDs()), [
|
|
clientsEngine.localID,
|
|
])
|
|
);
|
|
|
|
let logs;
|
|
|
|
_("Test listeners are registered on windows");
|
|
logs = fakeSvcWinMediator();
|
|
tracker.start();
|
|
Assert.equal(logs.length, 2);
|
|
for (let log of logs) {
|
|
Assert.equal(log.addTopics.length, 4);
|
|
Assert.ok(log.addTopics.includes("TabOpen"));
|
|
Assert.ok(log.addTopics.includes("TabClose"));
|
|
Assert.ok(log.addTopics.includes("TabSelect"));
|
|
Assert.ok(log.addTopics.includes("unload"));
|
|
Assert.equal(log.remTopics.length, 0);
|
|
Assert.equal(log.numAPL, 1, "Added 1 progress listener");
|
|
Assert.equal(log.numRPL, 0, "Didn't remove a progress listener");
|
|
}
|
|
|
|
_("Test listeners are unregistered on windows");
|
|
logs = fakeSvcWinMediator();
|
|
await tracker.stop();
|
|
Assert.equal(logs.length, 2);
|
|
for (let log of logs) {
|
|
Assert.equal(log.addTopics.length, 0);
|
|
Assert.equal(log.remTopics.length, 4);
|
|
Assert.ok(log.remTopics.includes("TabOpen"));
|
|
Assert.ok(log.remTopics.includes("TabClose"));
|
|
Assert.ok(log.remTopics.includes("TabSelect"));
|
|
Assert.ok(log.remTopics.includes("unload"));
|
|
Assert.equal(log.numAPL, 0, "Didn't add a progress listener");
|
|
Assert.equal(log.numRPL, 1, "Removed 1 progress listener");
|
|
}
|
|
|
|
_("Test tab listener");
|
|
for (let evttype of ["TabOpen", "TabClose", "TabSelect"]) {
|
|
// Pretend we just synced.
|
|
await tracker.clearChangedIDs();
|
|
Assert.ok(!tracker.modified);
|
|
|
|
// Send a fake tab event
|
|
tracker.onTab({ type: evttype, originalTarget: evttype });
|
|
Assert.ok(tracker.modified);
|
|
Assert.ok(
|
|
Utils.deepEquals(Object.keys(await engine.getChangedIDs()), [
|
|
clientsEngine.localID,
|
|
])
|
|
);
|
|
}
|
|
|
|
// Pretend we just synced.
|
|
await tracker.clearChangedIDs();
|
|
Assert.ok(!tracker.modified);
|
|
|
|
tracker.onTab({ type: "TabOpen", originalTarget: "TabOpen" });
|
|
Assert.ok(
|
|
Utils.deepEquals(Object.keys(await engine.getChangedIDs()), [
|
|
clientsEngine.localID,
|
|
])
|
|
);
|
|
|
|
// Pretend we just synced and saw some progress listeners.
|
|
await tracker.clearChangedIDs();
|
|
Assert.ok(!tracker.modified);
|
|
tracker.onLocationChange({ isTopLevel: false }, undefined, undefined, 0);
|
|
Assert.ok(!tracker.modified, "non-toplevel request didn't flag as modified");
|
|
|
|
tracker.onLocationChange(
|
|
{ isTopLevel: true },
|
|
undefined,
|
|
Services.io.newURI("https://www.mozilla.org"),
|
|
Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT
|
|
);
|
|
Assert.ok(
|
|
!tracker.modified,
|
|
"location change within the same document request didn't flag as modified"
|
|
);
|
|
|
|
tracker.onLocationChange(
|
|
{ isTopLevel: true },
|
|
undefined,
|
|
Services.io.newURI("https://www.mozilla.org"),
|
|
Ci.nsIWebProgressListener.LOCATION_CHANGE_RELOAD
|
|
);
|
|
Assert.ok(
|
|
tracker.modified,
|
|
"location change for a new top-level document flagged as modified"
|
|
);
|
|
Assert.ok(
|
|
Utils.deepEquals(Object.keys(await engine.getChangedIDs()), [
|
|
clientsEngine.localID,
|
|
])
|
|
);
|
|
});
|
|
|
|
add_task(async function run_sync_on_tab_change_test() {
|
|
let { manager } = await setupForExperimentFeature();
|
|
await manager.onStartup();
|
|
await ExperimentAPI.ready();
|
|
|
|
let testExperimentDelay = 5000;
|
|
|
|
// This is the fallback pref if we don't have a experiment running
|
|
Svc.Prefs.set("syncedTabs.syncDelayAfterTabChange", testExperimentDelay);
|
|
|
|
let doEnrollmentCleanup = await ExperimentFakes.enrollWithFeatureConfig(
|
|
{
|
|
enabled: true,
|
|
featureId: "syncAfterTabChange",
|
|
value: { syncDelayAfterTabChange: testExperimentDelay },
|
|
},
|
|
{
|
|
manager,
|
|
}
|
|
);
|
|
Assert.ok(
|
|
manager.store.getExperimentForFeature("syncAfterTabChange"),
|
|
"Should be enrolled in the experiment"
|
|
);
|
|
|
|
let engine = Service.engineManager.get("tabs");
|
|
|
|
_("We assume that tabs have changed at startup.");
|
|
let tracker = engine._tracker;
|
|
|
|
Assert.ok(tracker.modified);
|
|
Assert.ok(
|
|
Utils.deepEquals(Object.keys(await engine.getChangedIDs()), [
|
|
clientsEngine.localID,
|
|
])
|
|
);
|
|
|
|
_("Test sync is scheduled after a tab change if experiment is enabled");
|
|
for (let evttype of ["TabOpen", "TabClose", "TabSelect"]) {
|
|
// Send a fake tab event
|
|
tracker.onTab({ type: evttype, originalTarget: evttype });
|
|
// Ensure the tracker fired
|
|
Assert.ok(tracker.modified);
|
|
// We should be scheduling <= experiment value
|
|
Assert.ok(scheduler.nextSync - Date.now() <= testExperimentDelay);
|
|
}
|
|
|
|
_("Test navigating within the same tab triggers a sync");
|
|
// Pretend we just synced
|
|
await tracker.clearChangedIDs();
|
|
|
|
tracker.onLocationChange(
|
|
{ isTopLevel: true },
|
|
undefined,
|
|
Services.io.newURI("https://www.mozilla.org"),
|
|
Ci.nsIWebProgressListener.LOCATION_CHANGE_RELOAD
|
|
);
|
|
Assert.ok(
|
|
tracker.modified,
|
|
"location change for a new top-level document flagged as modified"
|
|
);
|
|
Assert.ok(
|
|
scheduler.nextSync - Date.now() <= testExperimentDelay,
|
|
"top level document change triggers a sync when experiment is enabled"
|
|
);
|
|
|
|
// Pretend we just synced
|
|
await tracker.clearChangedIDs();
|
|
scheduler.nextSync = Date.now() + scheduler.idleInterval;
|
|
|
|
_("Test navigating to an about page does not trigger sync");
|
|
tracker.onLocationChange(
|
|
{ isTopLevel: true },
|
|
undefined,
|
|
Services.io.newURI("about:config")
|
|
);
|
|
Assert.ok(!tracker.modified, "about page does not trigger a tab modified");
|
|
Assert.ok(
|
|
scheduler.nextSync - Date.now() > testExperimentDelay,
|
|
"about schema should not trigger a sync happening soon"
|
|
);
|
|
|
|
_("Test adjusting the filterScheme pref works");
|
|
// Pretend we just synced
|
|
await tracker.clearChangedIDs();
|
|
scheduler.nextSync = Date.now() + scheduler.idleInterval;
|
|
|
|
Svc.Prefs.set(
|
|
"engine.tabs.filteredSchemes",
|
|
// Removing the about scheme for this test
|
|
"resource|chrome|file|blob|moz-extension"
|
|
);
|
|
tracker.onLocationChange(
|
|
{ isTopLevel: true },
|
|
undefined,
|
|
Services.io.newURI("about:config")
|
|
);
|
|
Assert.ok(
|
|
tracker.modified,
|
|
"about page triggers a modified after we changed the pref"
|
|
);
|
|
Assert.ok(
|
|
scheduler.nextSync - Date.now() <= testExperimentDelay,
|
|
"about page should trigger a sync soon after we changed the pref"
|
|
);
|
|
await doEnrollmentCleanup();
|
|
|
|
_("If there is no experiment, fallback to the pref");
|
|
let delayPref = Svc.Prefs.get("syncedTabs.syncDelayAfterTabChange");
|
|
let evttype = "TabOpen";
|
|
Assert.equal(delayPref, testExperimentDelay);
|
|
// Fire ontab event
|
|
tracker.onTab({ type: evttype, originalTarget: evttype });
|
|
|
|
// Ensure the tracker fired
|
|
Assert.ok(tracker.modified);
|
|
// We should be scheduling <= preference value
|
|
Assert.ok(scheduler.nextSync - Date.now() <= delayPref);
|
|
|
|
_("We should not have a sync if experiment if off and pref is 0");
|
|
|
|
Svc.Prefs.set("syncedTabs.syncDelayAfterTabChange", 0);
|
|
let doAnotherEnrollmentCleanup = await ExperimentFakes.enrollWithFeatureConfig(
|
|
{
|
|
enabled: true,
|
|
featureId: "syncAfterTabChange",
|
|
value: { syncDelayAfterTabChange: 0 },
|
|
},
|
|
{
|
|
manager,
|
|
}
|
|
);
|
|
// Schedule sync a super long time from now
|
|
scheduler.nextSync = Date.now() + scheduler.idleInterval;
|
|
|
|
// Fire ontab event
|
|
evttype = "TabOpen";
|
|
tracker.onTab({ type: evttype, originalTarget: evttype });
|
|
// Ensure the tracker fired
|
|
Assert.ok(tracker.modified);
|
|
|
|
// We should NOT be scheduled for a sync soon
|
|
Assert.ok(scheduler.nextSync - Date.now() > testExperimentDelay);
|
|
|
|
// cleanup
|
|
await doAnotherEnrollmentCleanup();
|
|
scheduler.setDefaults();
|
|
Svc.Prefs.resetBranch("");
|
|
});
|