Commit 37135c7b authored by robliao@chromium.org's avatar robliao@chromium.org

Attempt Manager Refactor and Opt-In Pipeline Refactor

Refactored the attempt manager to use a more obvious naming scheme as well as
participate in promises for retries.

This also entailed reexamination of all attempt managers in Chrome Now.
Opt-in checking as a result became a first class state change citizen and is
no longer part of the card checking pipeline, fixing a few opt-in aggression
issues. With this change, we don't care how often a push message comes through
that may indicate that Google Now is enabled.

BUG=360649,362306

Review URL: https://codereview.chromium.org/248473003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@268302 0039d316-1c4b-4281-b951-d872f2087c98
parent 8b367f7f
......@@ -26,6 +26,7 @@ mockChromeEvent(instrumented, 'notifications.onShowSettings');
mockChromeEvent(instrumented, 'pushMessaging.onMessage');
mockChromeEvent(instrumented, 'runtime.onInstalled');
mockChromeEvent(instrumented, 'runtime.onStartup');
mockChromeEvent(instrumented, 'storage.onChanged');
NOTIFICATION_CARDS_URL = 'https://test/';
navigator = {language: 'en-US'};
......@@ -879,21 +879,19 @@ function buildAttemptManager(
}
/**
* Schedules next attempt.
* @param {number=} opt_previousDelaySeconds Previous delay in a sequence of
* retry attempts, if specified. Not specified for scheduling first retry
* in the exponential sequence.
* Schedules the alarm with a random factor to reduce the chance that all
* clients will fire their timers at the same time.
* @param {number} durationSeconds Number of seconds before firing the alarm.
*/
function scheduleNextAttempt(opt_previousDelaySeconds) {
var base = opt_previousDelaySeconds ? opt_previousDelaySeconds * 2 :
initialDelaySeconds;
var newRetryDelaySeconds =
Math.min(base * (1 + 0.2 * Math.random()), maximumDelaySeconds);
function scheduleAlarm(durationSeconds) {
var randomizedRetryDuration =
Math.min(durationSeconds * (1 + 0.2 * Math.random()),
maximumDelaySeconds);
createAlarm(newRetryDelaySeconds);
createAlarm(randomizedRetryDuration);
var items = {};
items[currentDelayStorageKey] = newRetryDelaySeconds;
items[currentDelayStorageKey] = randomizedRetryDuration;
chrome.storage.local.set(items);
}
......@@ -908,7 +906,7 @@ function buildAttemptManager(
createAlarm(opt_firstDelaySeconds);
chrome.storage.local.remove(currentDelayStorageKey);
} else {
scheduleNextAttempt();
scheduleAlarm(initialDelaySeconds);
}
}
......@@ -921,21 +919,24 @@ function buildAttemptManager(
}
/**
* Plans for the next attempt.
* @param {function()} callback Completion callback. It will be invoked after
* the planning is done.
* Schedules an exponential backoff retry.
* @return {Promise} A promise to schedule the retry.
*/
function planForNext(callback) {
function scheduleRetry() {
var request = {};
request[currentDelayStorageKey] = undefined;
fillFromChromeLocalStorage(request, PromiseRejection.ALLOW)
return fillFromChromeLocalStorage(request, PromiseRejection.ALLOW)
.catch(function() {
request[currentDelayStorageKey] = maximumDelaySeconds;
return Promise.resolve(request);
}).then(function(items) {
console.log('planForNext-get-storage ' + JSON.stringify(items));
scheduleNextAttempt(items[currentDelayStorageKey]);
callback();
})
.then(function(items) {
console.log('scheduleRetry-get-storage ' + JSON.stringify(items));
var retrySeconds = initialDelaySeconds;
if (items[currentDelayStorageKey]) {
retrySeconds = items[currentDelayStorageKey] * 2;
}
scheduleAlarm(retrySeconds);
});
}
......@@ -949,7 +950,7 @@ function buildAttemptManager(
return {
start: start,
planForNext: planForNext,
scheduleRetry: scheduleRetry,
stop: stop,
isRunning: isRunning
};
......
......@@ -792,7 +792,6 @@ function setupAttemptManagerTest(fixture) {
fixture.makeMockLocalFunctions([
'attempt',
'planForNextCallback',
'isRunningCallback'
]);
fixture.makeAndRegisterMockApis([
......@@ -908,8 +907,8 @@ TEST_F('GoogleNowUtilityUnitTest', 'AttemptManagerExponGrowth', function() {
var test = setupAttemptManagerTest(this);
var testStoredRetryDelay = 433;
// Call planForNext, which prepares next attempt. Current retry time
// is less than 1/2 of the maximum delay.
// Call scheduleRetry, which schedules a retry.
// Current retry time is less than 1/2 of the maximum delay.
// Expectations.
var expectedRetryDelaySeconds =
testStoredRetryDelay * 2 * (1 + testRandomValue * 0.2);
......@@ -925,10 +924,16 @@ TEST_F('GoogleNowUtilityUnitTest', 'AttemptManagerExponGrowth', function() {
periodInMinutes: testMaximumDelaySeconds / 60}));
this.mockApis.expects(once()).chrome_storage_local_set(
eqJSON(createTestAttemptStorageEntry(expectedRetryDelaySeconds)));
this.mockLocalFunctions.expects(once()).planForNextCallback();
// Invocation.
test.attempts.planForNext(
this.mockLocalFunctions.functions().planForNextCallback);
var thenCalled = false;
var catchCalled = false;
test.attempts.scheduleRetry().then(function(request) {
thenCalled = true;
}).catch(function(request) {
catchCalled = true;
});
assertTrue(thenCalled);
assertFalse(catchCalled);
});
TEST_F('GoogleNowUtilityUnitTest', 'AttemptManagerGrowthLimit', function() {
......@@ -938,8 +943,8 @@ TEST_F('GoogleNowUtilityUnitTest', 'AttemptManagerGrowthLimit', function() {
var test = setupAttemptManagerTest(this);
var testStoredRetryDelay = 1500;
// Call planForNext, which prepares next attempt. Current retry time
// is greater than 1/2 of the maximum delay.
// Call scheduleRetry, which schedules a retry.
// Current retry time is greater than 1/2 of the maximum delay.
// Expectations.
var expectedRetryDelaySeconds = testMaximumDelaySeconds;
expectChromeLocalStorageGet(
......@@ -955,10 +960,16 @@ TEST_F('GoogleNowUtilityUnitTest', 'AttemptManagerGrowthLimit', function() {
}));
this.mockApis.expects(once()).chrome_storage_local_set(
eqJSON(createTestAttemptStorageEntry(expectedRetryDelaySeconds)));
this.mockLocalFunctions.expects(once()).planForNextCallback();
// Invocation.
test.attempts.planForNext(
this.mockLocalFunctions.functions().planForNextCallback);
var thenCalled = false;
var catchCalled = false;
test.attempts.scheduleRetry().then(function(request) {
thenCalled = true;
}).catch(function(request) {
catchCalled = true;
});
assertTrue(thenCalled);
assertFalse(catchCalled);
});
TEST_F('GoogleNowUtilityUnitTest', 'AttemptManagerAlarm', function() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment