gecko/services/sync/tests/unit/test_interval_triggers.js

434 lines
16 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource://services-sync/engines.js");
Cu.import("resource://services-sync/engines/clients.js");
Cu.import("resource://services-sync/constants.js");
Cu.import("resource://services-sync/policies.js");
Svc.DefaultPrefs.set("registerEngines", "");
Cu.import("resource://services-sync/service.js");
function sync_httpd_setup() {
let global = new ServerWBO("global", {
syncID: Service.syncID,
storageVersion: STORAGE_VERSION,
engines: {clients: {version: Clients.version,
syncID: Clients.syncID}}
});
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())
});
}
function setUp() {
Service.username = "johndoe";
Service.password = "ilovejane";
Service.passphrase = "abcdeabcdeabcdeabcdeabcdea";
Service.clusterURL = "http://localhost:8080/";
generateNewKeys();
let serverKeys = CollectionKeys.asWBO("crypto", "keys");
serverKeys.encrypt(Service.syncKeyBundle);
return serverKeys.upload(Service.cryptoKeysURL);
}
function run_test() {
initTestLogging("Trace");
Log4Moz.repository.getLogger("Sync.Service").level = Log4Moz.Level.Trace;
Log4Moz.repository.getLogger("Sync.SyncScheduler").level = Log4Moz.Level.Trace;
run_next_test();
}
add_test(function test_successful_sync_adjustSyncInterval() {
_("Test successful sync calling adjustSyncInterval");
let syncSuccesses = 0;
function onSyncFinish() {
_("Sync success.");
syncSuccesses++;
};
Svc.Obs.add("weave:service:sync:finish", onSyncFinish);
let server = sync_httpd_setup();
setUp();
// Confirm defaults
do_check_false(SyncScheduler.idle);
do_check_false(SyncScheduler.numClients > 1);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
do_check_false(SyncScheduler.hasIncomingItems);
_("Test as long as numClients <= 1 our sync interval is SINGLE_USER.");
// idle == true && numClients <= 1 && hasIncomingItems == false
SyncScheduler.idle = true;
Service.sync();
do_check_eq(syncSuccesses, 1);
do_check_true(SyncScheduler.idle);
do_check_false(SyncScheduler.numClients > 1);
do_check_false(SyncScheduler.hasIncomingItems);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
// idle == false && numClients <= 1 && hasIncomingItems == false
SyncScheduler.idle = false;
Service.sync();
do_check_eq(syncSuccesses, 2);
do_check_false(SyncScheduler.idle);
do_check_false(SyncScheduler.numClients > 1);
do_check_false(SyncScheduler.hasIncomingItems);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
// idle == false && numClients <= 1 && hasIncomingItems == true
SyncScheduler.hasIncomingItems = true;
Service.sync();
do_check_eq(syncSuccesses, 3);
do_check_false(SyncScheduler.idle);
do_check_false(SyncScheduler.numClients > 1);
do_check_true(SyncScheduler.hasIncomingItems);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
// idle == true && numClients <= 1 && hasIncomingItems == true
SyncScheduler.idle = true;
Service.sync();
do_check_eq(syncSuccesses, 4);
do_check_true(SyncScheduler.idle);
do_check_false(SyncScheduler.numClients > 1);
do_check_true(SyncScheduler.hasIncomingItems);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
_("Test as long as idle && numClients > 1 our sync interval is idleInterval.");
// idle == true && numClients > 1 && hasIncomingItems == true
Clients._store.create({id: "foo", cleartext: "bar"});
Service.sync();
do_check_eq(syncSuccesses, 5);
do_check_true(SyncScheduler.idle);
do_check_true(SyncScheduler.numClients > 1);
do_check_true(SyncScheduler.hasIncomingItems);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.idleInterval);
// idle == true && numClients > 1 && hasIncomingItems == false
SyncScheduler.hasIncomingItems = false;
Service.sync();
do_check_eq(syncSuccesses, 6);
do_check_true(SyncScheduler.idle);
do_check_true(SyncScheduler.numClients > 1);
do_check_false(SyncScheduler.hasIncomingItems);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.idleInterval);
_("Test non-idle, numClients > 1, no incoming items => activeInterval.");
// idle == false && numClients > 1 && hasIncomingItems == false
SyncScheduler.idle = false;
Service.sync();
do_check_eq(syncSuccesses, 7);
do_check_false(SyncScheduler.idle);
do_check_true(SyncScheduler.numClients > 1);
do_check_false(SyncScheduler.hasIncomingItems);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.activeInterval);
_("Test non-idle, numClients > 1, incoming items => immediateInterval.");
// idle == false && numClients > 1 && hasIncomingItems == true
SyncScheduler.hasIncomingItems = true;
Service.sync();
do_check_eq(syncSuccesses, 8);
do_check_false(SyncScheduler.idle);
do_check_true(SyncScheduler.numClients > 1);
do_check_false(SyncScheduler.hasIncomingItems); //gets reset to false
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.immediateInterval);
Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
Service.startOver();
server.stop(run_next_test);
});
add_test(function test_unsuccessful_sync_adjustSyncInterval() {
_("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.Prefs.set("firstSync", "notReady");
let server = sync_httpd_setup();
setUp();
// Confirm defaults
do_check_false(SyncScheduler.idle);
do_check_false(SyncScheduler.numClients > 1);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
do_check_false(SyncScheduler.hasIncomingItems);
_("Test as long as numClients <= 1 our sync interval is SINGLE_USER.");
// idle == true && numClients <= 1 && hasIncomingItems == false
SyncScheduler.idle = true;
Service.sync();
do_check_eq(syncFailures, 1);
do_check_true(SyncScheduler.idle);
do_check_false(SyncScheduler.numClients > 1);
do_check_false(SyncScheduler.hasIncomingItems);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
// idle == false && numClients <= 1 && hasIncomingItems == false
SyncScheduler.idle = false;
Service.sync();
do_check_eq(syncFailures, 2);
do_check_false(SyncScheduler.idle);
do_check_false(SyncScheduler.numClients > 1);
do_check_false(SyncScheduler.hasIncomingItems);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
// idle == false && numClients <= 1 && hasIncomingItems == true
SyncScheduler.hasIncomingItems = true;
Service.sync();
do_check_eq(syncFailures, 3);
do_check_false(SyncScheduler.idle);
do_check_false(SyncScheduler.numClients > 1);
do_check_true(SyncScheduler.hasIncomingItems);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
// idle == true && numClients <= 1 && hasIncomingItems == true
SyncScheduler.idle = true;
Service.sync();
do_check_eq(syncFailures, 4);
do_check_true(SyncScheduler.idle);
do_check_false(SyncScheduler.numClients > 1);
do_check_true(SyncScheduler.hasIncomingItems);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
_("Test as long as idle && numClients > 1 our sync interval is idleInterval.");
// idle == true && numClients > 1 && hasIncomingItems == true
Clients._store.create({id: "foo", cleartext: "bar"});
Service.sync();
do_check_eq(syncFailures, 5);
do_check_true(SyncScheduler.idle);
do_check_true(SyncScheduler.numClients > 1);
do_check_true(SyncScheduler.hasIncomingItems);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.idleInterval);
// idle == true && numClients > 1 && hasIncomingItems == false
SyncScheduler.hasIncomingItems = false;
Service.sync();
do_check_eq(syncFailures, 6);
do_check_true(SyncScheduler.idle);
do_check_true(SyncScheduler.numClients > 1);
do_check_false(SyncScheduler.hasIncomingItems);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.idleInterval);
_("Test non-idle, numClients > 1, no incoming items => activeInterval.");
// idle == false && numClients > 1 && hasIncomingItems == false
SyncScheduler.idle = false;
Service.sync();
do_check_eq(syncFailures, 7);
do_check_false(SyncScheduler.idle);
do_check_true(SyncScheduler.numClients > 1);
do_check_false(SyncScheduler.hasIncomingItems);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.activeInterval);
_("Test non-idle, numClients > 1, incoming items => immediateInterval.");
// idle == false && numClients > 1 && hasIncomingItems == true
SyncScheduler.hasIncomingItems = true;
Service.sync();
do_check_eq(syncFailures, 8);
do_check_false(SyncScheduler.idle);
do_check_true(SyncScheduler.numClients > 1);
do_check_false(SyncScheduler.hasIncomingItems); //gets reset to false
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.immediateInterval);
Service.startOver();
Svc.Obs.remove("weave:service:sync:error", onSyncError);
server.stop(run_next_test);
});
add_test(function test_back_triggers_sync() {
let server = sync_httpd_setup();
setUp();
// Single device: no sync triggered.
SyncScheduler.idle = true;
SyncScheduler.observe(null, "back", Svc.Prefs.get("scheduler.idleTime"));
do_check_false(SyncScheduler.idle);
// Multiple devices: sync is triggered.
Clients._store.create({id: "foo", cleartext: "bar"});
SyncScheduler.updateClientMode();
Svc.Obs.add("weave:service:sync:finish", function onSyncFinish() {
Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
Records.clearCache();
Svc.Prefs.resetBranch("");
SyncScheduler.setDefaults();
Clients.resetClient();
Service.startOver();
server.stop(run_next_test);
});
SyncScheduler.idle = true;
SyncScheduler.observe(null, "back", Svc.Prefs.get("scheduler.idleTime"));
do_check_false(SyncScheduler.idle);
});
add_test(function test_adjust_interval_on_sync_error() {
let server = sync_httpd_setup();
setUp();
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.Prefs.set("firstSync", "notReady");
do_check_eq(syncFailures, 0);
do_check_false(SyncScheduler.numClients > 1);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
Clients._store.create({id: "foo", cleartext: "bar"});
Service.sync();
do_check_eq(syncFailures, 1);
do_check_true(SyncScheduler.numClients > 1);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.activeInterval);
Svc.Obs.remove("weave:service:sync:error", onSyncError);
Service.startOver();
server.stop(run_next_test);
});
add_test(function test_bug671378_scenario() {
// 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 = sync_httpd_setup();
setUp();
let syncSuccesses = 0;
function onSyncFinish() {
_("Sync success.");
syncSuccesses++;
};
Svc.Obs.add("weave:service:sync:finish", onSyncFinish);
// After first sync call, syncInterval & syncTimer are singleDeviceInterval.
Service.sync();
do_check_eq(syncSuccesses, 1);
do_check_false(SyncScheduler.numClients > 1);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
do_check_eq(SyncScheduler.syncTimer.delay, SyncScheduler.singleDeviceInterval);
// Wrap scheduleNextSync so we are notified when it is finished.
SyncScheduler._scheduleNextSync = SyncScheduler.scheduleNextSync;
SyncScheduler.scheduleNextSync = function() {
SyncScheduler._scheduleNextSync();
// Check on sync:finish scheduleNextSync sets the appropriate
// syncInterval and syncTimer values.
if (syncSuccesses == 2) {
do_check_neq(SyncScheduler.nextSync, 0);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.activeInterval);
do_check_true(SyncScheduler.syncTimer.delay <= SyncScheduler.activeInterval);
SyncScheduler.scheduleNextSync = SyncScheduler._scheduleNextSync;
Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
Service.startOver();
server.stop(run_next_test);
}
};
// 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.
Utils.nextTick(function() {
Svc.Obs.remove("weave:service:sync:start", onSyncStart);
SyncScheduler.scheduleNextSync();
do_check_neq(SyncScheduler.nextSync, 0);
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
do_check_eq(SyncScheduler.syncTimer.delay, SyncScheduler.singleDeviceInterval);
});
});
Clients._store.create({id: "foo", cleartext: "bar"});
Service.sync();
});
add_test(function test_adjust_timer_larger_syncInterval() {
_("Test syncInterval > current timout period && nextSync != 0, syncInterval is NOT used.");
Clients._store.create({id: "foo", cleartext: "bar"});
SyncScheduler.updateClientMode();
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.activeInterval);
SyncScheduler.scheduleNextSync();
// Ensure we have a small interval.
do_check_neq(SyncScheduler.nextSync, 0);
do_check_eq(SyncScheduler.syncTimer.delay, SyncScheduler.activeInterval);
// Make interval large again
Clients._wipeClient();
SyncScheduler.updateClientMode();
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.singleDeviceInterval);
SyncScheduler.scheduleNextSync();
// Ensure timer delay remains as the small interval.
do_check_neq(SyncScheduler.nextSync, 0);
do_check_true(SyncScheduler.syncTimer.delay <= SyncScheduler.activeInterval);
//SyncSchedule.
Service.startOver();
run_next_test();
});
add_test(function test_adjust_timer_smaller_syncInterval() {
_("Test current timout > syncInterval period && nextSync != 0, syncInterval is used.");
SyncScheduler.scheduleNextSync();
// Ensure we have a large interval.
do_check_neq(SyncScheduler.nextSync, 0);
do_check_eq(SyncScheduler.syncTimer.delay, SyncScheduler.singleDeviceInterval);
// Make interval smaller
Clients._store.create({id: "foo", cleartext: "bar"});
SyncScheduler.updateClientMode();
do_check_eq(SyncScheduler.syncInterval, SyncScheduler.activeInterval);
SyncScheduler.scheduleNextSync();
// Ensure smaller timer delay is used.
do_check_neq(SyncScheduler.nextSync, 0);
do_check_true(SyncScheduler.syncTimer.delay <= SyncScheduler.activeInterval);
//SyncSchedule.
Service.startOver();
run_next_test();
});