mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Backed out changesets 8522ea4f4621, c6d45a7a0eec, and 7d72517398ba (bug 1126184) for newtab mochitest-bc failures.
CLOSED TREE
This commit is contained in:
parent
30b95aef8e
commit
9cdb20ece0
@ -9,7 +9,6 @@
|
||||
*/
|
||||
function runTests() {
|
||||
requestLongerTimeout(2);
|
||||
yield addNewTabPageTab();
|
||||
|
||||
// test a simple drag-and-drop scenario
|
||||
yield setLinks("0,1,2,3,4,5,6,7,8");
|
||||
|
@ -13,7 +13,6 @@ const PREF_NEWTAB_COLUMNS = "browser.newtabpage.columns";
|
||||
*/
|
||||
function runTests() {
|
||||
registerCleanupFunction(_ => Services.prefs.clearUserPref(PREF_NEWTAB_COLUMNS));
|
||||
yield addNewTabPageTab();
|
||||
|
||||
// drag a new site onto the very first cell
|
||||
yield setLinks("0,1,2,3,4,5,6,7,8");
|
||||
|
@ -15,7 +15,6 @@ const XMLHttpRequest =
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
@ -57,9 +56,6 @@ const ALLOWED_IMAGE_SCHEMES = new Set(["https", "data"]);
|
||||
// The frecency of a directory link
|
||||
const DIRECTORY_FRECENCY = 1000;
|
||||
|
||||
// The frecency of a related link
|
||||
const RELATED_FRECENCY = Infinity;
|
||||
|
||||
// Divide frecency by this amount for pings
|
||||
const PING_SCORE_DIVISOR = 10000;
|
||||
|
||||
@ -93,11 +89,6 @@ let DirectoryLinksProvider = {
|
||||
*/
|
||||
_relatedLinks: new Map(),
|
||||
|
||||
/**
|
||||
* A set of top sites that we can provide related links for
|
||||
*/
|
||||
_topSitesWithRelatedLinks: new Set(),
|
||||
|
||||
get _observedPrefs() Object.freeze({
|
||||
enhanced: PREF_NEWTAB_ENHANCED,
|
||||
linksURL: PREF_DIRECTORY_SOURCE,
|
||||
@ -441,10 +432,7 @@ let DirectoryLinksProvider = {
|
||||
}).catch(ex => {
|
||||
Cu.reportError(ex);
|
||||
return [];
|
||||
}).then(links => {
|
||||
aCallback(links);
|
||||
this._populatePlacesLinks();
|
||||
});
|
||||
}).then(aCallback);
|
||||
},
|
||||
|
||||
init: function DirectoryLinksProvider_init() {
|
||||
@ -453,9 +441,6 @@ let DirectoryLinksProvider = {
|
||||
// setup directory file path and last download timestamp
|
||||
this._directoryFilePath = OS.Path.join(OS.Constants.Path.localProfileDir, DIRECTORY_LINKS_FILE);
|
||||
this._lastDownloadMS = 0;
|
||||
|
||||
NewTabUtils.placesProvider.addObserver(this);
|
||||
|
||||
return Task.spawn(function() {
|
||||
// get the last modified time of the links file if it exists
|
||||
let doesFileExists = yield OS.File.exists(this._directoryFilePath);
|
||||
@ -468,123 +453,6 @@ let DirectoryLinksProvider = {
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_handleManyLinksChanged: function() {
|
||||
this._topSitesWithRelatedLinks.clear();
|
||||
this._relatedLinks.forEach((relatedLinks, site) => {
|
||||
if (NewTabUtils.isTopPlacesSite(site)) {
|
||||
this._topSitesWithRelatedLinks.add(site);
|
||||
}
|
||||
});
|
||||
this._updateRelatedTile();
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates _topSitesWithRelatedLinks based on the link that was changed.
|
||||
*
|
||||
* @return true if _topSitesWithRelatedLinks was modified, false otherwise.
|
||||
*/
|
||||
_handleLinkChanged: function(aLink) {
|
||||
let changedLinkSite = NewTabUtils.extractSite(aLink.url);
|
||||
let linkStored = this._topSitesWithRelatedLinks.has(changedLinkSite);
|
||||
|
||||
if (!NewTabUtils.isTopPlacesSite(changedLinkSite) && linkStored) {
|
||||
this._topSitesWithRelatedLinks.delete(changedLinkSite);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this._relatedLinks.has(changedLinkSite) &&
|
||||
NewTabUtils.isTopPlacesSite(changedLinkSite) && !linkStored) {
|
||||
this._topSitesWithRelatedLinks.add(changedLinkSite);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_populatePlacesLinks: function () {
|
||||
NewTabUtils.links.populateProviderCache(NewTabUtils.placesProvider, () => {
|
||||
this._handleManyLinksChanged();
|
||||
});
|
||||
},
|
||||
|
||||
onLinkChanged: function (aProvider, aLink) {
|
||||
// Make sure NewTabUtils.links handles the notification first.
|
||||
setTimeout(() => {
|
||||
if (this._handleLinkChanged(aLink)) {
|
||||
this._updateRelatedTile();
|
||||
}
|
||||
}, 0);
|
||||
},
|
||||
|
||||
onManyLinksChanged: function () {
|
||||
// Make sure NewTabUtils.links handles the notification first.
|
||||
setTimeout(() => {
|
||||
this._handleManyLinksChanged();
|
||||
}, 0);
|
||||
},
|
||||
|
||||
/**
|
||||
* Chooses and returns a related tile based on a user's top sites
|
||||
* that we have an available related tile for.
|
||||
*
|
||||
* @return the chosen related tile, or undefined if there isn't one
|
||||
*/
|
||||
_updateRelatedTile: function() {
|
||||
let sortedLinks = NewTabUtils.getProviderLinks(this);
|
||||
|
||||
if (!sortedLinks) {
|
||||
// If NewTabUtils.links.resetCache() is called before getting here,
|
||||
// sortedLinks may be undefined.
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete the current related tile, if one exists.
|
||||
let initialLength = sortedLinks.length;
|
||||
this.maxNumLinks = initialLength;
|
||||
if (initialLength) {
|
||||
let mostFrecentLink = sortedLinks[0];
|
||||
if ("related" == mostFrecentLink.type) {
|
||||
this._callObservers("onLinkChanged", {
|
||||
url: mostFrecentLink.url,
|
||||
frecency: 0,
|
||||
lastVisitDate: mostFrecentLink.lastVisitDate,
|
||||
type: "related",
|
||||
}, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (this._topSitesWithRelatedLinks.size == 0) {
|
||||
// There are no potential related links we can show.
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a flat list of all possible links we can show as related.
|
||||
// Note that many top sites may map to the same related links, but we only
|
||||
// want to count each related link once (based on url), thus possibleLinks is a map
|
||||
// from url to relatedLink. Thus, each link has an equal chance of being chosen at
|
||||
// random from flattenedLinks if it appears only once.
|
||||
let possibleLinks = new Map();
|
||||
this._topSitesWithRelatedLinks.forEach(topSiteWithRelatedLink => {
|
||||
let relatedLinksMap = this._relatedLinks.get(topSiteWithRelatedLink);
|
||||
relatedLinksMap.forEach((relatedLink, url) => {
|
||||
possibleLinks.set(url, relatedLink);
|
||||
})
|
||||
});
|
||||
let flattenedLinks = [...possibleLinks.values()];
|
||||
|
||||
// Choose our related link at random
|
||||
let relatedIndex = Math.floor(Math.random() * flattenedLinks.length);
|
||||
let chosenRelatedLink = flattenedLinks[relatedIndex];
|
||||
|
||||
// Show the new directory tile.
|
||||
this._callObservers("onLinkChanged", {
|
||||
url: chosenRelatedLink.url,
|
||||
frecency: RELATED_FRECENCY,
|
||||
lastVisitDate: chosenRelatedLink.lastVisitDate,
|
||||
type: "related",
|
||||
});
|
||||
return chosenRelatedLink;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the object to its pre-init state
|
||||
*/
|
||||
|
@ -19,8 +19,6 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
|
||||
"resource://gre/modules/NewTabUtils.jsm");
|
||||
|
||||
do_get_profile();
|
||||
|
||||
@ -60,42 +58,6 @@ const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
|
||||
"setInputStream");
|
||||
|
||||
let gLastRequestPath;
|
||||
|
||||
let relatedTile1 = {
|
||||
url: "http://turbotax.com",
|
||||
type: "related",
|
||||
lastVisitDate: 4,
|
||||
related: [
|
||||
"taxact.com",
|
||||
"hrblock.com",
|
||||
"1040.com",
|
||||
"taxslayer.com"
|
||||
]
|
||||
};
|
||||
let relatedTile2 = {
|
||||
url: "http://irs.gov",
|
||||
type: "related",
|
||||
lastVisitDate: 3,
|
||||
related: [
|
||||
"taxact.com",
|
||||
"hrblock.com",
|
||||
"freetaxusa.com",
|
||||
"taxslayer.com"
|
||||
]
|
||||
};
|
||||
let relatedTile3 = {
|
||||
url: "http://hrblock.com",
|
||||
type: "related",
|
||||
lastVisitDate: 2,
|
||||
related: [
|
||||
"taxact.com",
|
||||
"freetaxusa.com",
|
||||
"1040.com",
|
||||
"taxslayer.com"
|
||||
]
|
||||
};
|
||||
let someOtherSite = {url: "http://someothersite.com", title: "Not_A_Related_Site"};
|
||||
|
||||
function getHttpHandler(path) {
|
||||
let code = 200;
|
||||
let body = JSON.stringify(kHttpHandlerData[path]);
|
||||
@ -199,7 +161,6 @@ function run_test() {
|
||||
server.registerPrefixHandler(kExamplePath, getHttpHandler(kExamplePath));
|
||||
server.registerPrefixHandler(kFailPath, getHttpHandler(kFailPath));
|
||||
server.start(kDefaultServerPort);
|
||||
NewTabUtils.init();
|
||||
|
||||
run_next_test();
|
||||
|
||||
@ -214,132 +175,41 @@ function run_test() {
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function test_updateRelatedTile() {
|
||||
let topSites = ["site0.com", "1040.com", "site2.com", "hrblock.com", "site4.com", "freetaxusa.com", "site6.com"];
|
||||
|
||||
// Initial setup
|
||||
let data = {"en-US": [relatedTile1, relatedTile2, relatedTile3, someOtherSite]};
|
||||
let dataURI = 'data:application/json,' + JSON.stringify(data);
|
||||
|
||||
let testObserver = new TestFirstRun();
|
||||
DirectoryLinksProvider.addObserver(testObserver);
|
||||
|
||||
yield promiseSetupDirectoryLinksProvider({linksURL: dataURI});
|
||||
let links = yield fetchData();
|
||||
|
||||
let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite;
|
||||
NewTabUtils.isTopPlacesSite = function(site) {
|
||||
return topSites.indexOf(site) >= 0;
|
||||
}
|
||||
|
||||
let origGetProviderLinks = NewTabUtils.getProviderLinks;
|
||||
NewTabUtils.getProviderLinks = function(provider) {
|
||||
return links;
|
||||
}
|
||||
|
||||
do_check_eq(DirectoryLinksProvider._updateRelatedTile(), undefined);
|
||||
|
||||
function TestFirstRun() {
|
||||
this.promise = new Promise(resolve => {
|
||||
this.onLinkChanged = (directoryLinksProvider, link) => {
|
||||
links.unshift(link);
|
||||
let possibleLinks = [relatedTile1.url, relatedTile2.url, relatedTile3.url];
|
||||
|
||||
isIdentical([...DirectoryLinksProvider._topSitesWithRelatedLinks], ["hrblock.com", "1040.com", "freetaxusa.com"]);
|
||||
do_check_true(possibleLinks.indexOf(link.url) > -1);
|
||||
do_check_eq(link.frecency, Infinity);
|
||||
do_check_eq(link.type, "related");
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function TestChangingRelatedTile() {
|
||||
this.count = 0;
|
||||
this.promise = new Promise(resolve => {
|
||||
this.onLinkChanged = (directoryLinksProvider, link) => {
|
||||
this.count++;
|
||||
let possibleLinks = [relatedTile1.url, relatedTile2.url, relatedTile3.url];
|
||||
|
||||
do_check_true(possibleLinks.indexOf(link.url) > -1);
|
||||
do_check_eq(link.type, "related");
|
||||
do_check_true(this.count <= 2);
|
||||
|
||||
if (this.count == 1) {
|
||||
// The removed related link is the one we added initially.
|
||||
do_check_eq(link.url, links.shift().url);
|
||||
do_check_eq(link.frecency, 0);
|
||||
} else {
|
||||
links.unshift(link);
|
||||
do_check_eq(link.frecency, Infinity);
|
||||
}
|
||||
isIdentical([...DirectoryLinksProvider._topSitesWithRelatedLinks], ["hrblock.com", "freetaxusa.com"]);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function TestRemovingRelatedTile() {
|
||||
this.count = 0;
|
||||
this.promise = new Promise(resolve => {
|
||||
this.onLinkChanged = (directoryLinksProvider, link) => {
|
||||
this.count++;
|
||||
|
||||
do_check_eq(link.type, "related");
|
||||
do_check_eq(this.count, 1);
|
||||
do_check_eq(link.frecency, 0);
|
||||
do_check_eq(link.url, links.shift().url);
|
||||
isIdentical([...DirectoryLinksProvider._topSitesWithRelatedLinks], []);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Test first call to '_updateRelatedTile()', called when fetching directory links.
|
||||
yield testObserver.promise;
|
||||
DirectoryLinksProvider.removeObserver(testObserver);
|
||||
|
||||
// Removing a top site that doesn't have a related link should
|
||||
// not change the current related tile.
|
||||
let removedTopsite = topSites.shift();
|
||||
do_check_eq(removedTopsite, "site0.com");
|
||||
do_check_false(NewTabUtils.isTopPlacesSite(removedTopsite));
|
||||
let updateRelatedTile = DirectoryLinksProvider._handleLinkChanged({
|
||||
url: "http://" + removedTopsite,
|
||||
type: "history",
|
||||
});
|
||||
do_check_false(updateRelatedTile);
|
||||
|
||||
// Removing a top site that has a related link should
|
||||
// remove any current related tile and add a new one.
|
||||
testObserver = new TestChangingRelatedTile();
|
||||
DirectoryLinksProvider.addObserver(testObserver);
|
||||
removedTopsite = topSites.shift();
|
||||
do_check_eq(removedTopsite, "1040.com");
|
||||
do_check_false(NewTabUtils.isTopPlacesSite(removedTopsite));
|
||||
DirectoryLinksProvider.onLinkChanged(DirectoryLinksProvider, {
|
||||
url: "http://" + removedTopsite,
|
||||
type: "history",
|
||||
});
|
||||
yield testObserver.promise;
|
||||
do_check_eq(testObserver.count, 2);
|
||||
DirectoryLinksProvider.removeObserver(testObserver);
|
||||
|
||||
// Removing all top sites with related links should remove
|
||||
// the current related link and not replace it.
|
||||
topSites = [];
|
||||
testObserver = new TestRemovingRelatedTile();
|
||||
DirectoryLinksProvider.addObserver(testObserver);
|
||||
DirectoryLinksProvider.onManyLinksChanged();
|
||||
yield testObserver.promise;
|
||||
|
||||
// Cleanup
|
||||
yield promiseCleanDirectoryLinksProvider();
|
||||
NewTabUtils.isTopPlacesSite = origIsTopPlacesSite;
|
||||
NewTabUtils.getProviderLinks = origGetProviderLinks;
|
||||
});
|
||||
|
||||
add_task(function test_relatedLinksMap() {
|
||||
let relatedTile1 = {
|
||||
url: "http://turbotax.com",
|
||||
type: "related",
|
||||
lastVisitDate: 4,
|
||||
related: [
|
||||
"taxact.com",
|
||||
"hrblock.com",
|
||||
"1040.com",
|
||||
"taxslayer.com"
|
||||
]
|
||||
};
|
||||
let relatedTile2 = {
|
||||
url: "http://irs.gov",
|
||||
type: "related",
|
||||
lastVisitDate: 3,
|
||||
related: [
|
||||
"taxact.com",
|
||||
"hrblock.com",
|
||||
"freetaxusa.com",
|
||||
"taxslayer.com"
|
||||
]
|
||||
};
|
||||
let relatedTile3 = {
|
||||
url: "http://hrblock.com",
|
||||
type: "related",
|
||||
lastVisitDate: 2,
|
||||
related: [
|
||||
"taxact.com",
|
||||
"freetaxusa.com",
|
||||
"1040.com",
|
||||
"taxslayer.com"
|
||||
]
|
||||
};
|
||||
let someOtherSite = {url: "http://someothersite.com", title: "Not_A_Related_Site"};
|
||||
let data = {"en-US": [relatedTile1, relatedTile2, relatedTile3, someOtherSite]};
|
||||
let dataURI = 'data:application/json,' + JSON.stringify(data);
|
||||
|
||||
@ -370,58 +240,6 @@ add_task(function test_relatedLinksMap() {
|
||||
yield promiseCleanDirectoryLinksProvider();
|
||||
});
|
||||
|
||||
add_task(function test_topSitesWithRelatedLinks() {
|
||||
let topSites = ["site0.com", "1040.com", "site2.com", "hrblock.com", "site4.com", "freetaxusa.com", "site6.com"];
|
||||
let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite;
|
||||
NewTabUtils.isTopPlacesSite = function(site) {
|
||||
return topSites.indexOf(site) >= 0;
|
||||
}
|
||||
|
||||
// Mock out getProviderLinks() so we don't have to populate cache in NewTabUtils
|
||||
let origGetProviderLinks = NewTabUtils.getProviderLinks;
|
||||
NewTabUtils.getProviderLinks = function(provider) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// We start off with no top sites with related links.
|
||||
do_check_eq(DirectoryLinksProvider._topSitesWithRelatedLinks.size, 0);
|
||||
|
||||
let data = {"en-US": [relatedTile1, relatedTile2, relatedTile3, someOtherSite]};
|
||||
let dataURI = 'data:application/json,' + JSON.stringify(data);
|
||||
|
||||
yield promiseSetupDirectoryLinksProvider({linksURL: dataURI});
|
||||
let links = yield fetchData();
|
||||
|
||||
// Check we've populated related links as expected.
|
||||
do_check_eq(DirectoryLinksProvider._relatedLinks.size, 5);
|
||||
|
||||
// When many sites change, we update _topSitesWithRelatedLinks as expected.
|
||||
let expectedTopSitesWithRelatedLinks = ["hrblock.com", "1040.com", "freetaxusa.com"];
|
||||
DirectoryLinksProvider._handleManyLinksChanged();
|
||||
isIdentical([...DirectoryLinksProvider._topSitesWithRelatedLinks], expectedTopSitesWithRelatedLinks);
|
||||
|
||||
// Removing site6.com as a topsite has no impact on _topSitesWithRelatedLinks.
|
||||
let popped = topSites.pop();
|
||||
DirectoryLinksProvider._handleLinkChanged({url: "http://" + popped});
|
||||
isIdentical([...DirectoryLinksProvider._topSitesWithRelatedLinks], expectedTopSitesWithRelatedLinks);
|
||||
|
||||
// Removing freetaxusa.com as a topsite will remove it from _topSitesWithRelatedLinks.
|
||||
popped = topSites.pop();
|
||||
expectedTopSitesWithRelatedLinks.pop();
|
||||
DirectoryLinksProvider._handleLinkChanged({url: "http://" + popped});
|
||||
isIdentical([...DirectoryLinksProvider._topSitesWithRelatedLinks], expectedTopSitesWithRelatedLinks);
|
||||
|
||||
// Re-adding freetaxusa.com as a topsite will add it to _topSitesWithRelatedLinks.
|
||||
topSites.push(popped);
|
||||
expectedTopSitesWithRelatedLinks.push(popped);
|
||||
DirectoryLinksProvider._handleLinkChanged({url: "http://" + popped});
|
||||
isIdentical([...DirectoryLinksProvider._topSitesWithRelatedLinks], expectedTopSitesWithRelatedLinks);
|
||||
|
||||
// Cleanup.
|
||||
NewTabUtils.isTopPlacesSite = origIsTopPlacesSite;
|
||||
NewTabUtils.getProviderLinks = origGetProviderLinks;
|
||||
});
|
||||
|
||||
add_task(function test_reportSitesAction() {
|
||||
yield DirectoryLinksProvider.init();
|
||||
let deferred, expectedPath, expectedPost;
|
||||
|
@ -12,7 +12,6 @@ const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
@ -715,13 +714,18 @@ let Links = {
|
||||
*/
|
||||
maxNumLinks: LINKS_GET_LINKS_LIMIT,
|
||||
|
||||
/**
|
||||
* The link providers.
|
||||
*/
|
||||
_providers: new Set(),
|
||||
|
||||
/**
|
||||
* A mapping from each provider to an object { sortedLinks, siteMap, linkMap }.
|
||||
* sortedLinks is the cached, sorted array of links for the provider.
|
||||
* siteMap is a mapping from base domains to URL count associated with the domain.
|
||||
* linkMap is a Map from link URLs to link objects.
|
||||
*/
|
||||
_providers: new Map(),
|
||||
_providerLinks: new Map(),
|
||||
|
||||
/**
|
||||
* The properties of link objects used to sort them.
|
||||
@ -742,7 +746,7 @@ let Links = {
|
||||
* @param aProvider The link provider.
|
||||
*/
|
||||
addProvider: function Links_addProvider(aProvider) {
|
||||
this._providers.set(aProvider, null);
|
||||
this._providers.add(aProvider);
|
||||
aProvider.addObserver(this);
|
||||
},
|
||||
|
||||
@ -753,6 +757,7 @@ let Links = {
|
||||
removeProvider: function Links_removeProvider(aProvider) {
|
||||
if (!this._providers.delete(aProvider))
|
||||
throw new Error("Unknown provider");
|
||||
this._providerLinks.delete(aProvider);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -785,7 +790,7 @@ let Links = {
|
||||
}
|
||||
|
||||
let numProvidersRemaining = this._providers.size;
|
||||
for (let [provider, links] of this._providers) {
|
||||
for (let provider of this._providers) {
|
||||
this._populateProviderCache(provider, () => {
|
||||
if (--numProvidersRemaining == 0)
|
||||
executeCallbacks();
|
||||
@ -835,9 +840,7 @@ let Links = {
|
||||
* Resets the links cache.
|
||||
*/
|
||||
resetCache: function Links_resetCache() {
|
||||
for (let provider of this._providers.keys()) {
|
||||
this._providers.set(provider, null);
|
||||
}
|
||||
this._providerLinks.clear();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -875,14 +878,6 @@ let Links = {
|
||||
}
|
||||
},
|
||||
|
||||
populateProviderCache: function(provider, callback) {
|
||||
if (!this._providers.has(provider)) {
|
||||
throw new Error("Can only populate provider cache for existing provider.");
|
||||
}
|
||||
|
||||
return this._populateProviderCache(provider, callback, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Calls getLinks on the given provider and populates our cache for it.
|
||||
* @param aProvider The provider whose cache will be populated.
|
||||
@ -890,42 +885,28 @@ let Links = {
|
||||
* @param aForce When true, populates the provider's cache even when it's
|
||||
* already filled.
|
||||
*/
|
||||
_populateProviderCache: function (aProvider, aCallback, aForce) {
|
||||
let cache = this._providers.get(aProvider);
|
||||
let createCache = !cache;
|
||||
if (createCache) {
|
||||
cache = {
|
||||
// Start with a resolved promise.
|
||||
populatePromise: new Promise(resolve => resolve()),
|
||||
};
|
||||
this._providers.set(aProvider, cache);
|
||||
}
|
||||
// Chain the populatePromise so that calls are effectively queued.
|
||||
cache.populatePromise = cache.populatePromise.then(() => {
|
||||
return new Promise(resolve => {
|
||||
if (!createCache && !aForce) {
|
||||
aCallback();
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
aProvider.getLinks(links => {
|
||||
// Filter out null and undefined links so we don't have to deal with
|
||||
// them in getLinks when merging links from providers.
|
||||
links = links.filter((link) => !!link);
|
||||
cache.sortedLinks = links;
|
||||
cache.siteMap = links.reduce((map, link) => {
|
||||
_populateProviderCache: function Links_populateProviderCache(aProvider, aCallback, aForce) {
|
||||
if (this._providerLinks.has(aProvider) && !aForce) {
|
||||
aCallback();
|
||||
} else {
|
||||
aProvider.getLinks(links => {
|
||||
// Filter out null and undefined links so we don't have to deal with
|
||||
// them in getLinks when merging links from providers.
|
||||
links = links.filter((link) => !!link);
|
||||
this._providerLinks.set(aProvider, {
|
||||
sortedLinks: links,
|
||||
siteMap: links.reduce((map, link) => {
|
||||
this._incrementSiteMap(map, link);
|
||||
return map;
|
||||
}, new Map());
|
||||
cache.linkMap = links.reduce((map, link) => {
|
||||
}, new Map()),
|
||||
linkMap: links.reduce((map, link) => {
|
||||
map.set(link.url, link);
|
||||
return map;
|
||||
}, new Map());
|
||||
aCallback();
|
||||
resolve();
|
||||
}, new Map()),
|
||||
});
|
||||
aCallback();
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -935,10 +916,8 @@ let Links = {
|
||||
_getMergedProviderLinks: function Links__getMergedProviderLinks() {
|
||||
// Build a list containing a copy of each provider's sortedLinks list.
|
||||
let linkLists = [];
|
||||
for (let links of this._providers.values()) {
|
||||
if (links && links.sortedLinks) {
|
||||
linkLists.push(links.sortedLinks.slice());
|
||||
}
|
||||
for (let links of this._providerLinks.values()) {
|
||||
linkLists.push(links.sortedLinks.slice());
|
||||
}
|
||||
|
||||
function getNextLink() {
|
||||
@ -967,15 +946,12 @@ let Links = {
|
||||
* @param aLink The link that changed. If the link is new, it must have all
|
||||
* of the _sortProperties. Otherwise, it may have as few or as
|
||||
* many as is convenient.
|
||||
* @param aIndex The current index of the changed link in the sortedLinks
|
||||
cache in _providers. Defaults to -1 if the provider doesn't know the index
|
||||
* @param aDeleted Boolean indicating if the provider has deleted the link.
|
||||
*/
|
||||
onLinkChanged: function Links_onLinkChanged(aProvider, aLink, aIndex=-1, aDeleted=false) {
|
||||
onLinkChanged: function Links_onLinkChanged(aProvider, aLink) {
|
||||
if (!("url" in aLink))
|
||||
throw new Error("Changed links must have a url property");
|
||||
|
||||
let links = this._providers.get(aProvider);
|
||||
let links = this._providerLinks.get(aProvider);
|
||||
if (!links)
|
||||
// This is not an error, it just means that between the time the provider
|
||||
// was added and the future time we call getLinks on it, it notified us of
|
||||
@ -991,33 +967,19 @@ let Links = {
|
||||
// Update our copy's position in O(lg n) by first removing it from its
|
||||
// list. It's important to do this before modifying its properties.
|
||||
if (this._sortProperties.some(prop => prop in aLink)) {
|
||||
let idx = aIndex;
|
||||
if (idx < 0) {
|
||||
idx = this._indexOf(sortedLinks, existingLink);
|
||||
} else if (this.compareLinks(aLink, sortedLinks[idx]) != 0) {
|
||||
throw new Error("aLink should be the same as sortedLinks[idx]");
|
||||
}
|
||||
|
||||
let idx = this._indexOf(sortedLinks, existingLink);
|
||||
if (idx < 0) {
|
||||
throw new Error("Link should be in _sortedLinks if in _linkMap");
|
||||
}
|
||||
sortedLinks.splice(idx, 1);
|
||||
|
||||
if (aDeleted) {
|
||||
updatePages = true;
|
||||
linkMap.delete(existingLink.url);
|
||||
this._decrementSiteMap(siteMap, existingLink);
|
||||
} else {
|
||||
// Update our copy's properties.
|
||||
for (let prop of this._sortProperties) {
|
||||
if (prop in aLink) {
|
||||
existingLink[prop] = aLink[prop];
|
||||
}
|
||||
// Update our copy's properties.
|
||||
for (let prop of this._sortProperties) {
|
||||
if (prop in aLink) {
|
||||
existingLink[prop] = aLink[prop];
|
||||
}
|
||||
|
||||
// Finally, reinsert our copy below.
|
||||
insertionLink = existingLink;
|
||||
}
|
||||
// Finally, reinsert our copy below.
|
||||
insertionLink = existingLink;
|
||||
}
|
||||
// Update our copy's title in O(1).
|
||||
if ("title" in aLink && aLink.title != existingLink.title) {
|
||||
@ -1247,12 +1209,8 @@ this.NewTabUtils = {
|
||||
return false;
|
||||
},
|
||||
|
||||
getProviderLinks: function(aProvider) {
|
||||
return Links._providers.get(aProvider).sortedLinks;
|
||||
},
|
||||
|
||||
isTopSiteGivenProvider: function(aSite, aProvider) {
|
||||
return Links._providers.get(aProvider).siteMap.has(aSite);
|
||||
return Links._providerLinks.get(aProvider).siteMap.has(aSite);
|
||||
},
|
||||
|
||||
isTopPlacesSite: function(aSite) {
|
||||
@ -1290,6 +1248,5 @@ this.NewTabUtils = {
|
||||
linkChecker: LinkChecker,
|
||||
pinnedLinks: PinnedLinks,
|
||||
blockedLinks: BlockedLinks,
|
||||
gridPrefs: GridPrefs,
|
||||
placesProvider: PlacesProvider
|
||||
gridPrefs: GridPrefs
|
||||
};
|
||||
|
@ -6,71 +6,11 @@
|
||||
const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
|
||||
Cu.import("resource://gre/modules/NewTabUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function notifyLinkDelete() {
|
||||
let expectedLinks = makeLinks(0, 3, 1);
|
||||
|
||||
let provider = new TestProvider(done => done(expectedLinks));
|
||||
provider.maxNumLinks = expectedLinks.length;
|
||||
|
||||
NewTabUtils.initWithoutProviders();
|
||||
NewTabUtils.links.addProvider(provider);
|
||||
yield new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
||||
|
||||
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
||||
|
||||
// Remove a link.
|
||||
let removedLink = expectedLinks[2];
|
||||
provider.notifyLinkChanged(removedLink, 2, true);
|
||||
let links = NewTabUtils.links._providers.get(provider);
|
||||
|
||||
// Check that sortedLinks is correctly updated.
|
||||
do_check_links(NewTabUtils.links.getLinks(), expectedLinks.slice(0, 2));
|
||||
|
||||
// Check that linkMap is accurately updated.
|
||||
do_check_eq(links.linkMap.size, 2);
|
||||
do_check_true(links.linkMap.get(expectedLinks[0].url));
|
||||
do_check_true(links.linkMap.get(expectedLinks[1].url));
|
||||
do_check_false(links.linkMap.get(removedLink.url));
|
||||
|
||||
// Check that siteMap is correctly updated.
|
||||
do_check_eq(links.siteMap.size, 2);
|
||||
do_check_true(links.siteMap.has(NewTabUtils.extractSite(expectedLinks[0].url)));
|
||||
do_check_true(links.siteMap.has(NewTabUtils.extractSite(expectedLinks[1].url)));
|
||||
do_check_false(links.siteMap.has(NewTabUtils.extractSite(removedLink.url)));
|
||||
|
||||
NewTabUtils.links.removeProvider(provider);
|
||||
});
|
||||
|
||||
add_task(function populatePromise() {
|
||||
let count = 0;
|
||||
let expectedLinks = makeLinks(0, 10, 2);
|
||||
|
||||
let getLinksFcn = Task.async(function* (callback) {
|
||||
//Should not be calling getLinksFcn twice
|
||||
count++;
|
||||
do_check_eq(count, 1);
|
||||
yield Promise.resolve();
|
||||
callback(expectedLinks);
|
||||
});
|
||||
|
||||
let provider = new TestProvider(getLinksFcn);
|
||||
|
||||
NewTabUtils.initWithoutProviders();
|
||||
NewTabUtils.links.addProvider(provider);
|
||||
|
||||
NewTabUtils.links.populateProviderCache(provider, () => {});
|
||||
NewTabUtils.links.populateProviderCache(provider, () => {
|
||||
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
||||
NewTabUtils.links.removeProvider(provider);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function isTopSiteGivenProvider() {
|
||||
let expectedLinks = makeLinks(0, 10, 2);
|
||||
|
||||
@ -82,7 +22,7 @@ add_task(function isTopSiteGivenProvider() {
|
||||
|
||||
NewTabUtils.initWithoutProviders();
|
||||
NewTabUtils.links.addProvider(provider);
|
||||
yield new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
||||
NewTabUtils.links.populateCache(function () {}, false);
|
||||
|
||||
do_check_eq(NewTabUtils.isTopSiteGivenProvider("example2.com", provider), true);
|
||||
do_check_eq(NewTabUtils.isTopSiteGivenProvider("example1.com", provider), false);
|
||||
@ -122,7 +62,8 @@ add_task(function multipleProviders() {
|
||||
NewTabUtils.links.addProvider(evenProvider);
|
||||
NewTabUtils.links.addProvider(oddProvider);
|
||||
|
||||
yield new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
||||
// This is sync since the providers' getLinks are sync.
|
||||
NewTabUtils.links.populateCache(function () {}, false);
|
||||
|
||||
let links = NewTabUtils.links.getLinks();
|
||||
let expectedLinks = makeLinks(NewTabUtils.links.maxNumLinks,
|
||||
@ -142,7 +83,8 @@ add_task(function changeLinks() {
|
||||
NewTabUtils.initWithoutProviders();
|
||||
NewTabUtils.links.addProvider(provider);
|
||||
|
||||
yield new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
||||
// This is sync since the provider's getLinks is sync.
|
||||
NewTabUtils.links.populateCache(function () {}, false);
|
||||
|
||||
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
||||
|
||||
@ -182,12 +124,8 @@ add_task(function changeLinks() {
|
||||
// Notify of many links changed.
|
||||
expectedLinks = makeLinks(0, 3, 1);
|
||||
provider.notifyManyLinksChanged();
|
||||
|
||||
// Since _populateProviderCache() is async, we must wait until the provider's
|
||||
// populate promise has been resolved.
|
||||
yield NewTabUtils.links._providers.get(provider).populatePromise;
|
||||
|
||||
// NewTabUtils.links will now repopulate its cache
|
||||
// NewTabUtils.links will now repopulate its cache, which is sync since
|
||||
// the provider's getLinks is sync.
|
||||
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
||||
|
||||
NewTabUtils.links.removeProvider(provider);
|
||||
@ -200,14 +138,15 @@ add_task(function oneProviderAlreadyCached() {
|
||||
NewTabUtils.initWithoutProviders();
|
||||
NewTabUtils.links.addProvider(provider1);
|
||||
|
||||
yield new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
||||
// This is sync since the provider's getLinks is sync.
|
||||
NewTabUtils.links.populateCache(function () {}, false);
|
||||
do_check_links(NewTabUtils.links.getLinks(), links1);
|
||||
|
||||
let links2 = makeLinks(10, 20, 1);
|
||||
let provider2 = new TestProvider(done => done(links2));
|
||||
NewTabUtils.links.addProvider(provider2);
|
||||
|
||||
yield new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
||||
NewTabUtils.links.populateCache(function () {}, false);
|
||||
do_check_links(NewTabUtils.links.getLinks(), links2.concat(links1));
|
||||
|
||||
NewTabUtils.links.removeProvider(provider1);
|
||||
@ -223,7 +162,8 @@ add_task(function newLowRankedLink() {
|
||||
NewTabUtils.initWithoutProviders();
|
||||
NewTabUtils.links.addProvider(provider);
|
||||
|
||||
yield new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
||||
// This is sync since the provider's getLinks is sync.
|
||||
NewTabUtils.links.populateCache(function () {}, false);
|
||||
do_check_links(NewTabUtils.links.getLinks(), links);
|
||||
|
||||
// Notify of a new link that's low-ranked enough not to make the list.
|
||||
@ -302,19 +242,16 @@ TestProvider.prototype = {
|
||||
addObserver: function (observer) {
|
||||
this._observers.add(observer);
|
||||
},
|
||||
notifyLinkChanged: function (link, index=-1, deleted=false) {
|
||||
this._notifyObservers("onLinkChanged", link, index, deleted);
|
||||
notifyLinkChanged: function (link) {
|
||||
this._notifyObservers("onLinkChanged", link);
|
||||
},
|
||||
notifyManyLinksChanged: function () {
|
||||
this._notifyObservers("onManyLinksChanged");
|
||||
},
|
||||
_notifyObservers: function () {
|
||||
let observerMethodName = arguments[0];
|
||||
let args = Array.prototype.slice.call(arguments, 1);
|
||||
args.unshift(this);
|
||||
_notifyObservers: function (observerMethodName, arg) {
|
||||
for (let obs of this._observers) {
|
||||
if (obs[observerMethodName])
|
||||
obs[observerMethodName].apply(NewTabUtils.links, args);
|
||||
obs[observerMethodName](this, arg);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user