зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1901526 - Build out backup scheduling mechanism. r=backup-reviewers,kpatenio,sthompson
Differential Revision: https://phabricator.services.mozilla.com/D213468
This commit is contained in:
Родитель
5dc35d19c8
Коммит
16715733d3
|
@ -3119,6 +3119,8 @@ pref("browser.backup.preferences.ui.enabled", false);
|
|||
pref("browser.backup.sqlite.pages_per_step", 5);
|
||||
// The delay between SQLite database backup steps in milliseconds.
|
||||
pref("browser.backup.sqlite.step_delay_ms", 250);
|
||||
pref("browser.backup.scheduled.idle-threshold-seconds", 300);
|
||||
pref("browser.backup.scheduled.minimum-time-between-backups-seconds", 3600);
|
||||
|
||||
// Pref to enable the new profiles
|
||||
pref("browser.profiles.enabled", false);
|
||||
|
|
|
@ -15,6 +15,13 @@ import {
|
|||
|
||||
const BACKUP_DIR_PREF_NAME = "browser.backup.location";
|
||||
const SCHEDULED_BACKUPS_ENABLED_PREF_NAME = "browser.backup.scheduled.enabled";
|
||||
const IDLE_THRESHOLD_SECONDS_PREF_NAME =
|
||||
"browser.backup.scheduled.idle-threshold-seconds";
|
||||
const MINIMUM_TIME_BETWEEN_BACKUPS_SECONDS_PREF_NAME =
|
||||
"browser.backup.scheduled.minimum-time-between-backups-seconds";
|
||||
const LAST_BACKUP_TIMESTAMP_PREF_NAME =
|
||||
"browser.backup.scheduled.last-backup-timestamp";
|
||||
|
||||
const SCHEMAS = Object.freeze({
|
||||
BACKUP_MANIFEST: 1,
|
||||
ARCHIVE_JSON_BLOCK: 2,
|
||||
|
@ -121,6 +128,20 @@ XPCOMUtils.defineLazyPreferenceGetter(
|
|||
}
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
lazy,
|
||||
"minimumTimeBetweenBackupsSeconds",
|
||||
MINIMUM_TIME_BETWEEN_BACKUPS_SECONDS_PREF_NAME,
|
||||
3600 /* 1 hour */
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
lazy,
|
||||
"idleService",
|
||||
"@mozilla.org/widget/useridleservice;1",
|
||||
"nsIUserIdleService"
|
||||
);
|
||||
|
||||
/**
|
||||
* A class that wraps a multipart/mixed stream converter instance, and streams
|
||||
* in the binary part of a single-file archive (which should be at the second
|
||||
|
@ -542,6 +563,8 @@ export class BackupService extends EventTarget {
|
|||
backupInProgress: false,
|
||||
scheduledBackupsEnabled: lazy.scheduledBackupsPref,
|
||||
encryptionEnabled: false,
|
||||
/** @type {number?} Number of seconds since UNIX epoch */
|
||||
lastBackupDate: null,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -756,6 +779,7 @@ export class BackupService extends EventTarget {
|
|||
this.#instance.takeMeasurements();
|
||||
});
|
||||
|
||||
this.#instance.initBackupScheduler();
|
||||
return this.#instance;
|
||||
}
|
||||
|
||||
|
@ -1006,6 +1030,10 @@ export class BackupService extends EventTarget {
|
|||
manifest.meta
|
||||
);
|
||||
|
||||
let nowSeconds = Math.floor(Date.now() / 1000);
|
||||
Services.prefs.setIntPref(LAST_BACKUP_TIMESTAMP_PREF_NAME, nowSeconds);
|
||||
this.#_state.lastBackupDate = nowSeconds;
|
||||
|
||||
return {
|
||||
stagingPath: renamedStagingPath,
|
||||
compressedStagingPath,
|
||||
|
@ -2495,4 +2523,203 @@ export class BackupService extends EventTarget {
|
|||
this.#_state.encryptionEnabled = false;
|
||||
this.stateUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* The value of IDLE_THRESHOLD_SECONDS_PREF_NAME at the time that
|
||||
* initBackupScheduler was called. This is recorded so that if the preference
|
||||
* changes at runtime, that we properly remove the idle observer in
|
||||
* uninitBackupScheduler, since it's mapped to the idle time value.
|
||||
*
|
||||
* @see BackupService.initBackupScheduler()
|
||||
* @see BackupService.uninitBackupScheduler()
|
||||
* @type {number}
|
||||
*/
|
||||
#idleThresholdSeconds = null;
|
||||
|
||||
/**
|
||||
* An ES6 class that extends EventTarget cannot, apparently, be coerced into
|
||||
* a nsIObserver, even when we define QueryInterface. We work around this
|
||||
* limitation by having the observer be a function that we define at
|
||||
* registration time. We hold a reference to the observer so that we can
|
||||
* properly unregister.
|
||||
*
|
||||
* @see BackupService.initBackupScheduler()
|
||||
* @type {Function}
|
||||
*/
|
||||
#observer = null;
|
||||
|
||||
/**
|
||||
* True if the backup scheduler system has been initted via
|
||||
* initBackupScheduler().
|
||||
*
|
||||
* @see BackupService.initBackupScheduler()
|
||||
* @type {boolean}
|
||||
*/
|
||||
#backupSchedulerInitted = false;
|
||||
|
||||
/**
|
||||
* Initializes the backup scheduling system. This should be done shortly
|
||||
* after startup. It is exposed as a public method mainly for ease in testing.
|
||||
*
|
||||
* The scheduler will automatically uninitialize itself on the
|
||||
* quit-application-granted observer notification.
|
||||
*
|
||||
* @returns {Promise<undefined>}
|
||||
*/
|
||||
async initBackupScheduler() {
|
||||
if (this.#backupSchedulerInitted) {
|
||||
lazy.logConsole.warn(
|
||||
"BackupService scheduler already initting or initted."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.#backupSchedulerInitted = true;
|
||||
|
||||
let lastBackupPrefValue = Services.prefs.getIntPref(
|
||||
LAST_BACKUP_TIMESTAMP_PREF_NAME,
|
||||
0
|
||||
);
|
||||
if (!lastBackupPrefValue) {
|
||||
this.#_state.lastBackupDate = null;
|
||||
} else {
|
||||
this.#_state.lastBackupDate = lastBackupPrefValue;
|
||||
}
|
||||
|
||||
this.stateUpdate();
|
||||
|
||||
// We'll default to 5 minutes of idle time unless otherwise configured.
|
||||
const FIVE_MINUTES_IN_SECONDS = 5 * 60;
|
||||
|
||||
this.#idleThresholdSeconds = Services.prefs.getIntPref(
|
||||
IDLE_THRESHOLD_SECONDS_PREF_NAME,
|
||||
FIVE_MINUTES_IN_SECONDS
|
||||
);
|
||||
this.#observer = (subject, topic, data) => {
|
||||
this.onObserve(subject, topic, data);
|
||||
};
|
||||
lazy.logConsole.debug(
|
||||
`Registering idle observer for ${
|
||||
this.#idleThresholdSeconds
|
||||
} seconds of idle time`
|
||||
);
|
||||
lazy.idleService.addIdleObserver(
|
||||
this.#observer,
|
||||
this.#idleThresholdSeconds
|
||||
);
|
||||
lazy.logConsole.debug("Idle observer registered.");
|
||||
|
||||
Services.obs.addObserver(this.#observer, "quit-application-granted");
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninitializes the backup scheduling system.
|
||||
*
|
||||
* @returns {Promise<undefined>}
|
||||
*/
|
||||
async uninitBackupScheduler() {
|
||||
if (!this.#backupSchedulerInitted) {
|
||||
lazy.logConsole.warn(
|
||||
"Tried to uninitBackupScheduler when it wasn't yet enabled."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
lazy.idleService.removeIdleObserver(
|
||||
this.#observer,
|
||||
this.#idleThresholdSeconds
|
||||
);
|
||||
Services.obs.removeObserver(this.#observer, "quit-application-granted");
|
||||
this.#observer = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by this.#observer on idle from the nsIUserIdleService or
|
||||
* quit-application-granted from the nsIObserverService. Exposed as a public
|
||||
* method mainly for ease in testing.
|
||||
*
|
||||
* @param {nsISupports|null} _subject
|
||||
* The nsIUserIdleService for the idle notification, and null for the
|
||||
* quit-application-granted topic.
|
||||
* @param {string} topic
|
||||
* The topic that the notification belongs to.
|
||||
*/
|
||||
onObserve(_subject, topic) {
|
||||
switch (topic) {
|
||||
case "idle": {
|
||||
this.onIdle();
|
||||
break;
|
||||
}
|
||||
case "quit-application-granted": {
|
||||
this.uninitBackupScheduler();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the nsIUserIdleService reports that user input events have
|
||||
* not been sent to the application for at least
|
||||
* IDLE_THRESHOLD_SECONDS_PREF_NAME seconds.
|
||||
*/
|
||||
onIdle() {
|
||||
lazy.logConsole.debug("Saw idle callback");
|
||||
if (lazy.scheduledBackupsPref) {
|
||||
lazy.logConsole.debug("Scheduled backups enabled.");
|
||||
let now = Math.floor(Date.now() / 1000);
|
||||
let lastBackupDate = this.#_state.lastBackupDate;
|
||||
if (lastBackupDate && lastBackupDate > now) {
|
||||
lazy.logConsole.error(
|
||||
"Last backup was somehow in the future. Resetting the preference."
|
||||
);
|
||||
lastBackupDate = null;
|
||||
this.#_state.lastBackupDate = null;
|
||||
this.stateUpdate();
|
||||
}
|
||||
|
||||
if (!lastBackupDate) {
|
||||
lazy.logConsole.debug("No last backup time recorded in prefs.");
|
||||
} else {
|
||||
lazy.logConsole.debug(
|
||||
"Last backup was: ",
|
||||
new Date(lastBackupDate * 1000)
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
!lastBackupDate ||
|
||||
now - lastBackupDate > lazy.minimumTimeBetweenBackupsSeconds
|
||||
) {
|
||||
lazy.logConsole.debug(
|
||||
"Last backup exceeded minimum time between backups. Queing a " +
|
||||
"backup via idleDispatch."
|
||||
);
|
||||
// Just because the user hasn't sent us events in a while doesn't mean
|
||||
// that the browser itself isn't busy. It might be, for example, playing
|
||||
// video or doing a complex calculation that the user is actively
|
||||
// waiting to complete, and we don't want to draw resources from that.
|
||||
// Instead, we'll use ChromeUtils.idleDispatch to wait until the event
|
||||
// loop in the parent process isn't so busy with higher priority things.
|
||||
this.createBackupOnIdleDispatch();
|
||||
} else {
|
||||
lazy.logConsole.debug(
|
||||
"Last backup was too recent. Not creating one for now."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls BackupService.createBackup at the next moment when the event queue
|
||||
* is not busy with higher priority events. This is intentionally broken out
|
||||
* into its own method to make it easier to stub out in tests.
|
||||
*/
|
||||
createBackupOnIdleDispatch() {
|
||||
ChromeUtils.idleDispatch(() => {
|
||||
lazy.logConsole.debug(
|
||||
"idleDispatch fired. Attempting to create a backup."
|
||||
);
|
||||
this.createBackup();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,7 +115,9 @@ async function testCreateBackupHelper(sandbox, taskFn) {
|
|||
"createBackupTest"
|
||||
);
|
||||
|
||||
Assert.ok(!bs.state.lastBackupDate, "No backup date is stored in state.");
|
||||
await bs.createBackup({ profilePath: fakeProfilePath });
|
||||
Assert.ok(bs.state.lastBackupDate, "The backup date was recorded.");
|
||||
|
||||
// We expect the staging folder to exist then be renamed under the fakeProfilePath.
|
||||
// We should also find a folder for each fake BackupResource.
|
||||
|
|
|
@ -0,0 +1,300 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { MockRegistrar } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/MockRegistrar.sys.mjs"
|
||||
);
|
||||
|
||||
const SCHEDULED_BACKUPS_ENABLED_PREF_NAME = "browser.backup.scheduled.enabled";
|
||||
const IDLE_THRESHOLD_SECONDS_PREF_NAME =
|
||||
"browser.backup.scheduled.idle-threshold-seconds";
|
||||
const LAST_BACKUP_TIMESTAMP_PREF_NAME =
|
||||
"browser.backup.scheduled.last-backup-timestamp";
|
||||
const MINIMUM_TIME_BETWEEN_BACKUPS_SECONDS_PREF_NAME =
|
||||
"browser.backup.scheduled.minimum-time-between-backups-seconds";
|
||||
|
||||
/**
|
||||
* This is a very thin nsIUserIdleService implementation that doesn't do much,
|
||||
* but with sinon we can stub out some parts of it to make sure that the
|
||||
* BackupService uses it in the way we expect.
|
||||
*/
|
||||
let idleService = {
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIUserIdleService"]),
|
||||
idleTime: 19999,
|
||||
disabled: true,
|
||||
addIdleObserver() {},
|
||||
removeIdleObserver() {},
|
||||
};
|
||||
|
||||
add_setup(() => {
|
||||
let fakeIdleServiceCID = MockRegistrar.register(
|
||||
"@mozilla.org/widget/useridleservice;1",
|
||||
idleService
|
||||
);
|
||||
|
||||
Services.prefs.setBoolPref(SCHEDULED_BACKUPS_ENABLED_PREF_NAME, true);
|
||||
|
||||
// We'll pretend that our threshold between backups is 20 seconds.
|
||||
Services.prefs.setIntPref(MINIMUM_TIME_BETWEEN_BACKUPS_SECONDS_PREF_NAME, 20);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
MockRegistrar.unregister(fakeIdleServiceCID);
|
||||
Services.prefs.clearUserPref(SCHEDULED_BACKUPS_ENABLED_PREF_NAME);
|
||||
Services.prefs.clearUserPref(
|
||||
MINIMUM_TIME_BETWEEN_BACKUPS_SECONDS_PREF_NAME
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that calling initBackupScheduler registers a callback with the
|
||||
* nsIUserIdleService.
|
||||
*/
|
||||
add_task(async function test_init_uninitBackupScheduler() {
|
||||
let bs = new BackupService();
|
||||
let sandbox = sinon.createSandbox();
|
||||
sandbox.stub(idleService, "addIdleObserver");
|
||||
sandbox.stub(idleService, "removeIdleObserver");
|
||||
|
||||
await bs.initBackupScheduler();
|
||||
Assert.ok(
|
||||
idleService.addIdleObserver.calledOnce,
|
||||
"addIdleObserver was called"
|
||||
);
|
||||
Assert.ok(
|
||||
idleService.addIdleObserver.firstCall.args[0] instanceof Ci.nsIObserver,
|
||||
"The first argument to addIdleObserver was an nsIObserver"
|
||||
);
|
||||
const THRESHOLD_SECONDS = Services.prefs.getIntPref(
|
||||
IDLE_THRESHOLD_SECONDS_PREF_NAME
|
||||
);
|
||||
Assert.equal(
|
||||
idleService.addIdleObserver.firstCall.args[1],
|
||||
THRESHOLD_SECONDS,
|
||||
"The idle threshold preference value was passed as the second argument."
|
||||
);
|
||||
Assert.ok(
|
||||
idleService.removeIdleObserver.notCalled,
|
||||
"removeIdleObserver has not been called yet."
|
||||
);
|
||||
|
||||
// Hold a reference to what addIdleObserver was called with as its first
|
||||
// argument, so we can compare it against what's passed to removeIdleObserver.
|
||||
let addObserverArg = idleService.addIdleObserver.firstCall.args[0];
|
||||
|
||||
// We want to make sure that uninitBackupScheduler doesn't call this again,
|
||||
// so reset its call history.
|
||||
idleService.addIdleObserver.resetHistory();
|
||||
|
||||
// Now, let's pretend that the preference for the idle threshold changed
|
||||
// before we could uninit the backup scheduler. We should ensure that this
|
||||
// change is _not_ reflected whenever deregistration of the idle callback
|
||||
// occurs, since it wouldn't match the registration arguments.
|
||||
Services.prefs.setIntPref(
|
||||
IDLE_THRESHOLD_SECONDS_PREF_NAME,
|
||||
THRESHOLD_SECONDS + 5
|
||||
);
|
||||
|
||||
bs.uninitBackupScheduler();
|
||||
Assert.ok(
|
||||
idleService.addIdleObserver.notCalled,
|
||||
"addIdleObserver was not called again."
|
||||
);
|
||||
Assert.ok(
|
||||
idleService.removeIdleObserver.calledOnce,
|
||||
"removeIdleObserver was called once."
|
||||
);
|
||||
Assert.ok(
|
||||
idleService.removeIdleObserver.firstCall.args[0] instanceof Ci.nsIObserver,
|
||||
"The first argument to addIdleObserver was an nsIObserver"
|
||||
);
|
||||
Assert.equal(
|
||||
idleService.removeIdleObserver.firstCall.args[0],
|
||||
addObserverArg,
|
||||
"The first argument to addIdleObserver matches the first argument to removeIdleObserver"
|
||||
);
|
||||
Assert.equal(
|
||||
idleService.removeIdleObserver.firstCall.args[1],
|
||||
THRESHOLD_SECONDS,
|
||||
"The original idle threshold preference value was passed as the second argument."
|
||||
);
|
||||
|
||||
sandbox.restore();
|
||||
Services.prefs.clearUserPref(IDLE_THRESHOLD_SECONDS_PREF_NAME);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that calling BackupService.onObserve with the "idle" notification
|
||||
* causes the BackupService.onIdle method to be called.
|
||||
*/
|
||||
add_task(async function test_BackupService_onObserve_idle() {
|
||||
let bs = new BackupService();
|
||||
let sandbox = sinon.createSandbox();
|
||||
sandbox.stub(bs, "onIdle");
|
||||
|
||||
// The subject for the idle notification is always the idle service itself.
|
||||
bs.onObserve(idleService, "idle");
|
||||
Assert.ok(bs.onIdle.calledOnce, "BackupService.onIdle was called.");
|
||||
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that calling BackupService.onObserve with the
|
||||
* "quit-application-granted" notification causes the
|
||||
* BackupService.uninitBackupScheduler method to be called.
|
||||
*/
|
||||
add_task(
|
||||
async function test_BackupService_onObserve_quit_application_granted() {
|
||||
let bs = new BackupService();
|
||||
let sandbox = sinon.createSandbox();
|
||||
sandbox.stub(bs, "uninitBackupScheduler");
|
||||
|
||||
// The subject for the quit-application-granted notification is null.
|
||||
bs.onObserve(null, "quit-application-granted");
|
||||
Assert.ok(
|
||||
bs.uninitBackupScheduler.calledOnce,
|
||||
"BackupService.uninitBackupScheduler was called."
|
||||
);
|
||||
|
||||
sandbox.restore();
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Tests that calling onIdle when a backup has never occurred causes a backup to
|
||||
* get scheduled.
|
||||
*/
|
||||
add_task(async function test_BackupService_idle_no_backup_exists() {
|
||||
// Make sure no last backup timestamp is recorded.
|
||||
Services.prefs.clearUserPref(LAST_BACKUP_TIMESTAMP_PREF_NAME);
|
||||
|
||||
let bs = new BackupService();
|
||||
let sandbox = sinon.createSandbox();
|
||||
sandbox.stub(bs, "createBackupOnIdleDispatch");
|
||||
|
||||
bs.initBackupScheduler();
|
||||
Assert.equal(
|
||||
bs.state.lastBackupDate,
|
||||
null,
|
||||
"State should have null for lastBackupDate"
|
||||
);
|
||||
|
||||
bs.onIdle();
|
||||
Assert.ok(
|
||||
bs.createBackupOnIdleDispatch.calledOnce,
|
||||
"BackupService.createBackupOnIdleDispatch was called."
|
||||
);
|
||||
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that calling onIdle when a backup has occurred recently does not cause
|
||||
* a backup to get scheduled.
|
||||
*/
|
||||
add_task(async function test_BackupService_idle_not_expired_backup() {
|
||||
// Let's calculate a Date that's five seconds ago.
|
||||
let fiveSecondsAgo = Date.now() - 5000; /* 5 seconds in milliseconds */
|
||||
let lastBackupPrefValue = Math.floor(fiveSecondsAgo / 1000);
|
||||
Services.prefs.setIntPref(
|
||||
LAST_BACKUP_TIMESTAMP_PREF_NAME,
|
||||
lastBackupPrefValue
|
||||
);
|
||||
|
||||
let bs = new BackupService();
|
||||
let sandbox = sinon.createSandbox();
|
||||
bs.initBackupScheduler();
|
||||
Assert.equal(
|
||||
bs.state.lastBackupDate,
|
||||
lastBackupPrefValue,
|
||||
"State should have cached lastBackupDate"
|
||||
);
|
||||
|
||||
sandbox.stub(bs, "createBackupOnIdleDispatch");
|
||||
|
||||
bs.onIdle();
|
||||
Assert.ok(
|
||||
bs.createBackupOnIdleDispatch.notCalled,
|
||||
"BackupService.createBackupOnIdleDispatch was not called."
|
||||
);
|
||||
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that calling onIdle when a backup has occurred, but after the threshold
|
||||
* does cause a backup to get scheduled
|
||||
*/
|
||||
add_task(async function test_BackupService_idle_expired_backup() {
|
||||
// Let's calculate a Date that's twenty five seconds ago.
|
||||
let twentyFiveSecondsAgo =
|
||||
Date.now() - 25000; /* 25 seconds in milliseconds */
|
||||
let lastBackupPrefValue = Math.floor(twentyFiveSecondsAgo / 1000);
|
||||
|
||||
Services.prefs.setIntPref(
|
||||
LAST_BACKUP_TIMESTAMP_PREF_NAME,
|
||||
lastBackupPrefValue
|
||||
);
|
||||
|
||||
let bs = new BackupService();
|
||||
let sandbox = sinon.createSandbox();
|
||||
bs.initBackupScheduler();
|
||||
Assert.equal(
|
||||
bs.state.lastBackupDate,
|
||||
lastBackupPrefValue,
|
||||
"State should have cached lastBackupDate"
|
||||
);
|
||||
|
||||
sandbox.stub(bs, "createBackupOnIdleDispatch");
|
||||
|
||||
bs.onIdle();
|
||||
Assert.ok(
|
||||
bs.createBackupOnIdleDispatch.calledOnce,
|
||||
"BackupService.createBackupOnIdleDispatch was called."
|
||||
);
|
||||
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that calling onIdle when a backup occurred in the future somehow causes
|
||||
* a backup to get scheduled.
|
||||
*/
|
||||
add_task(async function test_BackupService_idle_time_travel() {
|
||||
// Let's calculate a Date that's twenty-five seconds in the future.
|
||||
let twentyFiveSecondsFromNow =
|
||||
Date.now() + 25000; /* 25 seconds in milliseconds */
|
||||
let lastBackupPrefValue = Math.floor(twentyFiveSecondsFromNow / 1000);
|
||||
|
||||
Services.prefs.setIntPref(
|
||||
LAST_BACKUP_TIMESTAMP_PREF_NAME,
|
||||
lastBackupPrefValue
|
||||
);
|
||||
|
||||
let bs = new BackupService();
|
||||
let sandbox = sinon.createSandbox();
|
||||
bs.initBackupScheduler();
|
||||
Assert.equal(
|
||||
bs.state.lastBackupDate,
|
||||
lastBackupPrefValue,
|
||||
"State should have cached lastBackupDate"
|
||||
);
|
||||
|
||||
sandbox.stub(bs, "createBackupOnIdleDispatch");
|
||||
|
||||
bs.onIdle();
|
||||
Assert.ok(
|
||||
bs.createBackupOnIdleDispatch.calledOnce,
|
||||
"BackupService.createBackupOnIdleDispatch was called."
|
||||
);
|
||||
Assert.equal(
|
||||
bs.state.lastBackupDate,
|
||||
null,
|
||||
"Should have cleared the last backup date."
|
||||
);
|
||||
|
||||
sandbox.restore();
|
||||
});
|
|
@ -31,18 +31,20 @@ skip-if = ["apple_silicon && automation"] # bug 1729538
|
|||
|
||||
["test_BackupService_renderTemplate.js"]
|
||||
|
||||
["test_BackupService_scheduler.js"]
|
||||
|
||||
["test_BackupService_schema_versions.js"]
|
||||
|
||||
["test_BackupService_takeMeasurements.js"]
|
||||
|
||||
["test_MeasurementUtils_fuzzByteSize.js"]
|
||||
|
||||
["test_CookiesBackupResource.js"]
|
||||
|
||||
["test_CredentialsAndSecurityBackupResource.js"]
|
||||
|
||||
["test_FormHistoryBackupResource.js"]
|
||||
|
||||
["test_MeasurementUtils_fuzzByteSize.js"]
|
||||
|
||||
["test_MiscDataBackupResource.js"]
|
||||
|
||||
["test_PlacesBackupResource.js"]
|
||||
|
|
|
@ -3116,6 +3116,22 @@ backupService:
|
|||
setPref:
|
||||
branch: user
|
||||
pref: browser.backup.sqlite.step_delay_ms
|
||||
idleThresholdSeconds:
|
||||
description: >-
|
||||
The number of seconds of user idle time to wait for before considering
|
||||
to schedule a backup.
|
||||
type: int
|
||||
setPref:
|
||||
branch: user
|
||||
pref: browser.backup.scheduled.idle-threshold-seconds
|
||||
minTimeBetweenBackupsSeconds:
|
||||
description: >-
|
||||
The minimum number of seconds since the last known backup that must
|
||||
pass before we might schedule a backup.
|
||||
type: int
|
||||
setPref:
|
||||
branch: user
|
||||
pref: browser.backup.scheduled.minimum-time-between-backups-seconds
|
||||
|
||||
pqcrypto:
|
||||
description: Prefs that control the use of post-quantum cryptography.
|
||||
|
|
Загрузка…
Ссылка в новой задаче