зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to m-i
This commit is contained in:
Коммит
9007f77036
|
@ -70,7 +70,7 @@ let intervals = {
|
|||
get initial() this._fixupIntervalPref("initial", 10), // 10 seconds.
|
||||
// Every interval after the first.
|
||||
get schedule() this._fixupIntervalPref("schedule", 2 * 60 * 60), // 2 hours
|
||||
// After an error
|
||||
// Initial retry after an error (exponentially backed-off to .schedule)
|
||||
get retry() this._fixupIntervalPref("retry", 2 * 60), // 2 mins
|
||||
};
|
||||
|
||||
|
@ -111,6 +111,9 @@ InternalScheduler.prototype = {
|
|||
_timerRunning: false,
|
||||
// Our sync engine - XXX - maybe just a callback?
|
||||
_engine: Sync,
|
||||
// Our current "error backoff" timeout. zero if no error backoff is in
|
||||
// progress and incremented after successive errors until a max is reached.
|
||||
_currentErrorBackoff: 0,
|
||||
|
||||
// Our state variable and constants.
|
||||
state: null,
|
||||
|
@ -292,6 +295,7 @@ InternalScheduler.prototype = {
|
|||
this.state = this.STATE_OK;
|
||||
this._logManager.resetFileLog(this._logManager.REASON_SUCCESS);
|
||||
Services.obs.notifyObservers(null, "readinglist:sync:finish", null);
|
||||
this._currentErrorBackoff = 0; // error retry interval is reset on success.
|
||||
return intervals.schedule;
|
||||
}).catch(err => {
|
||||
// This isn't ideal - we really should have _canSync() check this - but
|
||||
|
@ -300,6 +304,7 @@ InternalScheduler.prototype = {
|
|||
if (err.message == fxAccountsCommon.ERROR_NO_ACCOUNT ||
|
||||
err.message == fxAccountsCommon.ERROR_UNVERIFIED_ACCOUNT) {
|
||||
// make everything look like success.
|
||||
this._currentErrorBackoff = 0; // error retry interval is reset on success.
|
||||
this.log.info("Can't sync due to FxA account state " + err.message);
|
||||
this.state = this.STATE_OK;
|
||||
this._logManager.resetFileLog(this._logManager.REASON_SUCCESS);
|
||||
|
@ -314,7 +319,10 @@ InternalScheduler.prototype = {
|
|||
{state: this.state, err});
|
||||
this._logManager.resetFileLog(this._logManager.REASON_ERROR);
|
||||
Services.obs.notifyObservers(null, "readinglist:sync:error", null);
|
||||
return intervals.retry;
|
||||
// We back-off on error retries until it hits our normally scheduled interval.
|
||||
this._currentErrorBackoff = this._currentErrorBackoff == 0 ? intervals.retry :
|
||||
Math.min(intervals.schedule, this._currentErrorBackoff * 2);
|
||||
return this._currentErrorBackoff;
|
||||
}).then(nextDelay => {
|
||||
this._timerRunning = false;
|
||||
// ensure a new timer is setup for the appropriate next time.
|
||||
|
|
|
@ -174,6 +174,81 @@ add_task(function* testBackoff() {
|
|||
scheduler.finalize();
|
||||
});
|
||||
|
||||
add_task(function testErrorBackoff() {
|
||||
// This test can't sanely use the "test scheduler" above, so make one more
|
||||
// suited.
|
||||
let rlMock = new ReadingListMock();
|
||||
let scheduler = createTestableScheduler(rlMock);
|
||||
scheduler._setTimeout = function(delay) {
|
||||
// create a timer that fires immediately
|
||||
return setTimeout(() => scheduler._doSync(), 0);
|
||||
}
|
||||
|
||||
// This does all the work...
|
||||
function checkBackoffs(expectedSequences) {
|
||||
let orig_maybeReschedule = scheduler._maybeReschedule;
|
||||
return new Promise(resolve => {
|
||||
let isSuccess = true; // ie, first run will put us in "fail" mode.
|
||||
let expected;
|
||||
function nextSequence() {
|
||||
if (expectedSequences.length == 0) {
|
||||
resolve();
|
||||
return true; // we are done.
|
||||
}
|
||||
// setup the current set of expected results.
|
||||
expected = expectedSequences.shift()
|
||||
// and toggle the success status of the engine.
|
||||
isSuccess = !isSuccess;
|
||||
if (isSuccess) {
|
||||
scheduler._engine.start = Promise.resolve;
|
||||
} else {
|
||||
scheduler._engine.start = () => {
|
||||
return Promise.reject(new Error("oh no"))
|
||||
}
|
||||
}
|
||||
return false; // not done.
|
||||
};
|
||||
// get the first sequence;
|
||||
nextSequence();
|
||||
// and setup the scheduler to check the sequences.
|
||||
scheduler._maybeReschedule = function(nextDelay) {
|
||||
let thisExpected = expected.shift();
|
||||
equal(thisExpected * 1000, nextDelay);
|
||||
if (expected.length == 0) {
|
||||
if (nextSequence()) {
|
||||
// we are done, so do nothing.
|
||||
return;
|
||||
}
|
||||
}
|
||||
// call the original impl to get the next schedule.
|
||||
return orig_maybeReschedule.call(scheduler, nextDelay);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
prefs.set("schedule", 100);
|
||||
prefs.set("retry", 5);
|
||||
// The sequences of timeouts we expect as the Sync error state changes.
|
||||
let backoffsChecked = checkBackoffs([
|
||||
// first sequence is in failure mode - expect the timeout to double until 'schedule'
|
||||
[5, 10, 20, 40, 80, 100, 100],
|
||||
// Sync just started working - more 'schedule'
|
||||
[100, 100],
|
||||
// Just stopped again - error backoff process restarts.
|
||||
[5, 10],
|
||||
// Another success and we are back to 'schedule'
|
||||
[100, 100],
|
||||
]);
|
||||
|
||||
// fire things off.
|
||||
scheduler.init();
|
||||
|
||||
// and wait for completion.
|
||||
yield backoffsChecked;
|
||||
|
||||
scheduler.finalize();
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
|
|
@ -460,13 +460,18 @@ var LoginManagerContent = {
|
|||
|
||||
if (!usernameField)
|
||||
log("(form -- no username field found)");
|
||||
|
||||
else
|
||||
log("Username field id/name/value is: ", usernameField.id, " / ",
|
||||
usernameField.name, " / ", usernameField.value);
|
||||
|
||||
// If we're not submitting a form (it's a page load), there are no
|
||||
// password field values for us to use for identifying fields. So,
|
||||
// just assume the first password field is the one to be filled in.
|
||||
if (!isSubmission || pwFields.length == 1)
|
||||
return [usernameField, pwFields[0].element, null];
|
||||
if (!isSubmission || pwFields.length == 1) {
|
||||
var passwordField = pwFields[0].element;
|
||||
log("Password field id/name is: ", passwordField.id, " / ", passwordField.name);
|
||||
return [usernameField, passwordField, null];
|
||||
}
|
||||
|
||||
|
||||
// Try to figure out WTF is in the form based on the password values.
|
||||
|
@ -509,6 +514,8 @@ var LoginManagerContent = {
|
|||
}
|
||||
}
|
||||
|
||||
log("Password field (new) id/name is: ", newPasswordField.id, " / ", newPasswordField.name);
|
||||
log("Password field (old) id/name is: ", oldPasswordField.id, " / ", oldPasswordField.name);
|
||||
return [usernameField, newPasswordField, oldPasswordField];
|
||||
},
|
||||
|
||||
|
|
|
@ -236,6 +236,11 @@ const DEFAULT_RECIPES = {
|
|||
"description": "anthem uses a hidden password and username field to disable filling",
|
||||
"hosts": ["www.anthem.com"],
|
||||
"passwordSelector": "#LoginContent_txtLoginPass"
|
||||
},
|
||||
{
|
||||
"description": "An ephemeral password-shim field is incorrectly selected as the username field.",
|
||||
"hosts": ["www.discover.com"],
|
||||
"usernameSelector": "#login-account"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче