gecko/services/sync/tests/unit/test_interval_triggers.js
Gregory Szorc 58bcd2801d Bug 787273 - Part 2: Refactor Resource and Record to not rely on singletons; r=rnewman
Resource currently relies on the Identity singleton to perform
authentication. This is bad magic behavior. Resource instances should
authenticate according to the service instance they are associated with.

This patch removes Identity magic from Resource. Everything using
Resource now explicitly assigns an authenticator which comes from
the service instance/singleton. This required API changes to Collection
and Record.

The preferred method to obtain a Resource instance is to call
getResource() on a service instance.

The end result of this patch looks a little weird, especially in test
code. You have things like Service.resource(Service.cryptoKeysURL).
This ugliness will go away when a unified storage service client is
used.
2012-09-14 16:02:32 -07:00

435 lines
15 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");
Svc.DefaultPrefs.set("registerEngines", "");
Cu.import("resource://services-sync/service.js");
let scheduler = Service.scheduler;
let clientsEngine = Service.clientsEngine;
function sync_httpd_setup() {
let global = new ServerWBO("global", {
syncID: Service.syncID,
storageVersion: STORAGE_VERSION,
engines: {clients: {version: clientsEngine.version,
syncID: clientsEngine.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() {
setBasicCredentials("johndoe", "ilovejane", "abcdeabcdeabcdeabcdeabcdea");
Service.serverURL = TEST_SERVER_URL;
Service.clusterURL = TEST_CLUSTER_URL;
generateNewKeys();
let serverKeys = CollectionKeys.asWBO("crypto", "keys");
serverKeys.encrypt(Identity.syncKeyBundle);
return serverKeys.upload(Service.resource(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(scheduler.idle);
do_check_false(scheduler.numClients > 1);
do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
do_check_false(scheduler.hasIncomingItems);
_("Test as long as numClients <= 1 our sync interval is SINGLE_USER.");
// idle == true && numClients <= 1 && hasIncomingItems == false
scheduler.idle = true;
Service.sync();
do_check_eq(syncSuccesses, 1);
do_check_true(scheduler.idle);
do_check_false(scheduler.numClients > 1);
do_check_false(scheduler.hasIncomingItems);
do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
// idle == false && numClients <= 1 && hasIncomingItems == false
scheduler.idle = false;
Service.sync();
do_check_eq(syncSuccesses, 2);
do_check_false(scheduler.idle);
do_check_false(scheduler.numClients > 1);
do_check_false(scheduler.hasIncomingItems);
do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
// idle == false && numClients <= 1 && hasIncomingItems == true
scheduler.hasIncomingItems = true;
Service.sync();
do_check_eq(syncSuccesses, 3);
do_check_false(scheduler.idle);
do_check_false(scheduler.numClients > 1);
do_check_true(scheduler.hasIncomingItems);
do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
// idle == true && numClients <= 1 && hasIncomingItems == true
scheduler.idle = true;
Service.sync();
do_check_eq(syncSuccesses, 4);
do_check_true(scheduler.idle);
do_check_false(scheduler.numClients > 1);
do_check_true(scheduler.hasIncomingItems);
do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
_("Test as long as idle && numClients > 1 our sync interval is idleInterval.");
// idle == true && numClients > 1 && hasIncomingItems == true
Service.clientsEngine._store.create({id: "foo", cleartext: "bar"});
Service.sync();
do_check_eq(syncSuccesses, 5);
do_check_true(scheduler.idle);
do_check_true(scheduler.numClients > 1);
do_check_true(scheduler.hasIncomingItems);
do_check_eq(scheduler.syncInterval, scheduler.idleInterval);
// idle == true && numClients > 1 && hasIncomingItems == false
scheduler.hasIncomingItems = false;
Service.sync();
do_check_eq(syncSuccesses, 6);
do_check_true(scheduler.idle);
do_check_true(scheduler.numClients > 1);
do_check_false(scheduler.hasIncomingItems);
do_check_eq(scheduler.syncInterval, scheduler.idleInterval);
_("Test non-idle, numClients > 1, no incoming items => activeInterval.");
// idle == false && numClients > 1 && hasIncomingItems == false
scheduler.idle = false;
Service.sync();
do_check_eq(syncSuccesses, 7);
do_check_false(scheduler.idle);
do_check_true(scheduler.numClients > 1);
do_check_false(scheduler.hasIncomingItems);
do_check_eq(scheduler.syncInterval, scheduler.activeInterval);
_("Test non-idle, numClients > 1, incoming items => immediateInterval.");
// idle == false && numClients > 1 && hasIncomingItems == true
scheduler.hasIncomingItems = true;
Service.sync();
do_check_eq(syncSuccesses, 8);
do_check_false(scheduler.idle);
do_check_true(scheduler.numClients > 1);
do_check_false(scheduler.hasIncomingItems); //gets reset to false
do_check_eq(scheduler.syncInterval, scheduler.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(scheduler.idle);
do_check_false(scheduler.numClients > 1);
do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
do_check_false(scheduler.hasIncomingItems);
_("Test as long as numClients <= 1 our sync interval is SINGLE_USER.");
// idle == true && numClients <= 1 && hasIncomingItems == false
scheduler.idle = true;
Service.sync();
do_check_eq(syncFailures, 1);
do_check_true(scheduler.idle);
do_check_false(scheduler.numClients > 1);
do_check_false(scheduler.hasIncomingItems);
do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
// idle == false && numClients <= 1 && hasIncomingItems == false
scheduler.idle = false;
Service.sync();
do_check_eq(syncFailures, 2);
do_check_false(scheduler.idle);
do_check_false(scheduler.numClients > 1);
do_check_false(scheduler.hasIncomingItems);
do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
// idle == false && numClients <= 1 && hasIncomingItems == true
scheduler.hasIncomingItems = true;
Service.sync();
do_check_eq(syncFailures, 3);
do_check_false(scheduler.idle);
do_check_false(scheduler.numClients > 1);
do_check_true(scheduler.hasIncomingItems);
do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
// idle == true && numClients <= 1 && hasIncomingItems == true
scheduler.idle = true;
Service.sync();
do_check_eq(syncFailures, 4);
do_check_true(scheduler.idle);
do_check_false(scheduler.numClients > 1);
do_check_true(scheduler.hasIncomingItems);
do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
_("Test as long as idle && numClients > 1 our sync interval is idleInterval.");
// idle == true && numClients > 1 && hasIncomingItems == true
Service.clientsEngine._store.create({id: "foo", cleartext: "bar"});
Service.sync();
do_check_eq(syncFailures, 5);
do_check_true(scheduler.idle);
do_check_true(scheduler.numClients > 1);
do_check_true(scheduler.hasIncomingItems);
do_check_eq(scheduler.syncInterval, scheduler.idleInterval);
// idle == true && numClients > 1 && hasIncomingItems == false
scheduler.hasIncomingItems = false;
Service.sync();
do_check_eq(syncFailures, 6);
do_check_true(scheduler.idle);
do_check_true(scheduler.numClients > 1);
do_check_false(scheduler.hasIncomingItems);
do_check_eq(scheduler.syncInterval, scheduler.idleInterval);
_("Test non-idle, numClients > 1, no incoming items => activeInterval.");
// idle == false && numClients > 1 && hasIncomingItems == false
scheduler.idle = false;
Service.sync();
do_check_eq(syncFailures, 7);
do_check_false(scheduler.idle);
do_check_true(scheduler.numClients > 1);
do_check_false(scheduler.hasIncomingItems);
do_check_eq(scheduler.syncInterval, scheduler.activeInterval);
_("Test non-idle, numClients > 1, incoming items => immediateInterval.");
// idle == false && numClients > 1 && hasIncomingItems == true
scheduler.hasIncomingItems = true;
Service.sync();
do_check_eq(syncFailures, 8);
do_check_false(scheduler.idle);
do_check_true(scheduler.numClients > 1);
do_check_false(scheduler.hasIncomingItems); //gets reset to false
do_check_eq(scheduler.syncInterval, scheduler.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.
scheduler.idle = true;
scheduler.observe(null, "back", Svc.Prefs.get("scheduler.idleTime"));
do_check_false(scheduler.idle);
// Multiple devices: sync is triggered.
clientsEngine._store.create({id: "foo", cleartext: "bar"});
scheduler.updateClientMode();
Svc.Obs.add("weave:service:sync:finish", function onSyncFinish() {
Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
Service.recordManager.clearCache();
Svc.Prefs.resetBranch("");
scheduler.setDefaults();
clientsEngine.resetClient();
Service.startOver();
server.stop(run_next_test);
});
scheduler.idle = true;
scheduler.observe(null, "back", Svc.Prefs.get("scheduler.idleTime"));
do_check_false(scheduler.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(scheduler.numClients > 1);
do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
clientsEngine._store.create({id: "foo", cleartext: "bar"});
Service.sync();
do_check_eq(syncFailures, 1);
do_check_true(scheduler.numClients > 1);
do_check_eq(scheduler.syncInterval, scheduler.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(scheduler.numClients > 1);
do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
do_check_eq(scheduler.syncTimer.delay, scheduler.singleDeviceInterval);
// 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) {
do_check_neq(scheduler.nextSync, 0);
do_check_eq(scheduler.syncInterval, scheduler.activeInterval);
do_check_true(scheduler.syncTimer.delay <= scheduler.activeInterval);
scheduler.scheduleNextSync = scheduler._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);
scheduler.scheduleNextSync();
do_check_neq(scheduler.nextSync, 0);
do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
do_check_eq(scheduler.syncTimer.delay, scheduler.singleDeviceInterval);
});
});
clientsEngine._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.");
clientsEngine._store.create({id: "foo", cleartext: "bar"});
scheduler.updateClientMode();
do_check_eq(scheduler.syncInterval, scheduler.activeInterval);
scheduler.scheduleNextSync();
// Ensure we have a small interval.
do_check_neq(scheduler.nextSync, 0);
do_check_eq(scheduler.syncTimer.delay, scheduler.activeInterval);
// Make interval large again
clientsEngine._wipeClient();
scheduler.updateClientMode();
do_check_eq(scheduler.syncInterval, scheduler.singleDeviceInterval);
scheduler.scheduleNextSync();
// Ensure timer delay remains as the small interval.
do_check_neq(scheduler.nextSync, 0);
do_check_true(scheduler.syncTimer.delay <= scheduler.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.");
scheduler.scheduleNextSync();
// Ensure we have a large interval.
do_check_neq(scheduler.nextSync, 0);
do_check_eq(scheduler.syncTimer.delay, scheduler.singleDeviceInterval);
// Make interval smaller
clientsEngine._store.create({id: "foo", cleartext: "bar"});
scheduler.updateClientMode();
do_check_eq(scheduler.syncInterval, scheduler.activeInterval);
scheduler.scheduleNextSync();
// Ensure smaller timer delay is used.
do_check_neq(scheduler.nextSync, 0);
do_check_true(scheduler.syncTimer.delay <= scheduler.activeInterval);
//SyncSchedule.
Service.startOver();
run_next_test();
});