forked from mirrors/gecko-dev
Theoretically we only need to change this where the strings might be non-ascii but it seems safer in the long run to just avoid the "char" versions entirely. Differential Revision: https://phabricator.services.mozilla.com/D200342
472 lines
16 KiB
JavaScript
472 lines
16 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
Svc.PrefBranch.setStringPref("registerEngines", "");
|
|
const { Service } = ChromeUtils.importESModule(
|
|
"resource://services-sync/service.sys.mjs"
|
|
);
|
|
|
|
let scheduler;
|
|
let clientsEngine;
|
|
|
|
async function sync_httpd_setup() {
|
|
let clientsSyncID = await clientsEngine.resetLocalSyncID();
|
|
let global = new ServerWBO("global", {
|
|
syncID: Service.syncID,
|
|
storageVersion: STORAGE_VERSION,
|
|
engines: {
|
|
clients: { version: clientsEngine.version, syncID: clientsSyncID },
|
|
},
|
|
});
|
|
let clientsColl = new ServerCollection({}, true);
|
|
|
|
// Tracking info/collections.
|
|
let collectionsHelper = track_collections_helper();
|
|
let upd = collectionsHelper.with_updated_collection;
|
|
|
|
return httpd_setup({
|
|
"/1.1/johndoe/storage/meta/global": upd("meta", global.handler()),
|
|
"/1.1/johndoe/info/collections": collectionsHelper.handler,
|
|
"/1.1/johndoe/storage/crypto/keys": upd(
|
|
"crypto",
|
|
new ServerWBO("keys").handler()
|
|
),
|
|
"/1.1/johndoe/storage/clients": upd("clients", clientsColl.handler()),
|
|
});
|
|
}
|
|
|
|
async function setUp(server) {
|
|
syncTestLogging();
|
|
await configureIdentity({ username: "johndoe" }, server);
|
|
await generateNewKeys(Service.collectionKeys);
|
|
let serverKeys = Service.collectionKeys.asWBO("crypto", "keys");
|
|
await serverKeys.encrypt(Service.identity.syncKeyBundle);
|
|
await serverKeys.upload(Service.resource(Service.cryptoKeysURL));
|
|
}
|
|
|
|
add_task(async function setup() {
|
|
scheduler = Service.scheduler;
|
|
clientsEngine = Service.clientsEngine;
|
|
|
|
// Don't remove stale clients when syncing. This is a test-only workaround
|
|
// that lets us add clients directly to the store, without losing them on
|
|
// the next sync.
|
|
clientsEngine._removeRemoteClient = async id => {};
|
|
});
|
|
|
|
add_task(async function test_successful_sync_adjustSyncInterval() {
|
|
enableValidationPrefs();
|
|
|
|
_("Test successful sync calling adjustSyncInterval");
|
|
let syncSuccesses = 0;
|
|
function onSyncFinish() {
|
|
_("Sync success.");
|
|
syncSuccesses++;
|
|
}
|
|
Svc.Obs.add("weave:service:sync:finish", onSyncFinish);
|
|
|
|
let server = await sync_httpd_setup();
|
|
await setUp(server);
|
|
|
|
// Confirm defaults
|
|
Assert.ok(!scheduler.idle);
|
|
Assert.equal(false, scheduler.numClients > 1);
|
|
Assert.equal(scheduler.syncInterval, scheduler.singleDeviceInterval);
|
|
Assert.ok(!scheduler.hasIncomingItems);
|
|
|
|
_("Test as long as numClients <= 1 our sync interval is SINGLE_USER.");
|
|
// idle == true && numClients <= 1 && hasIncomingItems == false
|
|
scheduler.idle = true;
|
|
await Service.sync();
|
|
Assert.equal(syncSuccesses, 1);
|
|
Assert.ok(scheduler.idle);
|
|
Assert.equal(false, scheduler.numClients > 1);
|
|
Assert.ok(!scheduler.hasIncomingItems);
|
|
Assert.equal(scheduler.syncInterval, scheduler.singleDeviceInterval);
|
|
|
|
// idle == false && numClients <= 1 && hasIncomingItems == false
|
|
scheduler.idle = false;
|
|
await Service.sync();
|
|
Assert.equal(syncSuccesses, 2);
|
|
Assert.ok(!scheduler.idle);
|
|
Assert.equal(false, scheduler.numClients > 1);
|
|
Assert.ok(!scheduler.hasIncomingItems);
|
|
Assert.equal(scheduler.syncInterval, scheduler.singleDeviceInterval);
|
|
|
|
// idle == false && numClients <= 1 && hasIncomingItems == true
|
|
scheduler.hasIncomingItems = true;
|
|
await Service.sync();
|
|
Assert.equal(syncSuccesses, 3);
|
|
Assert.ok(!scheduler.idle);
|
|
Assert.equal(false, scheduler.numClients > 1);
|
|
Assert.ok(scheduler.hasIncomingItems);
|
|
Assert.equal(scheduler.syncInterval, scheduler.singleDeviceInterval);
|
|
|
|
// idle == true && numClients <= 1 && hasIncomingItems == true
|
|
scheduler.idle = true;
|
|
await Service.sync();
|
|
Assert.equal(syncSuccesses, 4);
|
|
Assert.ok(scheduler.idle);
|
|
Assert.equal(false, scheduler.numClients > 1);
|
|
Assert.ok(scheduler.hasIncomingItems);
|
|
Assert.equal(scheduler.syncInterval, scheduler.singleDeviceInterval);
|
|
|
|
_(
|
|
"Test as long as idle && numClients > 1 our sync interval is idleInterval."
|
|
);
|
|
// idle == true && numClients > 1 && hasIncomingItems == true
|
|
await Service.clientsEngine._store.create({
|
|
id: "foo",
|
|
cleartext: { name: "bar", type: "mobile" },
|
|
});
|
|
await Service.sync();
|
|
Assert.equal(syncSuccesses, 5);
|
|
Assert.ok(scheduler.idle);
|
|
Assert.ok(scheduler.numClients > 1);
|
|
Assert.ok(scheduler.hasIncomingItems);
|
|
Assert.equal(scheduler.syncInterval, scheduler.idleInterval);
|
|
|
|
// idle == true && numClients > 1 && hasIncomingItems == false
|
|
scheduler.hasIncomingItems = false;
|
|
await Service.sync();
|
|
Assert.equal(syncSuccesses, 6);
|
|
Assert.ok(scheduler.idle);
|
|
Assert.ok(scheduler.numClients > 1);
|
|
Assert.ok(!scheduler.hasIncomingItems);
|
|
Assert.equal(scheduler.syncInterval, scheduler.idleInterval);
|
|
|
|
_("Test non-idle, numClients > 1, no incoming items => activeInterval.");
|
|
// idle == false && numClients > 1 && hasIncomingItems == false
|
|
scheduler.idle = false;
|
|
await Service.sync();
|
|
Assert.equal(syncSuccesses, 7);
|
|
Assert.ok(!scheduler.idle);
|
|
Assert.ok(scheduler.numClients > 1);
|
|
Assert.ok(!scheduler.hasIncomingItems);
|
|
Assert.equal(scheduler.syncInterval, scheduler.activeInterval);
|
|
|
|
_("Test non-idle, numClients > 1, incoming items => immediateInterval.");
|
|
// idle == false && numClients > 1 && hasIncomingItems == true
|
|
scheduler.hasIncomingItems = true;
|
|
await Service.sync();
|
|
Assert.equal(syncSuccesses, 8);
|
|
Assert.ok(!scheduler.idle);
|
|
Assert.ok(scheduler.numClients > 1);
|
|
Assert.ok(!scheduler.hasIncomingItems); // gets reset to false
|
|
Assert.equal(scheduler.syncInterval, scheduler.immediateInterval);
|
|
|
|
Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
|
|
await Service.startOver();
|
|
await promiseStopServer(server);
|
|
});
|
|
|
|
add_task(async function test_unsuccessful_sync_adjustSyncInterval() {
|
|
enableValidationPrefs();
|
|
|
|
_("Test unsuccessful sync calling adjustSyncInterval");
|
|
|
|
let syncFailures = 0;
|
|
function onSyncError() {
|
|
_("Sync error.");
|
|
syncFailures++;
|
|
}
|
|
Svc.Obs.add("weave:service:sync:error", onSyncError);
|
|
|
|
_("Test unsuccessful sync calls adjustSyncInterval");
|
|
// Force sync to fail.
|
|
Svc.PrefBranch.setStringPref("firstSync", "notReady");
|
|
|
|
let server = await sync_httpd_setup();
|
|
await setUp(server);
|
|
|
|
// Confirm defaults
|
|
Assert.ok(!scheduler.idle);
|
|
Assert.equal(false, scheduler.numClients > 1);
|
|
Assert.equal(scheduler.syncInterval, scheduler.singleDeviceInterval);
|
|
Assert.ok(!scheduler.hasIncomingItems);
|
|
|
|
_("Test as long as numClients <= 1 our sync interval is SINGLE_USER.");
|
|
// idle == true && numClients <= 1 && hasIncomingItems == false
|
|
scheduler.idle = true;
|
|
await Service.sync();
|
|
Assert.equal(syncFailures, 1);
|
|
Assert.ok(scheduler.idle);
|
|
Assert.equal(false, scheduler.numClients > 1);
|
|
Assert.ok(!scheduler.hasIncomingItems);
|
|
Assert.equal(scheduler.syncInterval, scheduler.singleDeviceInterval);
|
|
|
|
// idle == false && numClients <= 1 && hasIncomingItems == false
|
|
scheduler.idle = false;
|
|
await Service.sync();
|
|
Assert.equal(syncFailures, 2);
|
|
Assert.ok(!scheduler.idle);
|
|
Assert.equal(false, scheduler.numClients > 1);
|
|
Assert.ok(!scheduler.hasIncomingItems);
|
|
Assert.equal(scheduler.syncInterval, scheduler.singleDeviceInterval);
|
|
|
|
// idle == false && numClients <= 1 && hasIncomingItems == true
|
|
scheduler.hasIncomingItems = true;
|
|
await Service.sync();
|
|
Assert.equal(syncFailures, 3);
|
|
Assert.ok(!scheduler.idle);
|
|
Assert.equal(false, scheduler.numClients > 1);
|
|
Assert.ok(scheduler.hasIncomingItems);
|
|
Assert.equal(scheduler.syncInterval, scheduler.singleDeviceInterval);
|
|
|
|
// idle == true && numClients <= 1 && hasIncomingItems == true
|
|
scheduler.idle = true;
|
|
await Service.sync();
|
|
Assert.equal(syncFailures, 4);
|
|
Assert.ok(scheduler.idle);
|
|
Assert.equal(false, scheduler.numClients > 1);
|
|
Assert.ok(scheduler.hasIncomingItems);
|
|
Assert.equal(scheduler.syncInterval, scheduler.singleDeviceInterval);
|
|
|
|
_(
|
|
"Test as long as idle && numClients > 1 our sync interval is idleInterval."
|
|
);
|
|
// idle == true && numClients > 1 && hasIncomingItems == true
|
|
Svc.PrefBranch.setIntPref("clients.devices.mobile", 2);
|
|
scheduler.updateClientMode();
|
|
|
|
await Service.sync();
|
|
Assert.equal(syncFailures, 5);
|
|
Assert.ok(scheduler.idle);
|
|
Assert.ok(scheduler.numClients > 1);
|
|
Assert.ok(scheduler.hasIncomingItems);
|
|
Assert.equal(scheduler.syncInterval, scheduler.idleInterval);
|
|
|
|
// idle == true && numClients > 1 && hasIncomingItems == false
|
|
scheduler.hasIncomingItems = false;
|
|
await Service.sync();
|
|
Assert.equal(syncFailures, 6);
|
|
Assert.ok(scheduler.idle);
|
|
Assert.ok(scheduler.numClients > 1);
|
|
Assert.ok(!scheduler.hasIncomingItems);
|
|
Assert.equal(scheduler.syncInterval, scheduler.idleInterval);
|
|
|
|
_("Test non-idle, numClients > 1, no incoming items => activeInterval.");
|
|
// idle == false && numClients > 1 && hasIncomingItems == false
|
|
scheduler.idle = false;
|
|
await Service.sync();
|
|
Assert.equal(syncFailures, 7);
|
|
Assert.ok(!scheduler.idle);
|
|
Assert.ok(scheduler.numClients > 1);
|
|
Assert.ok(!scheduler.hasIncomingItems);
|
|
Assert.equal(scheduler.syncInterval, scheduler.activeInterval);
|
|
|
|
_("Test non-idle, numClients > 1, incoming items => immediateInterval.");
|
|
// idle == false && numClients > 1 && hasIncomingItems == true
|
|
scheduler.hasIncomingItems = true;
|
|
await Service.sync();
|
|
Assert.equal(syncFailures, 8);
|
|
Assert.ok(!scheduler.idle);
|
|
Assert.ok(scheduler.numClients > 1);
|
|
Assert.ok(!scheduler.hasIncomingItems); // gets reset to false
|
|
Assert.equal(scheduler.syncInterval, scheduler.immediateInterval);
|
|
|
|
await Service.startOver();
|
|
Svc.Obs.remove("weave:service:sync:error", onSyncError);
|
|
await promiseStopServer(server);
|
|
});
|
|
|
|
add_task(async function test_back_triggers_sync() {
|
|
enableValidationPrefs();
|
|
|
|
let server = await sync_httpd_setup();
|
|
await setUp(server);
|
|
|
|
// Single device: no sync triggered.
|
|
scheduler.idle = true;
|
|
scheduler.observe(
|
|
null,
|
|
"active",
|
|
Svc.PrefBranch.getIntPref("scheduler.idleTime")
|
|
);
|
|
Assert.ok(!scheduler.idle);
|
|
|
|
// Multiple devices: sync is triggered.
|
|
Svc.PrefBranch.setIntPref("clients.devices.mobile", 2);
|
|
scheduler.updateClientMode();
|
|
|
|
let promiseDone = promiseOneObserver("weave:service:sync:finish");
|
|
|
|
scheduler.idle = true;
|
|
scheduler.observe(
|
|
null,
|
|
"active",
|
|
Svc.PrefBranch.getIntPref("scheduler.idleTime")
|
|
);
|
|
Assert.ok(!scheduler.idle);
|
|
await promiseDone;
|
|
|
|
Service.recordManager.clearCache();
|
|
for (const pref of Svc.PrefBranch.getChildList("")) {
|
|
Svc.PrefBranch.clearUserPref(pref);
|
|
}
|
|
scheduler.setDefaults();
|
|
await clientsEngine.resetClient();
|
|
|
|
await Service.startOver();
|
|
await promiseStopServer(server);
|
|
});
|
|
|
|
add_task(async function test_adjust_interval_on_sync_error() {
|
|
enableValidationPrefs();
|
|
|
|
let server = await sync_httpd_setup();
|
|
await setUp(server);
|
|
|
|
let syncFailures = 0;
|
|
function onSyncError() {
|
|
_("Sync error.");
|
|
syncFailures++;
|
|
}
|
|
Svc.Obs.add("weave:service:sync:error", onSyncError);
|
|
|
|
_("Test unsuccessful sync updates client mode & sync intervals");
|
|
// Force a sync fail.
|
|
Svc.PrefBranch.setStringPref("firstSync", "notReady");
|
|
|
|
Assert.equal(syncFailures, 0);
|
|
Assert.equal(false, scheduler.numClients > 1);
|
|
Assert.equal(scheduler.syncInterval, scheduler.singleDeviceInterval);
|
|
|
|
Svc.PrefBranch.setIntPref("clients.devices.mobile", 2);
|
|
await Service.sync();
|
|
|
|
Assert.equal(syncFailures, 1);
|
|
Assert.ok(scheduler.numClients > 1);
|
|
Assert.equal(scheduler.syncInterval, scheduler.activeInterval);
|
|
|
|
Svc.Obs.remove("weave:service:sync:error", onSyncError);
|
|
await Service.startOver();
|
|
await promiseStopServer(server);
|
|
});
|
|
|
|
add_task(async function test_bug671378_scenario() {
|
|
enableValidationPrefs();
|
|
|
|
// Test scenario similar to bug 671378. This bug appeared when a score
|
|
// update occurred that wasn't large enough to trigger a sync so
|
|
// scheduleNextSync() was called without a time interval parameter,
|
|
// setting nextSync to a non-zero value and preventing the timer from
|
|
// being adjusted in the next call to scheduleNextSync().
|
|
let server = await sync_httpd_setup();
|
|
await setUp(server);
|
|
|
|
let syncSuccesses = 0;
|
|
function onSyncFinish() {
|
|
_("Sync success.");
|
|
syncSuccesses++;
|
|
}
|
|
Svc.Obs.add("weave:service:sync:finish", onSyncFinish);
|
|
|
|
// After first sync call, syncInterval & syncTimer are singleDeviceInterval.
|
|
await Service.sync();
|
|
Assert.equal(syncSuccesses, 1);
|
|
Assert.equal(false, scheduler.numClients > 1);
|
|
Assert.equal(scheduler.syncInterval, scheduler.singleDeviceInterval);
|
|
Assert.equal(scheduler.syncTimer.delay, scheduler.singleDeviceInterval);
|
|
|
|
let promiseDone = new Promise(resolve => {
|
|
// Wrap scheduleNextSync so we are notified when it is finished.
|
|
scheduler._scheduleNextSync = scheduler.scheduleNextSync;
|
|
scheduler.scheduleNextSync = function () {
|
|
scheduler._scheduleNextSync();
|
|
|
|
// Check on sync:finish scheduleNextSync sets the appropriate
|
|
// syncInterval and syncTimer values.
|
|
if (syncSuccesses == 2) {
|
|
Assert.notEqual(scheduler.nextSync, 0);
|
|
Assert.equal(scheduler.syncInterval, scheduler.activeInterval);
|
|
Assert.ok(scheduler.syncTimer.delay <= scheduler.activeInterval);
|
|
|
|
scheduler.scheduleNextSync = scheduler._scheduleNextSync;
|
|
Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
|
|
Service.startOver().then(() => {
|
|
server.stop(resolve);
|
|
});
|
|
}
|
|
};
|
|
});
|
|
|
|
// Set nextSync != 0
|
|
// syncInterval still hasn't been set by call to updateClientMode.
|
|
// Explicitly trying to invoke scheduleNextSync during a sync
|
|
// (to immitate a score update that isn't big enough to trigger a sync).
|
|
Svc.Obs.add("weave:service:sync:start", function onSyncStart() {
|
|
// Wait for other sync:start observers to be called so that
|
|
// nextSync is set to 0.
|
|
CommonUtils.nextTick(function () {
|
|
Svc.Obs.remove("weave:service:sync:start", onSyncStart);
|
|
|
|
scheduler.scheduleNextSync();
|
|
Assert.notEqual(scheduler.nextSync, 0);
|
|
Assert.equal(scheduler.syncInterval, scheduler.singleDeviceInterval);
|
|
Assert.equal(scheduler.syncTimer.delay, scheduler.singleDeviceInterval);
|
|
});
|
|
});
|
|
|
|
await Service.clientsEngine._store.create({
|
|
id: "foo",
|
|
cleartext: { name: "bar", type: "mobile" },
|
|
});
|
|
await Service.sync();
|
|
await promiseDone;
|
|
});
|
|
|
|
add_task(async function test_adjust_timer_larger_syncInterval() {
|
|
_(
|
|
"Test syncInterval > current timout period && nextSync != 0, syncInterval is NOT used."
|
|
);
|
|
Svc.PrefBranch.setIntPref("clients.devices.mobile", 2);
|
|
scheduler.updateClientMode();
|
|
Assert.equal(scheduler.syncInterval, scheduler.activeInterval);
|
|
|
|
scheduler.scheduleNextSync();
|
|
|
|
// Ensure we have a small interval.
|
|
Assert.notEqual(scheduler.nextSync, 0);
|
|
Assert.equal(scheduler.syncTimer.delay, scheduler.activeInterval);
|
|
|
|
// Make interval large again
|
|
await clientsEngine._wipeClient();
|
|
Svc.PrefBranch.clearUserPref("clients.devices.mobile");
|
|
scheduler.updateClientMode();
|
|
Assert.equal(scheduler.syncInterval, scheduler.singleDeviceInterval);
|
|
|
|
scheduler.scheduleNextSync();
|
|
|
|
// Ensure timer delay remains as the small interval.
|
|
Assert.notEqual(scheduler.nextSync, 0);
|
|
Assert.ok(scheduler.syncTimer.delay <= scheduler.activeInterval);
|
|
|
|
// SyncSchedule.
|
|
await Service.startOver();
|
|
});
|
|
|
|
add_task(async function test_adjust_timer_smaller_syncInterval() {
|
|
_(
|
|
"Test current timout > syncInterval period && nextSync != 0, syncInterval is used."
|
|
);
|
|
scheduler.scheduleNextSync();
|
|
|
|
// Ensure we have a large interval.
|
|
Assert.notEqual(scheduler.nextSync, 0);
|
|
Assert.equal(scheduler.syncTimer.delay, scheduler.singleDeviceInterval);
|
|
|
|
// Make interval smaller
|
|
Svc.PrefBranch.setIntPref("clients.devices.mobile", 2);
|
|
scheduler.updateClientMode();
|
|
Assert.equal(scheduler.syncInterval, scheduler.activeInterval);
|
|
|
|
scheduler.scheduleNextSync();
|
|
|
|
// Ensure smaller timer delay is used.
|
|
Assert.notEqual(scheduler.nextSync, 0);
|
|
Assert.ok(scheduler.syncTimer.delay <= scheduler.activeInterval);
|
|
|
|
// SyncSchedule.
|
|
await Service.startOver();
|
|
});
|