Merge pull request #970 from sarracini/replace_simple_storage
feat(addon): #928 Replace simplestorage to read/write from metadata db
This commit is contained in:
Коммит
2fc7a046d5
|
@ -19,13 +19,16 @@ function getBackgroundRGB(site) {
|
|||
if (site.favicon_color) {
|
||||
return site.favicon_color;
|
||||
}
|
||||
|
||||
if (site.favicons && site.favicons[0] && site.favicons[0].color) {
|
||||
return site.favicons[0].color;
|
||||
}
|
||||
|
||||
if (site.favicon_colors && site.favicon_colors[0] && site.favicon_colors[0].color) {
|
||||
return site.favicon_colors[0].color;
|
||||
}
|
||||
|
||||
const favicon = site.favicon_url || site.favicon;
|
||||
const parsedUrl = site.parsedUrl || urlParse(site.url || "") ;
|
||||
const label = prettyUrl(parsedUrl.hostname);
|
||||
const {favicon, label} = selectSiteProperties(site);
|
||||
return favicon ? DEFAULT_FAVICON_BG_COLOR : getRandomColor(label);
|
||||
}
|
||||
|
||||
|
@ -126,12 +129,18 @@ module.exports.selectNewTabSites = createSelector(
|
|||
}
|
||||
);
|
||||
|
||||
function selectSiteProperties(site) {
|
||||
const metadataFavicon = site.favicons && site.favicons[0] && site.favicons[0].url;
|
||||
const favicon = site.favicon_url || metadataFavicon || site.favicon;
|
||||
const parsedUrl = site.parsedUrl || urlParse(site.url || "") ;
|
||||
const label = prettyUrl(parsedUrl.hostname);
|
||||
return {favicon, parsedUrl, label};
|
||||
}
|
||||
|
||||
const selectSiteIcon = createSelector(
|
||||
site => site,
|
||||
site => {
|
||||
const favicon = site.favicon_url || site.favicon;
|
||||
const parsedUrl = site.parsedUrl || urlParse(site.url || "") ;
|
||||
const label = prettyUrl(parsedUrl.hostname);
|
||||
const {favicon, parsedUrl, label} = selectSiteProperties(site);
|
||||
const backgroundRGB = getBackgroundRGB(site);
|
||||
const backgroundColor = site.background_color || toRGBString(...backgroundRGB, favicon ? BACKGROUND_FADE : 1);
|
||||
const fontColor = getBlackOrWhite(...backgroundRGB);
|
||||
|
|
|
@ -211,6 +211,10 @@ describe("selectors", () => {
|
|||
url: "http://foo.com",
|
||||
favicon_url: "http://foo.com/favicon.ico",
|
||||
favicon: "http://foo.com/favicon-16.ico",
|
||||
favicons: [{
|
||||
colors: [11, 11, 11],
|
||||
url: "http://foo.com/metadatafavicon.ico"
|
||||
}],
|
||||
favicon_colors: [{color: [11, 11, 11]}]
|
||||
};
|
||||
let state;
|
||||
|
@ -230,10 +234,14 @@ describe("selectors", () => {
|
|||
it("should select favicon_url", () => {
|
||||
assert.equal(state.favicon, siteWithFavicon.favicon_url);
|
||||
});
|
||||
it("should fall back to favicon_url", () => {
|
||||
state = selectSiteIcon(Object.assign({}, siteWithFavicon, {favicon_url: null}));
|
||||
it("should fall back to favicon", () => {
|
||||
state = selectSiteIcon(Object.assign({}, siteWithFavicon, {favicon_url: null, favicons: null}));
|
||||
assert.equal(state.favicon, siteWithFavicon.favicon);
|
||||
});
|
||||
it("should use favicons[0].url if exists", () => {
|
||||
state = selectSiteIcon(Object.assign({}, siteWithFavicon, {favicon_url: null}));
|
||||
assert.equal(state.favicon, siteWithFavicon.favicons[0].url);
|
||||
});
|
||||
it("should select the first letter of the hostname", () => {
|
||||
state = selectSiteIcon(Object.assign({}, siteWithFavicon, {url: "http://kate.com"}));
|
||||
assert.equal(state.firstLetter, "k");
|
||||
|
@ -246,7 +254,7 @@ describe("selectors", () => {
|
|||
assert.equal(state.backgroundColor, `rgba(11, 11, 11, ${selectSiteIcon.BACKGROUND_FADE})`);
|
||||
});
|
||||
it("should create an opaque background color if there is no favicon", () => {
|
||||
state = selectSiteIcon(Object.assign({}, siteWithFavicon, {favicon_url: null, favicon: null}));
|
||||
state = selectSiteIcon(Object.assign({}, siteWithFavicon, {favicon_url: null, favicon: null, favicons: null}));
|
||||
assert.equal(state.backgroundColor, "rgba(11, 11, 11, 1)");
|
||||
});
|
||||
it("should create a random background color if no favicon color exists", () => {
|
||||
|
@ -323,12 +331,18 @@ describe("getBackgroundRGB", () => {
|
|||
[11, 11, 11]
|
||||
);
|
||||
});
|
||||
it("should use favicons[0].color if available", () => {
|
||||
assert.deepEqual(
|
||||
getBackgroundRGB({url: "http://foo.com", favicons: [{color: [11, 11, 11]}]}),
|
||||
[11, 11, 11]
|
||||
);
|
||||
});
|
||||
it("should use a default bg if a favicon is supplied", () => {
|
||||
const result = getBackgroundRGB({url: "http://foo.com", favicon_url: "adsd.ico"});
|
||||
assert.ok(result);
|
||||
assert.deepEqual(result, DEFAULT_FAVICON_BG_COLOR);
|
||||
});
|
||||
it("should use a random color if no favicon_colors or favicon", () => {
|
||||
it("should use a random color if no favicon_colors or favicon or favicons[0].color", () => {
|
||||
const result = getBackgroundRGB({url: "http://foo.com"});
|
||||
assert.ok(result);
|
||||
assert.notDeepEqual(result, DEFAULT_FAVICON_BG_COLOR);
|
||||
|
|
|
@ -46,7 +46,6 @@ const DEFAULT_OPTIONS = {
|
|||
pageURL: data.url("content/activity-streams.html"),
|
||||
onAddWorker: null,
|
||||
onRemoveWorker: null,
|
||||
previewCacheTimeout: 21600000, // every 6 hours, rebuild/repopulate the cache
|
||||
placesCacheTimeout: 1800000, // every 30 minutes, rebuild/repopulate the cache
|
||||
recommendationTTL: 3600000, // every hour, get a new recommendation
|
||||
};
|
||||
|
@ -102,14 +101,10 @@ function ActivityStreams(metadataStore, options = {}) {
|
|||
|
||||
this._populatingCache = {
|
||||
places: false,
|
||||
preview: false,
|
||||
};
|
||||
|
||||
this._asyncBuildPlacesCache();
|
||||
|
||||
this._asyncBuildPreviewCache();
|
||||
this._startPeriodicBuildPreviewCache(this.options.previewCacheTimeout);
|
||||
|
||||
// Only create RecommendationProvider if they are in the experiment
|
||||
if (this._experimentProvider.data.recommendedHighlight) {
|
||||
this._recommendationProvider = new RecommendationProvider(this._previewProvider, this._tabTracker);
|
||||
|
@ -124,7 +119,6 @@ ActivityStreams.prototype = {
|
|||
|
||||
_pagemod: null,
|
||||
_button: null,
|
||||
_previewCacheTimeoutID: null,
|
||||
_newRecommendationTimeoutID: null,
|
||||
|
||||
/**
|
||||
|
@ -433,53 +427,6 @@ ActivityStreams.prototype = {
|
|||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Builds a preview cache with links from a normal content page load
|
||||
*/
|
||||
_asyncBuildPreviewCache: Task.async(function*() {
|
||||
if (this._populatingCache && !this._populatingCache.preview) {
|
||||
this._populatingCache.preview = true;
|
||||
let placesLinks = [];
|
||||
let promises = [];
|
||||
|
||||
promises.push(PlacesProvider.links.getTopFrecentSites().then(links => {
|
||||
placesLinks.push(...links);
|
||||
}));
|
||||
|
||||
promises.push(PlacesProvider.links.getRecentBookmarks().then(links => {
|
||||
placesLinks.push(...links);
|
||||
}));
|
||||
|
||||
promises.push(PlacesProvider.links.getRecentLinks().then(links => {
|
||||
placesLinks.push(...links);
|
||||
}));
|
||||
|
||||
promises.push(PlacesProvider.links.getHighlightsLinks().then(links => {
|
||||
placesLinks.push(...links);
|
||||
}));
|
||||
|
||||
yield Promise.all(promises);
|
||||
const event = this._tabTracker.generateEvent({source: "BUILD_PREVIEW_CACHE"});
|
||||
yield this._previewProvider.asyncBuildCache(placesLinks, event);
|
||||
this._populatingCache.preview = false;
|
||||
Services.obs.notifyObservers(null, "activity-streams-previews-cache-complete", null);
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Set up preview cache to be repopulated every 6 hours
|
||||
*/
|
||||
_startPeriodicBuildPreviewCache(previewCacheTimeout) {
|
||||
if (previewCacheTimeout) {
|
||||
// only set a timeout if a non-null value is provided otherwise this will
|
||||
// effectively be an infinite loop
|
||||
this._previewCacheTimeoutID = setTimeout(() => {
|
||||
this._asyncBuildPreviewCache();
|
||||
this._startPeriodicBuildPreviewCache(previewCacheTimeout);
|
||||
}, previewCacheTimeout);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Start a timer to fetch a new recommendation every hour. This will only
|
||||
* run for those in the experiment
|
||||
|
@ -625,7 +572,6 @@ ActivityStreams.prototype = {
|
|||
*/
|
||||
unload(reason) { // eslint-disable-line no-unused-vars
|
||||
let defaultUnload = () => {
|
||||
clearTimeout(this._previewCacheTimeoutID);
|
||||
clearTimeout(this._placesCacheTimeoutID);
|
||||
if (this._newRecommendationTimeoutID) {
|
||||
clearTimeout(this._newRecommendationTimeoutID);
|
||||
|
@ -647,7 +593,6 @@ ActivityStreams.prototype = {
|
|||
this._memoizer.uninit();
|
||||
this._populatingCache = {
|
||||
places: false,
|
||||
preview: false,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -656,7 +601,6 @@ ActivityStreams.prototype = {
|
|||
case "disable":
|
||||
case "uninstall":
|
||||
this._tabTracker.handleUserEvent({event: reason});
|
||||
this._previewProvider.clearCache();
|
||||
this._unsetHomePage();
|
||||
defaultUnload();
|
||||
break;
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
/* globals Task, require, exports, Services */
|
||||
/* globals Task, require, exports */
|
||||
"use strict";
|
||||
|
||||
const {Cu} = require("chrome");
|
||||
const ss = require("sdk/simple-storage");
|
||||
const simplePrefs = require("sdk/simple-prefs");
|
||||
const self = require("sdk/self");
|
||||
const {TippyTopProvider} = require("lib/TippyTopProvider");
|
||||
|
@ -26,12 +25,9 @@ const URL_FILTERS = [
|
|||
Cu.importGlobalProperties(["fetch"]);
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const DEFAULT_OPTIONS = {
|
||||
cacheCleanupPeriod: 86400000, // a cache clearing job runs at most once every 24 hours
|
||||
cacheRefreshAge: 259200000, // refresh a link every 3 days
|
||||
cacheTTL: 2592000000, // cached items expire if they haven't been accessed in 30 days
|
||||
metadataTTL: 3 * 24 * 60 * 60 * 1000, // 3 days for the metadata to live
|
||||
proxyMaxLinks: 25, // number of links embedly proxy accepts per request
|
||||
initFresh: false,
|
||||
};
|
||||
|
@ -47,38 +43,6 @@ function PreviewProvider(tabTracker, metadataStore, options = {}) {
|
|||
|
||||
PreviewProvider.prototype = {
|
||||
|
||||
/**
|
||||
* Clean-up the preview cache
|
||||
*/
|
||||
cleanUpCacheMaybe(force = false) {
|
||||
let currentTime = Date.now();
|
||||
this._setupState(currentTime);
|
||||
|
||||
// exit if the last cleanup exceeds a threshold
|
||||
if (!force && (currentTime - ss.storage.previewCacheState.lastCleanup) < this.options.cacheCleanupPeriod) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let key in ss.storage.embedlyData) {
|
||||
// in case accessTime is not set, don't crash, but don't clean up
|
||||
let accessTime = ss.storage.embedlyData[key].accessTime;
|
||||
if (!accessTime) {
|
||||
ss.storage.embedlyData[key].accessTime = Date.now();
|
||||
}
|
||||
if ((currentTime - accessTime) > this.options.cacheTTL) {
|
||||
delete ss.storage.embedlyData[key];
|
||||
}
|
||||
}
|
||||
ss.storage.previewCacheState.lastCleanup = currentTime;
|
||||
Services.obs.notifyObservers(null, "activity-streams-preview-cache-cleanup", null);
|
||||
},
|
||||
|
||||
_setupState(stateTime) {
|
||||
if (!ss.storage.previewCacheState) {
|
||||
ss.storage.previewCacheState = {lastCleanup: stateTime};
|
||||
}
|
||||
},
|
||||
|
||||
_onPrefChange(prefName) {
|
||||
if (ALLOWED_PREFS.has(prefName)) {
|
||||
switch (prefName) {
|
||||
|
@ -86,12 +50,6 @@ PreviewProvider.prototype = {
|
|||
this._embedlyEndpoint = simplePrefs.prefs[EMBEDLY_PREF];
|
||||
break;
|
||||
case ENABLED_PREF:
|
||||
if (this.enabled) {
|
||||
this.clearCache();
|
||||
} else {
|
||||
// if enabling, create cache
|
||||
ss.storage.embedlyData = {};
|
||||
}
|
||||
this.enabled = simplePrefs.prefs[ENABLED_PREF];
|
||||
break;
|
||||
}
|
||||
|
@ -108,7 +66,7 @@ PreviewProvider.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Santize the URL to remove any unwanted or sensitive information about the link
|
||||
* Sanitize the URL to remove any unwanted or sensitive information about the link
|
||||
*/
|
||||
_sanitizeURL(url) {
|
||||
if (!url) {
|
||||
|
@ -179,7 +137,7 @@ PreviewProvider.prototype = {
|
|||
.map(link => {
|
||||
const sanitizedURL = this._sanitizeURL(link.url);
|
||||
const cacheKey = this._createCacheKey(sanitizedURL);
|
||||
return Object.assign({}, link, {sanitized_url: sanitizedURL, cache_key: cacheKey});
|
||||
return Object.assign({}, link, {sanitized_url: sanitizedURL, cache_key: cacheKey, places_url: link.url});
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -211,9 +169,8 @@ PreviewProvider.prototype = {
|
|||
this._asyncSaveLinks(processedLinks, event);
|
||||
}
|
||||
|
||||
let cachedLinks = this._getEnhancedLinks(processedLinks, previewsOnly, event);
|
||||
return this._getFaviconColors(cachedLinks).then(linksToSend => {
|
||||
return linksToSend;
|
||||
return this._asyncGetEnhancedLinks(processedLinks, previewsOnly, event).then(cachedLinks => {
|
||||
return this._getFaviconColors(cachedLinks);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -222,14 +179,16 @@ PreviewProvider.prototype = {
|
|||
* Also, collect some metrics on how many links were returned by PlacesProvider vs how
|
||||
* how many were returned by the cache
|
||||
*/
|
||||
_getEnhancedLinks(processedLinks, previewsOnly, event) {
|
||||
_asyncGetEnhancedLinks: Task.async(function*(processedLinks, previewsOnly, event) {
|
||||
this._tabTracker.handlePerformanceEvent(event, "previewCacheRequest", processedLinks.length);
|
||||
if (!this.enabled) {
|
||||
return processedLinks;
|
||||
}
|
||||
|
||||
let now = Date.now();
|
||||
|
||||
// Collect all items in the DB that we requested and create a mapping between that
|
||||
// object's metadata and it's cache key
|
||||
let dbLinks = yield this._asyncFindItemsInDB(processedLinks);
|
||||
let existingLinks = new Map();
|
||||
dbLinks.forEach(item => existingLinks.set(item.cache_key, item));
|
||||
let results = processedLinks.map(link => {
|
||||
if (!link) {
|
||||
return link;
|
||||
|
@ -238,54 +197,40 @@ PreviewProvider.prototype = {
|
|||
// Add tippy top data, if available
|
||||
link = this._tippyTopProvider.processSite(link);
|
||||
|
||||
if (link.cache_key && ss.storage.embedlyData[link.cache_key]) {
|
||||
ss.storage.embedlyData[link.cache_key].accessTime = now;
|
||||
return Object.assign({}, ss.storage.embedlyData[link.cache_key], link);
|
||||
// Find the item in the map and return it if it exists
|
||||
if (existingLinks.has(link.cache_key)) {
|
||||
return Object.assign({}, existingLinks.get(link.cache_key), link);
|
||||
} else {
|
||||
return previewsOnly ? null : link;
|
||||
}
|
||||
})
|
||||
.filter(link => link);
|
||||
}).filter(link => link);
|
||||
|
||||
// gives the opportunity to have at least one run with an old
|
||||
// preview cache. This is for the case where one hasn't opened
|
||||
// the browser since `cacheTTL`
|
||||
this.cleanUpCacheMaybe();
|
||||
this._tabTracker.handlePerformanceEvent(event, "previewCacheHits", results.length);
|
||||
this._tabTracker.handlePerformanceEvent(event, "previewCacheMisses", processedLinks.length - results.length);
|
||||
return results;
|
||||
},
|
||||
}),
|
||||
|
||||
/**
|
||||
* Determine if a cached link has expired
|
||||
* Find the metadata for each link in the database
|
||||
*/
|
||||
_isLinkExpired(link) {
|
||||
const cachedLink = ss.storage.embedlyData[link.cache_key];
|
||||
if (!cachedLink) {
|
||||
return false;
|
||||
}
|
||||
let currentTime = Date.now();
|
||||
return (currentTime - cachedLink.refreshTime) > this.options.cacheRefreshAge;
|
||||
},
|
||||
|
||||
/**
|
||||
* Build the preview cache
|
||||
*/
|
||||
asyncBuildCache: Task.async(function*(placesLinks, event = {}) {
|
||||
let processedLinks = this._processLinks(placesLinks);
|
||||
yield this._asyncSaveLinks(processedLinks, event);
|
||||
_asyncFindItemsInDB: Task.async(function*(links) {
|
||||
const cacheKeyArray = links.map(link => link.cache_key);
|
||||
let linksMetadata = yield this._metadataStore.asyncGetMetadataByCacheKey(cacheKeyArray);
|
||||
return linksMetadata;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Request links from embedly, optionally filtering out known links
|
||||
*/
|
||||
_asyncSaveLinks: Task.async(function*(processedLinks, event, updateAccessTime = true) {
|
||||
_asyncSaveLinks: Task.async(function*(processedLinks, event) {
|
||||
let dbLinks = yield this._asyncFindItemsInDB(processedLinks);
|
||||
let existingLinks = new Set();
|
||||
dbLinks.forEach(item => existingLinks.add(item.cache_key));
|
||||
let linksList = this._uniqueLinks(processedLinks)
|
||||
// If a request is in progress, don't re-request it
|
||||
.filter(link => !this._alreadyRequested.has(link.cache_key))
|
||||
// If we already have the link in the cache, don't request it again...
|
||||
// ... UNLESS it has expired
|
||||
.filter(link => !ss.storage.embedlyData[link.cache_key] || this._isLinkExpired(link));
|
||||
// If we already have the link in the database don't request it again
|
||||
.filter(link => !existingLinks.has(link.cache_key));
|
||||
|
||||
linksList.forEach(link => this._alreadyRequested.add(link.cache_key));
|
||||
|
||||
|
@ -297,7 +242,7 @@ PreviewProvider.prototype = {
|
|||
}
|
||||
// for each bundle of 25 links, create a new request to embedly
|
||||
requestQueue.forEach(requestBundle => {
|
||||
promises.push(this._asyncFetchAndCache(requestBundle, event, updateAccessTime));
|
||||
promises.push(this._asyncFetchAndStore(requestBundle, event));
|
||||
});
|
||||
yield Promise.all(promises);
|
||||
}),
|
||||
|
@ -320,11 +265,11 @@ PreviewProvider.prototype = {
|
|||
}),
|
||||
|
||||
/**
|
||||
* Extracts data from embedly and caches it.
|
||||
* Extracts data from embedly and saves in the MetadataStore
|
||||
* Also, collect metrics on how many requests were made, how much time each
|
||||
* request took to complete, and their success or failure status
|
||||
*/
|
||||
_asyncFetchAndCache: Task.async(function*(newLinks, event, updateAccessTime = true) {
|
||||
_asyncFetchAndStore: Task.async(function*(newLinks, event) {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
@ -342,18 +287,9 @@ PreviewProvider.prototype = {
|
|||
let responseJson = yield response.json();
|
||||
this._tabTracker.handlePerformanceEvent(event, "embedlyProxyRequestReceivedCount", responseJson.urls.length);
|
||||
this._tabTracker.handlePerformanceEvent(event, "embedlyProxyRequestSucess", 1);
|
||||
let currentTime = Date.now();
|
||||
newLinks.forEach(link => {
|
||||
let data = responseJson.urls[link.sanitized_url];
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
ss.storage.embedlyData[link.cache_key] = Object.assign({}, ss.storage.embedlyData[link.cache_key], data);
|
||||
if (updateAccessTime) {
|
||||
ss.storage.embedlyData[link.cache_key].accessTime = currentTime;
|
||||
}
|
||||
ss.storage.embedlyData[link.cache_key].refreshTime = currentTime;
|
||||
});
|
||||
let linksToInsert = newLinks.filter(link => responseJson.urls[link.sanitized_url])
|
||||
.map(link => Object.assign({}, link, responseJson.urls[link.sanitized_url], {expired_at: (this.options.metadataTTL) + Date.now()}));
|
||||
this._metadataStore.asyncInsert(linksToInsert);
|
||||
} else {
|
||||
this._tabTracker.handlePerformanceEvent(event, "embedlyProxyFailure", 1);
|
||||
}
|
||||
|
@ -367,25 +303,13 @@ PreviewProvider.prototype = {
|
|||
}),
|
||||
|
||||
/**
|
||||
* Initialize the simple storage
|
||||
* Initialize Preview Provider
|
||||
*/
|
||||
init() {
|
||||
this._alreadyRequested = new Set();
|
||||
this._embedlyEndpoint = simplePrefs.prefs[EMBEDLY_PREF] + EMBEDLY_VERSION_QUERY + self.version;
|
||||
this.enabled = simplePrefs.prefs[ENABLED_PREF];
|
||||
if (!ss.storage.embedlyData || this.options.initFresh) {
|
||||
ss.storage.embedlyData = {};
|
||||
}
|
||||
simplePrefs.on("", this._onPrefChange);
|
||||
this._setupState(Date.now());
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear out the preview cache
|
||||
*/
|
||||
clearCache() {
|
||||
delete ss.storage.previewCacheState;
|
||||
delete ss.storage.embedlyData;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -57,7 +57,9 @@ function getTestActivityStream(options = {}) {
|
|||
const mockMetadataStore = {
|
||||
asyncConnect() { return Promise.resolve();},
|
||||
asyncReset() { return Promise.resolve();},
|
||||
asyncClose() { return Promise.resolve();}
|
||||
asyncClose() { return Promise.resolve();},
|
||||
asyncInsert() { return Promise.resolve();},
|
||||
asyncGetMetadataByCacheKey() { return Promise.resolve([]);},
|
||||
};
|
||||
let mockApp = new ActivityStreams(mockMetadataStore, options);
|
||||
return mockApp;
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
/* globals XPCOMUtils */
|
||||
|
||||
"use strict";
|
||||
const {Cu} = require("chrome");
|
||||
const {before, after} = require("sdk/test/utils");
|
||||
const test = require("sdk/test");
|
||||
const {getTestActivityStream} = require("./lib/utils");
|
||||
const simplePrefs = require("sdk/simple-prefs");
|
||||
const {PlacesProvider} = require("lib/PlacesProvider");
|
||||
const {PreviewProvider} = require("lib/PreviewProvider");
|
||||
const {makeCachePromise, makeCountingCachePromise} = require("./lib/cachePromises");
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
let gInitialCachePref = simplePrefs.prefs["query.cache"];
|
||||
let gPreviewProvider;
|
||||
|
||||
exports["test preview cache repopulation works"] = function*(assert) {
|
||||
let placesCachePromise;
|
||||
let previewsCachePromise;
|
||||
|
||||
placesCachePromise = makeCachePromise("places");
|
||||
previewsCachePromise = makeCachePromise("previews");
|
||||
let app = getTestActivityStream({previewCacheTimeout: 100});
|
||||
yield placesCachePromise;
|
||||
yield previewsCachePromise;
|
||||
|
||||
let expectedRepopulations = 3;
|
||||
let previewsCountPromise = makeCountingCachePromise("previews", expectedRepopulations);
|
||||
let numRepopulations = yield previewsCountPromise;
|
||||
|
||||
assert.equal(numRepopulations, expectedRepopulations, "preview cache successfully repopulated periodically");
|
||||
app.unload();
|
||||
};
|
||||
|
||||
exports["test places cache repopulation works"] = function*(assert) {
|
||||
let placesCachePromise = makeCachePromise("places");
|
||||
let app = getTestActivityStream({placesCacheTimeout: 100});
|
||||
yield placesCachePromise;
|
||||
|
||||
let expectedRepopulations = 3;
|
||||
let placesCountPromise = makeCountingCachePromise("places", expectedRepopulations);
|
||||
let numRepopulations = yield placesCountPromise;
|
||||
|
||||
assert.equal(numRepopulations, expectedRepopulations, "places cache successfully repopulated periodically");
|
||||
app.unload();
|
||||
};
|
||||
|
||||
before(exports, function*() {
|
||||
simplePrefs.prefs["query.cache"] = true;
|
||||
PlacesProvider.links.init();
|
||||
gPreviewProvider = new PreviewProvider({initFresh: true});
|
||||
});
|
||||
|
||||
after(exports, function() {
|
||||
gPreviewProvider.clearCache();
|
||||
gPreviewProvider.uninit();
|
||||
PlacesProvider.links.uninit();
|
||||
simplePrefs.prefs["query.cache"] = gInitialCachePref || false;
|
||||
});
|
||||
|
||||
test.run(exports);
|
|
@ -0,0 +1,142 @@
|
|||
/* globals require, exports */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {before, after, waitUntil} = require("sdk/test/utils");
|
||||
const simplePrefs = require("sdk/simple-prefs");
|
||||
const {Loader} = require("sdk/test/loader");
|
||||
const loader = Loader(module);
|
||||
const httpd = loader.require("./lib/httpd");
|
||||
const {PreviewProvider} = require("lib/PreviewProvider");
|
||||
const {MetadataStore} = require("lib/MetadataStore");
|
||||
const {metadataFixture} = require("./lib/MetastoreFixture.js");
|
||||
|
||||
const gMetadataStore = new MetadataStore();
|
||||
const gPort = 8079;
|
||||
let gPreviewProvider;
|
||||
let gPrefEmbedly = simplePrefs.prefs["embedly.endpoint"];
|
||||
let gPrefEnabled = simplePrefs.prefs["previews.enabled"];
|
||||
|
||||
exports.test_metadatastore_saves_new_links = function*(assert) {
|
||||
// to start, put some links in the database
|
||||
yield gMetadataStore.asyncInsert(metadataFixture);
|
||||
let items = yield gMetadataStore.asyncExecuteQuery("SELECT * FROM page_metadata");
|
||||
assert.equal(items.length, 3, "sanity check that we only have 3 items in the database to start");
|
||||
|
||||
// these are links we are going to request - the first two should get filtered out
|
||||
const links = [
|
||||
{cache_key: "https://www.mozilla.org/", places_url: "https://www.mozilla.org/"},
|
||||
{cache_key: "https://www.mozilla.org/en-US/firefox/new/", places_url: "https://www.mozilla.org/en-US/firefox/new"},
|
||||
{cache_key: "https://notinDB.com/", places_url: "https://www.notinDB.com/", sanitized_url: "https://www.notinDB.com/"}];
|
||||
const fakeResponse = {"urls": {
|
||||
"https://www.notinDB.com/": {
|
||||
"embedlyMetaData": "some embedly metadata"
|
||||
}
|
||||
}};
|
||||
|
||||
let srv = httpd.startServerAsync(gPort);
|
||||
srv.registerPathHandler("/previewProviderMetadataStore", function handle(request, response) {
|
||||
response.setHeader("Content-Type", "application/json", false);
|
||||
response.write(JSON.stringify(fakeResponse));
|
||||
});
|
||||
|
||||
// only request the items that are not in the database and wait for them to
|
||||
// successfully be inserted
|
||||
yield gPreviewProvider._asyncSaveLinks(links);
|
||||
|
||||
// asyncSaveLinks doesn't yield on inserting in the db so we need to wait
|
||||
// until it has successfully finished the transaction before checking
|
||||
yield waitUntil(() => !gMetadataStore.transactionInProgress);
|
||||
|
||||
// check that it inserted the link that was filtered out
|
||||
items = yield gMetadataStore.asyncExecuteQuery("SELECT * FROM page_metadata");
|
||||
assert.equal(items.length, 4, "it should now have a length of 4");
|
||||
assert.equal(items[3][1], links[2].cache_key, "it newly inserted the one we didn't already have");
|
||||
|
||||
yield new Promise(resolve => {
|
||||
srv.stop(resolve);
|
||||
});
|
||||
};
|
||||
|
||||
exports.test_find_correct_links = function*(assert) {
|
||||
yield gMetadataStore.asyncInsert(metadataFixture);
|
||||
const links = [
|
||||
{cache_key: "https://www.mozilla.org/", places_url: "https://www.mozilla.org/"},
|
||||
{cache_key: "https://www.mozilla.org/en-US/firefox/new/", places_url: "https://www.mozilla.org/en-US/firefox/new"},
|
||||
{cache_key: "https://www.notinDB.com/", places_url: "https://www.notinDB.com/"}];
|
||||
|
||||
// find the items in the database, based on their cache keys
|
||||
const dbLinks = yield gPreviewProvider._asyncFindItemsInDB(links);
|
||||
assert.equal(dbLinks.length, 2, "returned two items out of the three based on their cache_key");
|
||||
assert.equal(dbLinks[0].cache_key, links[0].cache_key, "correctly returned the first link");
|
||||
assert.equal(dbLinks[1].cache_key, links[1].cache_key, "correctly returned the second link");
|
||||
};
|
||||
|
||||
exports.test_get_links_from_metadatastore = function*(assert) {
|
||||
yield gMetadataStore.asyncInsert(metadataFixture);
|
||||
const links = [
|
||||
{cache_key: "https://www.mozilla.org/", places_url: "https://www.mozilla.org/"},
|
||||
{cache_key: "https://www.mozilla.org/en-US/firefox/new/", places_url: "https://www.mozilla.org/en-US/firefox/new"},
|
||||
{cache_key: "https://www.notinDB.com/", places_url: "https://www.notinDB.com/"}];
|
||||
|
||||
// get enhanced links - the third link should be returned as is since it
|
||||
// is not yet in the database
|
||||
let cachedLinks = yield gPreviewProvider._asyncGetEnhancedLinks(links);
|
||||
assert.equal(cachedLinks.length, 3, "returned all 3 links");
|
||||
assert.deepEqual(cachedLinks[2], links[2], "the third link was untouched");
|
||||
|
||||
// get enhanced links after third link has been inserted in db - the third
|
||||
// link should now have more properties i.e title, description etc...
|
||||
yield gMetadataStore.asyncInsert([links[2]]);
|
||||
cachedLinks = yield gPreviewProvider._asyncGetEnhancedLinks(links);
|
||||
assert.equal(cachedLinks.length, 3, "returned all 3 links");
|
||||
assert.equal(cachedLinks[2].title, null, "the third link has a title field");
|
||||
assert.equal(cachedLinks[2].description, null, "the third links has a description field");
|
||||
assert.deepEqual(cachedLinks[2].images, [], "the third links has images field");
|
||||
assert.deepEqual(cachedLinks[2].favicons, [], "the third links has favicons field");
|
||||
};
|
||||
|
||||
function waitForAsyncReset() {
|
||||
return waitUntil(function*() {
|
||||
if (gMetadataStore.transactionInProgress) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
let nMetadata = yield gMetadataStore.asyncExecuteQuery(
|
||||
"SELECT count(*) as count FROM page_metadata",
|
||||
{"columns": ["count"]});
|
||||
let nImages = yield gMetadataStore.asyncExecuteQuery(
|
||||
"SELECT count(*) as count FROM page_images",
|
||||
{"columns": ["count"]});
|
||||
let nMetadataImages = yield gMetadataStore.asyncExecuteQuery(
|
||||
"SELECT count(*) as count FROM page_metadata_images",
|
||||
{"columns": ["count"]});
|
||||
return !nMetadata[0].count &&
|
||||
!nImages[0].count &&
|
||||
!nMetadataImages[0].count;
|
||||
} catch (e) {
|
||||
/* ignore whatever error that makes the query above fail */
|
||||
return false;
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
|
||||
before(exports, function*() {
|
||||
simplePrefs.prefs["embedly.endpoint"] = `http://localhost:${gPort}/previewProviderMetadataStore`;
|
||||
simplePrefs.prefs["previews.enabled"] = true;
|
||||
yield gMetadataStore.asyncConnect();
|
||||
let mockTabTracker = {handlePerformanceEvent: function() {}, generateEvent: function() {}};
|
||||
gPreviewProvider = new PreviewProvider(mockTabTracker, gMetadataStore, {initFresh: true});
|
||||
});
|
||||
|
||||
after(exports, function*() {
|
||||
simplePrefs.prefs["embedly.endpoint"] = gPrefEmbedly;
|
||||
simplePrefs.prefs["previews.enabled"] = gPrefEnabled;
|
||||
yield gMetadataStore.asyncReset();
|
||||
yield waitForAsyncReset();
|
||||
yield gMetadataStore.asyncClose();
|
||||
gPreviewProvider.uninit();
|
||||
});
|
||||
|
||||
require("sdk/test").run(exports);
|
|
@ -1,4 +1,4 @@
|
|||
/* globals require, exports, Services, NetUtil */
|
||||
/* globals require, exports, NetUtil */
|
||||
|
||||
"use strict";
|
||||
|
||||
|
@ -6,10 +6,8 @@ const {before, after} = require("sdk/test/utils");
|
|||
const simplePrefs = require("sdk/simple-prefs");
|
||||
const self = require("sdk/self");
|
||||
const {Loader} = require("sdk/test/loader");
|
||||
const {setTimeout} = require("sdk/timers");
|
||||
const loader = Loader(module);
|
||||
const httpd = loader.require("./lib/httpd");
|
||||
const ss = require("sdk/simple-storage");
|
||||
const {Cu} = require("chrome");
|
||||
const {PreviewProvider} = require("lib/PreviewProvider");
|
||||
const ALLOWED_PROTOCOLS = new Set(["http:", "https:"]);
|
||||
|
@ -22,88 +20,14 @@ const URL_FILTERS = [
|
|||
];
|
||||
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
const gPort = 8089;
|
||||
let gPreviewProvider;
|
||||
let gMetadataStore = [];
|
||||
let gPrefEmbedly = simplePrefs.prefs["embedly.endpoint"];
|
||||
let gPrefEnabled = simplePrefs.prefs["previews.enabled"];
|
||||
|
||||
exports.test_cache_invalidation = function*(assert) {
|
||||
let currentTime = Date.now();
|
||||
let fortyDaysAgo = currentTime - (40 * 24 * 60 * 60 * 1000);
|
||||
ss.storage.embedlyData.item_1 = {accessTime: fortyDaysAgo};
|
||||
ss.storage.embedlyData.item_2 = {accessTime: currentTime};
|
||||
assert.equal(Object.keys(ss.storage.embedlyData).length, 2, "items set");
|
||||
gPreviewProvider.cleanUpCacheMaybe(true);
|
||||
assert.equal(Object.keys(ss.storage.embedlyData).length, 1, "items cleaned up");
|
||||
};
|
||||
|
||||
exports.test_enabling = function*(assert) {
|
||||
assert.equal(Object.keys(ss.storage.embedlyData).length, 0, "empty object");
|
||||
simplePrefs.prefs["previews.enabled"] = false;
|
||||
assert.equal(ss.storage.embedlyData, undefined, "embedlyData is undefined");
|
||||
simplePrefs.prefs["previews.enabled"] = true;
|
||||
assert.equal(Object.keys(ss.storage.embedlyData).length, 0, "empty object");
|
||||
};
|
||||
|
||||
exports.test_access_update = function*(assert) {
|
||||
let currentTime = Date.now();
|
||||
let twoDaysAgo = currentTime - (2 * 24 * 60 * 60 * 1000);
|
||||
ss.storage.embedlyData.item_1 = {accessTime: twoDaysAgo};
|
||||
gPreviewProvider._getEnhancedLinks([{cache_key: "item_1"}]);
|
||||
assert.ok(ss.storage.embedlyData.item_1.accessTime > twoDaysAgo, "access time is updated");
|
||||
};
|
||||
|
||||
exports.test_long_hibernation = function*(assert) {
|
||||
let currentTime = Date.now();
|
||||
let fortyDaysAgo = currentTime - (40 * 24 * 60 * 60 * 1000);
|
||||
ss.storage.embedlyData.item_1 = {accessTime: fortyDaysAgo};
|
||||
gPreviewProvider._getEnhancedLinks([{cache_key: "item_1"}]);
|
||||
assert.ok(ss.storage.embedlyData.item_1.accessTime >= currentTime, "access time is updated");
|
||||
};
|
||||
|
||||
exports.test_periodic_cleanup = function*(assert) {
|
||||
let oldThreshold = gPreviewProvider.options.cacheCleanupPeriod;
|
||||
gPreviewProvider.options.cacheCleanupPeriod = 30;
|
||||
|
||||
let countingCleanupPromise = new Promise(resolve => {
|
||||
let notif = "activity-streams-preview-cache-cleanup";
|
||||
let count = 0;
|
||||
let waitForNotif = (subject, topic, data) => {
|
||||
if (topic === notif) {
|
||||
count++;
|
||||
if (count === 3) {
|
||||
Services.obs.removeObserver(waitForNotif, notif);
|
||||
resolve(count);
|
||||
}
|
||||
}
|
||||
};
|
||||
Services.obs.addObserver(waitForNotif, notif);
|
||||
});
|
||||
|
||||
let countingRunsPromise = new Promise(resolve => {
|
||||
let runCount = 0;
|
||||
let periodicCleanups = () => {
|
||||
setTimeout(() => {
|
||||
gPreviewProvider.cleanUpCacheMaybe();
|
||||
runCount++;
|
||||
if (runCount >= 6) {
|
||||
resolve(runCount);
|
||||
} else {
|
||||
periodicCleanups();
|
||||
}
|
||||
}, 20);
|
||||
};
|
||||
periodicCleanups();
|
||||
});
|
||||
|
||||
let values = yield Promise.all([countingRunsPromise, countingCleanupPromise]);
|
||||
assert.equal(JSON.stringify(values), JSON.stringify([6, 3]), "expected counts are obtained");
|
||||
gPreviewProvider.options.cacheCleanupPeriod = oldThreshold;
|
||||
};
|
||||
|
||||
exports.test_only_request_links_once = function*(assert) {
|
||||
const msg1 = [{"url": "a.com", "sanitized_url": "a.com", "cache_key": "a.com"},
|
||||
{"url": "b.com", "sanitized_url": "b.com", "cache_key": "b.com"},
|
||||
|
@ -124,15 +48,18 @@ exports.test_only_request_links_once = function*(assert) {
|
|||
request.bodyInputStream.available()
|
||||
)
|
||||
);
|
||||
// count the times each url has been requested
|
||||
data.urls.forEach(url => urlsRequested[url] = (urlsRequested[url] + 1) || 1);
|
||||
response.setHeader("Content-Type", "application/json", false);
|
||||
response.write(JSON.stringify({"urls": {urlsRequested}}));
|
||||
});
|
||||
|
||||
// request 'b.com' and 'c.com' twice
|
||||
gPreviewProvider._asyncSaveLinks(msg1);
|
||||
yield gPreviewProvider._asyncSaveLinks(msg2);
|
||||
|
||||
for (let url in urlsRequested) {
|
||||
// each url should have a count of just one
|
||||
assert.equal(urlsRequested[url], 1, "URL was requested only once");
|
||||
}
|
||||
|
||||
|
@ -141,49 +68,6 @@ exports.test_only_request_links_once = function*(assert) {
|
|||
});
|
||||
};
|
||||
|
||||
exports.test_is_link_expired = function(assert) {
|
||||
const refreshTime = Date.now() - (gPreviewProvider.options.cacheRefreshAge + 1000);
|
||||
ss.storage.embedlyData["a.com"] = {"url": "a.com", "sanitized_url": "a.com", "cache_key": "a.com", refreshTime};
|
||||
assert.equal(gPreviewProvider._isLinkExpired({cache_key: "a.com"}), true, "expired link should return true");
|
||||
ss.storage.embedlyData["b.com"] = {"url": "b.com", "sanitized_url": "b.com", "cache_key": "b.com", refreshTime: new Date()};
|
||||
assert.equal(gPreviewProvider._isLinkExpired({cache_key: "b.com"}), false, "non-expired link should return false");
|
||||
};
|
||||
|
||||
exports.test_request_links_if_expired = function*(assert) {
|
||||
const oldTime = Date.now() - (gPreviewProvider.options.cacheRefreshAge + 1000);
|
||||
const links = [{"url": "a.com", "sanitized_url": "a.com", "cache_key": "a.com"},
|
||||
{"url": "b.com", "sanitized_url": "b.com", "cache_key": "b.com"},
|
||||
{"url": "c.com", "sanitized_url": "c.com", "cache_key": "c.com"}];
|
||||
links.forEach(link => {
|
||||
ss.storage.embedlyData[link.cache_key] = Object.assign({}, link, {refreshTime: new Date()});
|
||||
});
|
||||
ss.storage.embedlyData["a.com"].refreshTime = oldTime;
|
||||
|
||||
assert.ok(gPreviewProvider._embedlyEndpoint, "The embedly endpoint is set");
|
||||
let srv = httpd.startServerAsync(gPort);
|
||||
|
||||
let urlsRequested = [];
|
||||
srv.registerPathHandler("/embedlyLinkData", function handle(request, response) {
|
||||
let data = JSON.parse(
|
||||
NetUtil.readInputStreamToString(
|
||||
request.bodyInputStream,
|
||||
request.bodyInputStream.available()
|
||||
)
|
||||
);
|
||||
data.urls.forEach(url => urlsRequested.push(url));
|
||||
response.setHeader("Content-Type", "application/json", false);
|
||||
response.write(JSON.stringify({"urls": {urlsRequested}}));
|
||||
});
|
||||
|
||||
yield gPreviewProvider._asyncSaveLinks(links);
|
||||
|
||||
assert.deepEqual(urlsRequested, ["a.com"], "we should only request the expired URL");
|
||||
|
||||
yield new Promise(resolve => {
|
||||
srv.stop(resolve);
|
||||
});
|
||||
};
|
||||
|
||||
exports.test_filter_urls = function*(assert) {
|
||||
const fakeData = {
|
||||
get validLinks() {
|
||||
|
@ -262,14 +146,17 @@ exports.test_process_links = function*(assert) {
|
|||
{"url": "https://foo.com/", "title": "blah"}
|
||||
];
|
||||
|
||||
// process the links
|
||||
const processedLinks = gPreviewProvider._processLinks(fakeData);
|
||||
|
||||
assert.equal(fakeData.length, processedLinks.length, "should not deduplicate or remove any links");
|
||||
|
||||
// check that each link has added the correct fields
|
||||
processedLinks.forEach((link, i) => {
|
||||
assert.equal(link.url, fakeData[i].url, "each site has its original url");
|
||||
assert.ok(link.sanitized_url, "links have sanitizedURLs");
|
||||
assert.ok(link.cache_key, "links have cacheKeys");
|
||||
assert.ok(link.sanitized_url, "link has a sanitized url");
|
||||
assert.ok(link.cache_key, "link has a cache key");
|
||||
assert.ok(link.places_url, "link has a places url");
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -331,17 +218,21 @@ exports.test_throw_out_non_requested_responses = function*(assert) {
|
|||
|
||||
yield gPreviewProvider._asyncSaveLinks(fakeData);
|
||||
|
||||
// cache should contain example1.com and example2.com
|
||||
assert.ok(ss.storage.embedlyData[fakeSite1.cache_key].embedlyMetaData, "first site was saved as expected");
|
||||
assert.ok(ss.storage.embedlyData[fakeSite2.cache_key].embedlyMetaData, "second site was saved as expected");
|
||||
// cache should not contain example3.com and example4.com
|
||||
assert.throws(() => ss.storage.embedlyData[fakeSite3.cache_key].embedlyMetaData, "third site was not found in the cache");
|
||||
assert.throws(() => ss.storage.embedlyData[fakeSite4.cache_key].embedlyMetaData, "fourth site was not found in the cache");
|
||||
// database should contain example1.com and example2.com
|
||||
assert.equal(gMetadataStore[0].length, 2, "saved two items");
|
||||
assert.equal(gMetadataStore[0][0].url, fakeSite1.url, "first site was saved as expected");
|
||||
assert.equal(gMetadataStore[0][1].url, fakeSite2.url, "second site was saved as expected");
|
||||
|
||||
// database should not contain example3.com and example4.com
|
||||
gMetadataStore[0].forEach(item => {
|
||||
assert.ok(item.url !== fakeSite3.url, "third site was not saved");
|
||||
assert.ok(item.url !== fakeSite4.url, "fourth site was not saved");
|
||||
});
|
||||
|
||||
yield new Promise(resolve => {
|
||||
srv.stop(resolve);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
exports.test_mock_embedly_request = function*(assert) {
|
||||
const fakeSite = {
|
||||
|
@ -355,8 +246,8 @@ exports.test_mock_embedly_request = function*(assert) {
|
|||
"sanitized_url": "http://example.com/",
|
||||
"cache_key": "example.com/"
|
||||
};
|
||||
const fakeData = [fakeSite];
|
||||
const fakeDataCached = {"urls": {
|
||||
const fakeRequest = [fakeSite];
|
||||
const fakeResponse = {"urls": {
|
||||
"http://example.com/": {
|
||||
"embedlyMetaData": "some embedly metadata"
|
||||
}
|
||||
|
@ -370,18 +261,21 @@ exports.test_mock_embedly_request = function*(assert) {
|
|||
// first, check that the version included in the query string
|
||||
assert.deepEqual(`${request.queryString}`, `${embedlyVersionQuery}${self.version}`, "we're hitting the correct endpoint");
|
||||
response.setHeader("Content-Type", "application/json", false);
|
||||
response.write(JSON.stringify(fakeDataCached));
|
||||
response.write(JSON.stringify(fakeResponse));
|
||||
});
|
||||
|
||||
yield gPreviewProvider._asyncSaveLinks(fakeData);
|
||||
// make a request to embedly with 'fakeSite'
|
||||
yield gPreviewProvider._asyncSaveLinks(fakeRequest);
|
||||
|
||||
assert.deepEqual(ss.storage.embedlyData[fakeSite.cache_key].embedlyMetaData, "some embedly metadata", "the cache saved the embedly data");
|
||||
assert.ok(ss.storage.embedlyData[fakeSite.cache_key].accessTime, "the cached saved a time stamp");
|
||||
// we should have saved the fake site into the database
|
||||
assert.deepEqual(gMetadataStore[0][0].embedlyMetaData, "some embedly metadata", "inserted and saved the embedly data");
|
||||
assert.ok(gMetadataStore[0][0].expired_at, "an expiry time was added");
|
||||
|
||||
let cachedLinks = gPreviewProvider._getEnhancedLinks(fakeData);
|
||||
// retrieve the contents of the database - don't go to embedly
|
||||
let cachedLinks = yield gPreviewProvider._asyncGetEnhancedLinks(fakeRequest);
|
||||
assert.equal(cachedLinks[0].lastVisitDate, fakeSite.lastVisitDate, "getEnhancedLinks should prioritize new data");
|
||||
assert.equal(cachedLinks[0].bookmarkDateCreated, fakeSite.bookmarkDateCreated, "getEnhancedLinks should prioritize new data");
|
||||
assert.ok(ss.storage.embedlyData[fakeSite.cache_key], "the cached link is now retrieved next time");
|
||||
assert.deepEqual(gMetadataStore[0][0].cache_key, cachedLinks[0].cache_key, "the cached link is now retrieved next time");
|
||||
|
||||
yield new Promise(resolve => {
|
||||
srv.stop(resolve);
|
||||
|
@ -393,32 +287,47 @@ exports.test_get_enhanced_disabled = function*(assert) {
|
|||
{url: "http://foo.com/", lastVisitDate: 1459537019061}
|
||||
];
|
||||
simplePrefs.prefs["previews.enabled"] = false;
|
||||
let cachedLinks = gPreviewProvider._getEnhancedLinks(fakeData);
|
||||
let cachedLinks = yield gPreviewProvider._asyncGetEnhancedLinks(fakeData);
|
||||
assert.deepEqual(cachedLinks, fakeData, "if disabled, should return links as is");
|
||||
};
|
||||
|
||||
exports.test_get_enhanced_previews_only = function*(assert) {
|
||||
ss.storage.embedlyData["example.com/"] = {sanitized_url: "http://example.com/", cache_key: "example.com/", url: "http://example.com/"};
|
||||
gMetadataStore[0] = {sanitized_url: "http://example.com/", cache_key: "example.com/", url: "http://example.com/"};
|
||||
let links;
|
||||
|
||||
links = gPreviewProvider._getEnhancedLinks([{cache_key: "example.com/"}, {cache_key: "foo.com"}]);
|
||||
links = yield gPreviewProvider._asyncGetEnhancedLinks([{cache_key: "example.com/"}, {cache_key: "foo.com"}]);
|
||||
assert.equal(links.length, 2, "by default getEnhancedLinks returns links with and without previews");
|
||||
|
||||
links = gPreviewProvider._getEnhancedLinks([{cache_key: "example.com/"}, {cache_key: "foo.com"}], true);
|
||||
links = yield gPreviewProvider._asyncGetEnhancedLinks([{cache_key: "example.com/"}, {cache_key: "foo.com"}], true);
|
||||
assert.equal(links.length, 1, "when previewOnly is set, return only links with previews");
|
||||
};
|
||||
|
||||
before(exports, function*() {
|
||||
simplePrefs.prefs["embedly.endpoint"] = `http://localhost:${gPort}/embedlyLinkData`;
|
||||
simplePrefs.prefs["previews.enabled"] = true;
|
||||
let mockMetadataStore = {
|
||||
asyncInsert: function(data) {
|
||||
gMetadataStore.push(data);
|
||||
return gMetadataStore;
|
||||
},
|
||||
asyncGetMetadataByCacheKey: function(cacheKeys) {
|
||||
let items = [];
|
||||
gMetadataStore.forEach(item => {
|
||||
if (cacheKeys.includes(item.cache_key)) {
|
||||
items.push(Object.assign({}, {cache_key: item.cache_key}, {title: `Title for ${item.cache_key}`}));
|
||||
}
|
||||
});
|
||||
return items;
|
||||
}
|
||||
};
|
||||
let mockTabTracker = {handlePerformanceEvent: function() {}, generateEvent: function() {}};
|
||||
gPreviewProvider = new PreviewProvider(mockTabTracker, {initFresh: true});
|
||||
gPreviewProvider = new PreviewProvider(mockTabTracker, mockMetadataStore, {initFresh: true});
|
||||
});
|
||||
|
||||
after(exports, function*() {
|
||||
simplePrefs.prefs["embedly.endpoint"] = gPrefEmbedly;
|
||||
simplePrefs.prefs["previews.enabled"] = gPrefEnabled;
|
||||
gPreviewProvider.clearCache();
|
||||
gMetadataStore = [];
|
||||
gPreviewProvider.uninit();
|
||||
});
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче