diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index a02a258704fa..39bb89bfa434 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1464,7 +1464,7 @@ pref("browser.newtabpage.rows", 3); // number of columns of newtab grid pref("browser.newtabpage.columns", 3); -pref("browser.newtabpage.directory.source", "chrome://global/content/directoryLinks.json"); +pref("browser.newtabpage.directorySource", "chrome://global/content/directoryLinks.json"); // Enable the DOM fullscreen API. pref("full-screen-api.enabled", true); diff --git a/browser/base/content/newtab/page.js b/browser/base/content/newtab/page.js index 8a81780fd021..758eb0fa94bb 100644 --- a/browser/base/content/newtab/page.js +++ b/browser/base/content/newtab/page.js @@ -217,7 +217,6 @@ let gPage = { } } - DirectoryLinksProvider.reportShownCount(directoryCount); // Record how many directory sites were shown, but place counts over the // default 9 in the same bucket for (let type of Object.keys(directoryCount)) { diff --git a/browser/base/content/test/general/browser_tabopen_reflows.js b/browser/base/content/test/general/browser_tabopen_reflows.js index 945670052b8f..aeaf168019ed 100644 --- a/browser/base/content/test/general/browser_tabopen_reflows.js +++ b/browser/base/content/test/general/browser_tabopen_reflows.js @@ -56,7 +56,7 @@ const EXPECTED_REFLOWS = [ ]; const PREF_PRELOAD = "browser.newtab.preload"; -const PREF_NEWTAB_DIRECTORYSOURCE = "browser.newtabpage.directory.source"; +const PREF_NEWTAB_DIRECTORYSOURCE = "browser.newtabpage.directorySource"; /* * This test ensures that there are no unexpected @@ -64,47 +64,26 @@ const PREF_NEWTAB_DIRECTORYSOURCE = "browser.newtabpage.directory.source"; */ function test() { waitForExplicitFinish(); - let DirectoryLinksProvider = Cu.import("resource://gre/modules/DirectoryLinksProvider.jsm", {}).DirectoryLinksProvider; - let Promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise; - - // resolves promise when directory links are downloaded and written to disk - function watchLinksChangeOnce() { - let deferred = Promise.defer(); - let observer = { - onManyLinksChanged: () => { - DirectoryLinksProvider.removeObserver(observer); - deferred.resolve(); - } - }; - observer.onDownloadFail = observer.onManyLinksChanged; - DirectoryLinksProvider.addObserver(observer); - return deferred.promise; - }; + Services.prefs.setBoolPref(PREF_PRELOAD, false); + Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, "data:application/json,{}"); registerCleanupFunction(() => { Services.prefs.clearUserPref(PREF_PRELOAD); Services.prefs.clearUserPref(PREF_NEWTAB_DIRECTORYSOURCE); - return watchLinksChangeOnce(); }); - // run tests when directory source change completes - watchLinksChangeOnce().then(() => { - // Add a reflow observer and open a new tab. - docShell.addWeakReflowObserver(observer); - BrowserOpenTab(); + // Add a reflow observer and open a new tab. + docShell.addWeakReflowObserver(observer); + BrowserOpenTab(); - // Wait until the tabopen animation has finished. - waitForTransitionEnd(function () { - // Remove reflow observer and clean up. - docShell.removeWeakReflowObserver(observer); - gBrowser.removeCurrentTab(); - finish(); - }); + // Wait until the tabopen animation has finished. + waitForTransitionEnd(function () { + // Remove reflow observer and clean up. + docShell.removeWeakReflowObserver(observer); + gBrowser.removeCurrentTab(); + + finish(); }); - - Services.prefs.setBoolPref(PREF_PRELOAD, false); - // set directory source to empty links - Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, "data:application/json,{}"); } let observer = { diff --git a/browser/base/content/test/newtab/head.js b/browser/base/content/test/newtab/head.js index 88223f9b028d..6699b4ab0d33 100644 --- a/browser/base/content/test/newtab/head.js +++ b/browser/base/content/test/newtab/head.js @@ -2,19 +2,20 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ const PREF_NEWTAB_ENABLED = "browser.newtabpage.enabled"; -const PREF_NEWTAB_DIRECTORYSOURCE = "browser.newtabpage.directory.source"; +const PREF_NEWTAB_DIRECTORYSOURCE = "browser.newtabpage.directorySource"; Services.prefs.setBoolPref(PREF_NEWTAB_ENABLED, true); +// start with no directory links by default +Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, "data:application/json,{}"); let tmp = {}; Cu.import("resource://gre/modules/Promise.jsm", tmp); Cu.import("resource://gre/modules/NewTabUtils.jsm", tmp); -Cu.import("resource://gre/modules/DirectoryLinksProvider.jsm", tmp); Cc["@mozilla.org/moz/jssubscript-loader;1"] .getService(Ci.mozIJSSubScriptLoader) .loadSubScript("chrome://browser/content/sanitize.js", tmp); Cu.import("resource://gre/modules/Timer.jsm", tmp); -let {Promise, NewTabUtils, Sanitizer, clearTimeout, DirectoryLinksProvider} = tmp; +let {Promise, NewTabUtils, Sanitizer, clearTimeout} = tmp; let uri = Services.io.newURI("about:newtab", null, null); let principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri); @@ -59,45 +60,22 @@ registerCleanupFunction(function () { if (oldInnerHeight) gBrowser.contentWindow.innerHeight = oldInnerHeight; + Services.prefs.clearUserPref(PREF_NEWTAB_ENABLED); + Services.prefs.clearUserPref(PREF_NEWTAB_DIRECTORYSOURCE); + // Stop any update timers to prevent unexpected updates in later tests let timer = NewTabUtils.allPages._scheduleUpdateTimeout; if (timer) { clearTimeout(timer); delete NewTabUtils.allPages._scheduleUpdateTimeout; } - - Services.prefs.clearUserPref(PREF_NEWTAB_ENABLED); - Services.prefs.clearUserPref(PREF_NEWTAB_DIRECTORYSOURCE); - - return watchLinksChangeOnce(); }); -/** - * Resolves promise when directory links are downloaded and written to disk - */ -function watchLinksChangeOnce() { - let deferred = Promise.defer(); - let observer = { - onManyLinksChanged: () => { - DirectoryLinksProvider.removeObserver(observer); - deferred.resolve(); - } - }; - observer.onDownloadFail = observer.onManyLinksChanged; - DirectoryLinksProvider.addObserver(observer); - return deferred.promise; -}; - /** * Provide the default test function to start our test runner. */ function test() { - waitForExplicitFinish(); - // start TestRunner.run() after directory links is downloaded and written to disk - watchLinksChangeOnce().then(() => { - TestRunner.run(); - }); - Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE, "data:application/json,{}"); + TestRunner.run(); } /** @@ -108,6 +86,8 @@ let TestRunner = { * Starts the test runner. */ run: function () { + waitForExplicitFinish(); + this._iter = runTests(); this.next(); }, diff --git a/toolkit/modules/DirectoryLinksProvider.jsm b/toolkit/modules/DirectoryLinksProvider.jsm index 06894fabb2e9..8dff9a10a591 100644 --- a/toolkit/modules/DirectoryLinksProvider.jsm +++ b/toolkit/modules/DirectoryLinksProvider.jsm @@ -14,7 +14,6 @@ const XMLHttpRequest = Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); @@ -22,9 +21,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm") XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm"); -XPCOMUtils.defineLazyGetter(this, "gTextDecoder", () => { - return new TextDecoder(); -}); // The filename where directory links are stored locally const DIRECTORY_LINKS_FILE = "directoryLinks.json"; @@ -36,7 +32,7 @@ const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS"; const PREF_SELECTED_LOCALE = "general.useragent.locale"; // The preference that tells where to obtain directory links -const PREF_DIRECTORY_SOURCE = "browser.newtabpage.directory.source"; +const PREF_DIRECTORY_SOURCE = "browser.newtabpage.directorySource"; // The frecency of a directory link const DIRECTORY_FRECENCY = 1000; @@ -56,13 +52,7 @@ let DirectoryLinksProvider = { __linksURL: null, - _observers: new Set(), - - // links download deferred, resolved upon download completion - _downloadDeferred: null, - - // download default interval is 24 hours in milliseconds - _downloadIntervalMS: 86400000, + _observers: [], get _observedPrefs() Object.freeze({ linksURL: PREF_DIRECTORY_SOURCE, @@ -121,9 +111,8 @@ let DirectoryLinksProvider = { if (aData == this._observedPrefs["linksURL"]) { delete this.__linksURL; } + this._callObservers("onManyLinksChanged"); } - // force directory download on changes to any of the observed prefs - this._fetchAndCacheLinksIfNecessary(true); }, _addPrefsObserver: function DirectoryLinksProvider_addObserver() { @@ -140,6 +129,38 @@ let DirectoryLinksProvider = { } }, + /** + * Fetches the current set of directory links. + * @param aCallback a callback that is provided a set of links. + */ + _fetchLinks: function DirectoryLinksProvider_fetchLinks(aCallback) { + try { + NetUtil.asyncFetch(this._linksURL, (aInputStream, aResult, aRequest) => { + let output; + if (Components.isSuccessCode(aResult)) { + try { + let json = NetUtil.readInputStreamToString(aInputStream, + aInputStream.available(), + {charset: "UTF-8"}); + let locale = this.locale; + output = JSON.parse(json)[locale]; + } + catch (e) { + Cu.reportError(e); + } + } + else { + Cu.reportError(new Error("the fetch of " + this._linksURL + "was unsuccessful")); + } + aCallback(output || []); + }); + } + catch (e) { + Cu.reportError(e); + aCallback([]); + } + }, + _fetchAndCacheLinks: function DirectoryLinksProvider_fetchAndCacheLinks(uri) { let deferred = Promise.defer(); let xmlHttp = new XMLHttpRequest(); @@ -151,9 +172,11 @@ let DirectoryLinksProvider = { if (this.status && this.status != 200) { json = "{}"; } - OS.File.writeAtomic(self._directoryFilePath, json, {tmpPath: self._directoryFilePath + ".tmp"}) + let directoryLinksFilePath = OS.Path.join(OS.Constants.Path.localProfileDir, DIRECTORY_LINKS_FILE); + OS.File.writeAtomic(directoryLinksFilePath, json, {tmpPath: directoryLinksFilePath + ".tmp"}) .then(() => { deferred.resolve(); + self._callObservers("onManyLinksChanged"); }, () => { deferred.reject("Error writing uri data in profD."); @@ -174,93 +197,12 @@ let DirectoryLinksProvider = { return deferred.promise; }, - /** - * Downloads directory links if needed - * @return promise resolved immediately if no download needed, or upon completion - */ - _fetchAndCacheLinksIfNecessary: function DirectoryLinksProvider_fetchAndCacheLinksIfNecessary(forceDownload=false) { - if (this._downloadDeferred) { - // fetching links already - just return the promise - return this._downloadDeferred.promise; - } - - if (forceDownload || this._needsDownload) { - this._downloadDeferred = Promise.defer(); - this._fetchAndCacheLinks(this._linksURL).then(() => { - // the new file was successfully downloaded and cached, so update a timestamp - this._lastDownloadMS = Date.now(); - this._downloadDeferred.resolve(); - this._downloadDeferred = null; - this._callObservers("onManyLinksChanged") - }, - error => { - this._downloadDeferred.resolve(); - this._downloadDeferred = null; - this._callObservers("onDownloadFail"); - }); - return this._downloadDeferred.promise; - } - - // download is not needed - return Promise.resolve(); - }, - - /** - * @return true if download is needed, false otherwise - */ - get _needsDownload () { - // fail if last download occured less then 24 hours ago - if ((Date.now() - this._lastDownloadMS) > this._downloadIntervalMS) { - return true; - } - return false; - }, - - /** - * Reads directory links file and parses its content - * @return a promise resolved to valid list of links or [] if read or parse fails - */ - _readDirectoryLinksFile: function DirectoryLinksProvider_readDirectoryLinksFile() { - return OS.File.read(this._directoryFilePath).then(binaryData => { - let output; - try { - let locale = this.locale; - let json = gTextDecoder.decode(binaryData); - output = JSON.parse(json)[locale]; - } - catch (e) { - Cu.reportError(e); - } - return output || []; - }, - error => { - Cu.reportError(error); - return []; - }); - }, - - /** - * Submits counts of shown directory links for each type and - * triggers directory download if sponsored link was shown - * - * @param object keyed on types containing counts - * @return download promise - */ - reportShownCount: function DirectoryLinksProvider_reportShownCount(directoryCount) { - if (directoryCount.sponsored > 0 - || directoryCount.affiliate > 0 - || directoryCount.organic > 0) { - return this._fetchAndCacheLinksIfNecessary(); - } - return Promise.resolve(); - }, - /** * Gets the current set of directory links. * @param aCallback The function that the array of links is passed to. */ getLinks: function DirectoryLinksProvider_getLinks(aCallback) { - this._readDirectoryLinksFile().then(rawLinks => { + this._fetchLinks(rawLinks => { // all directory links have a frecency of DIRECTORY_FRECENCY aCallback(rawLinks.map((link, position) => { link.frecency = DIRECTORY_FRECENCY; @@ -272,19 +214,6 @@ let DirectoryLinksProvider = { init: function DirectoryLinksProvider_init() { this._addPrefsObserver(); - // setup directory file path and last download timestamp - this._directoryFilePath = OS.Path.join(OS.Constants.Path.localProfileDir, DIRECTORY_LINKS_FILE); - this._lastDownloadMS = 0; - return Task.spawn(function() { - // get the last modified time of the links file if it exists - let doesFileExists = yield OS.File.exists(this._directoryFilePath); - if (doesFileExists) { - let fileInfo = yield OS.File.stat(this._directoryFilePath); - this._lastDownloadMS = Date.parse(fileInfo.lastModificationDate); - } - // fetch directory on startup without force - yield this._fetchAndCacheLinksIfNecessary(); - }.bind(this)); }, /** @@ -297,11 +226,7 @@ let DirectoryLinksProvider = { }, addObserver: function DirectoryLinksProvider_addObserver(aObserver) { - this._observers.add(aObserver); - }, - - removeObserver: function DirectoryLinksProvider_removeObserver(aObserver) { - this._observers.delete(aObserver); + this._observers.push(aObserver); }, _callObservers: function DirectoryLinksProvider__callObservers(aMethodName, aArg) { @@ -317,6 +242,8 @@ let DirectoryLinksProvider = { }, _removeObservers: function() { - this._observers.clear(); + while (this._observers.length) { + this._observers.pop(); + } } }; diff --git a/toolkit/modules/tests/xpcshell/test_DirectoryLinksProvider.js b/toolkit/modules/tests/xpcshell/test_DirectoryLinksProvider.js index c5e518aae14a..e77ad87e40b3 100644 --- a/toolkit/modules/tests/xpcshell/test_DirectoryLinksProvider.js +++ b/toolkit/modules/tests/xpcshell/test_DirectoryLinksProvider.js @@ -14,9 +14,7 @@ Cu.import("resource://gre/modules/Promise.jsm"); Cu.import("resource://gre/modules/Http.jsm"); Cu.import("resource://testing-common/httpd.js"); Cu.import("resource://gre/modules/osfile.jsm") -Cu.import("resource://gre/modules/Task.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); @@ -31,10 +29,6 @@ const kTestURL = 'data:application/json,' + JSON.stringify(kURLData); const kLocalePref = DirectoryLinksProvider._observedPrefs.prefSelectedLocale; const kSourceUrlPref = DirectoryLinksProvider._observedPrefs.linksURL; -// app/profile/firefox.js are not avaialble in xpcshell: hence, preset them -Services.prefs.setCharPref(kLocalePref, "en-US"); -Services.prefs.setCharPref(kSourceUrlPref, kTestURL); - // httpd settings var server; const kDefaultServerPort = 9000; @@ -109,44 +103,19 @@ function cleanJsonFile(jsonFile = DIRECTORY_LINKS_FILE) { return OS.File.remove(directoryLinksFilePath); } -function LinksChangeObserver() { - this.deferred = Promise.defer(); - this.onManyLinksChanged = () => this.deferred.resolve(); - this.onDownloadFail = this.onManyLinksChanged; +// All tests that call setupDirectoryLinksProvider() must also call cleanDirectoryLinksProvider(). +function setupDirectoryLinksProvider(options = {}) { + let linksURL = options.linksURL || kTestURL; + DirectoryLinksProvider.init(); + Services.prefs.setCharPref(kLocalePref, options.locale || "en-US"); + Services.prefs.setCharPref(kSourceUrlPref, linksURL); + do_check_eq(DirectoryLinksProvider._linksURL, linksURL); } -function promiseDirectoryDownloadOnPrefChange(pref, newValue) { - let oldValue = Services.prefs.getCharPref(pref); - if (oldValue != newValue) { - // if the preference value is already equal to newValue - // the pref service will not call our observer and we - // deadlock. Hence only setup observer if values differ - let observer = new LinksChangeObserver(); - DirectoryLinksProvider.addObserver(observer); - Services.prefs.setCharPref(pref, newValue); - return observer.deferred.promise; - } - return Promise.resolve(); -} - -function promiseSetupDirectoryLinksProvider(options = {}) { - return Task.spawn(function() { - let linksURL = options.linksURL || kTestURL; - yield DirectoryLinksProvider.init(); - yield promiseDirectoryDownloadOnPrefChange(kLocalePref, options.locale || "en-US"); - yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, linksURL); - do_check_eq(DirectoryLinksProvider._linksURL, linksURL); - DirectoryLinksProvider._lastDownloadMS = options.lastDownloadMS || 0; - }); -} - -function promiseCleanDirectoryLinksProvider() { - return Task.spawn(function() { - yield promiseDirectoryDownloadOnPrefChange(kLocalePref, "en-US"); - yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, kTestURL); - DirectoryLinksProvider._lastDownloadMS = 0; - DirectoryLinksProvider.reset(); - }); +function cleanDirectoryLinksProvider() { + DirectoryLinksProvider.reset(); + Services.prefs.clearUserPref(kLocalePref); + Services.prefs.clearUserPref(kSourceUrlPref); } function run_test() { @@ -161,14 +130,10 @@ function run_test() { // Teardown. do_register_cleanup(function() { server.stop(function() { }); - DirectoryLinksProvider.reset(); - Services.prefs.clearUserPref(kLocalePref); - Services.prefs.clearUserPref(kSourceUrlPref); }); } add_task(function test_fetchAndCacheLinks_local() { - yield DirectoryLinksProvider.init(); yield cleanJsonFile(); // Trigger cache of data or chrome uri files in profD yield DirectoryLinksProvider._fetchAndCacheLinks(kTestURL); @@ -177,7 +142,6 @@ add_task(function test_fetchAndCacheLinks_local() { }); add_task(function test_fetchAndCacheLinks_remote() { - yield DirectoryLinksProvider.init(); yield cleanJsonFile(); // this must trigger directory links json download and save it to cache file yield DirectoryLinksProvider._fetchAndCacheLinks(kExampleURL); @@ -186,7 +150,6 @@ add_task(function test_fetchAndCacheLinks_remote() { }); add_task(function test_fetchAndCacheLinks_malformedURI() { - yield DirectoryLinksProvider.init(); yield cleanJsonFile(); let someJunk = "some junk"; try { @@ -202,7 +165,6 @@ add_task(function test_fetchAndCacheLinks_malformedURI() { }); add_task(function test_fetchAndCacheLinks_unknownHost() { - yield DirectoryLinksProvider.init(); yield cleanJsonFile(); let nonExistentServer = "http://nosuchhost"; try { @@ -218,7 +180,6 @@ add_task(function test_fetchAndCacheLinks_unknownHost() { }); add_task(function test_fetchAndCacheLinks_non200Status() { - yield DirectoryLinksProvider.init(); yield cleanJsonFile(); yield DirectoryLinksProvider._fetchAndCacheLinks(kFailURL); let data = yield readJsonFile(); @@ -226,19 +187,24 @@ add_task(function test_fetchAndCacheLinks_non200Status() { }); // To test onManyLinksChanged observer, trigger a fetch -add_task(function test_DirectoryLinksProvider__linkObservers() { - yield DirectoryLinksProvider.init(); +add_task(function test_linkObservers() { + let deferred = Promise.defer(); + let testObserver = { + onManyLinksChanged: function() { + deferred.resolve(); + } + } - let testObserver = new LinksChangeObserver(); + DirectoryLinksProvider.init(); DirectoryLinksProvider.addObserver(testObserver); - do_check_eq(DirectoryLinksProvider._observers.size, 1); - DirectoryLinksProvider._fetchAndCacheLinksIfNecessary(true); + do_check_eq(DirectoryLinksProvider._observers.length, 1); + DirectoryLinksProvider._fetchAndCacheLinks(kTestURL); - yield testObserver.deferred.promise; + yield deferred.promise; DirectoryLinksProvider._removeObservers(); - do_check_eq(DirectoryLinksProvider._observers.size, 0); + do_check_eq(DirectoryLinksProvider._observers.length, 0); - yield promiseCleanDirectoryLinksProvider(); + cleanDirectoryLinksProvider(); }); add_task(function test_linksURL_locale() { @@ -251,7 +217,7 @@ add_task(function test_linksURL_locale() { }; let dataURI = 'data:application/json,' + JSON.stringify(data); - yield promiseSetupDirectoryLinksProvider({linksURL: dataURI}); + setupDirectoryLinksProvider({linksURL: dataURI}); let links; let expected_data; @@ -261,7 +227,7 @@ add_task(function test_linksURL_locale() { expected_data = [{url: "http://example.com", title: "US", frecency: DIRECTORY_FRECENCY, lastVisitDate: 1}]; isIdentical(links, expected_data); - yield promiseDirectoryDownloadOnPrefChange("general.useragent.locale", "zh-CN"); + Services.prefs.setCharPref('general.useragent.locale', 'zh-CN'); links = yield fetchData(); do_check_eq(links.length, 2) @@ -271,11 +237,11 @@ add_task(function test_linksURL_locale() { ]; isIdentical(links, expected_data); - yield promiseCleanDirectoryLinksProvider(); + cleanDirectoryLinksProvider(); }); -add_task(function test_DirectoryLinksProvider__prefObserver_url() { - yield promiseSetupDirectoryLinksProvider({linksURL: kTestURL}); +add_task(function test_prefObserver_url() { + setupDirectoryLinksProvider({linksURL: kTestURL}); let links = yield fetchData(); do_check_eq(links.length, 1); @@ -286,146 +252,18 @@ add_task(function test_DirectoryLinksProvider__prefObserver_url() { // 1. _linksURL is properly set after the pref change // 2. invalid source url is correctly handled let exampleUrl = 'http://nosuchhost/bad'; - yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, exampleUrl); + Services.prefs.setCharPref(kSourceUrlPref, exampleUrl); do_check_eq(DirectoryLinksProvider._linksURL, exampleUrl); - // since the download fail, the directory file must remain the same let newLinks = yield fetchData(); - isIdentical(newLinks, expectedData); - - // now remove the file, and re-download - yield cleanJsonFile(); - yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, exampleUrl + " "); - // we now should see empty links - newLinks = yield fetchData(); isIdentical(newLinks, []); - yield promiseCleanDirectoryLinksProvider(); + cleanDirectoryLinksProvider(); }); -add_task(function test_DirectoryLinksProvider_getLinks_noLocaleData() { - yield promiseSetupDirectoryLinksProvider({locale: 'zh-CN'}); +add_task(function test_getLinks_noLocaleData() { + setupDirectoryLinksProvider({locale: 'zh-CN'}); let links = yield fetchData(); do_check_eq(links.length, 0); - yield promiseCleanDirectoryLinksProvider(); -}); - -add_task(function test_DirectoryLinksProvider_needsDownload() { - // test timestamping - DirectoryLinksProvider._lastDownloadMS = 0; - do_check_true(DirectoryLinksProvider._needsDownload); - DirectoryLinksProvider._lastDownloadMS = Date.now(); - do_check_false(DirectoryLinksProvider._needsDownload); - DirectoryLinksProvider._lastDownloadMS = Date.now() - (60*60*24 + 1)*1000; - do_check_true(DirectoryLinksProvider._needsDownload); - DirectoryLinksProvider._lastDownloadMS = 0; -}); - -add_task(function test_DirectoryLinksProvider_fetchAndCacheLinksIfNecessary() { - yield DirectoryLinksProvider.init(); - yield cleanJsonFile(); - // explicitly change source url to cause the download during setup - yield promiseSetupDirectoryLinksProvider({linksURL: kTestURL+" "}); - yield DirectoryLinksProvider._fetchAndCacheLinksIfNecessary(); - - // inspect lastDownloadMS timestamp which should be 5 seconds less then now() - let lastDownloadMS = DirectoryLinksProvider._lastDownloadMS; - do_check_true((Date.now() - lastDownloadMS) < 5000); - - // we should have fetched a new file during setup - let data = yield readJsonFile(); - isIdentical(data, kURLData); - - // attempt to download again - the timestamp should not change - yield DirectoryLinksProvider._fetchAndCacheLinksIfNecessary(); - do_check_eq(DirectoryLinksProvider._lastDownloadMS, lastDownloadMS); - - // clean the file and force the download - yield cleanJsonFile(); - yield DirectoryLinksProvider._fetchAndCacheLinksIfNecessary(true); - data = yield readJsonFile(); - isIdentical(data, kURLData); - - // make sure that failed download does not corrupt the file, nor changes lastDownloadMS - lastDownloadMS = DirectoryLinksProvider._lastDownloadMS; - yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, "http://"); - yield DirectoryLinksProvider._fetchAndCacheLinksIfNecessary(true); - data = yield readJsonFile(); - isIdentical(data, kURLData); - do_check_eq(DirectoryLinksProvider._lastDownloadMS, lastDownloadMS); - - // _fetchAndCacheLinksIfNecessary must return same promise if download is in progress - let downloadPromise = DirectoryLinksProvider._fetchAndCacheLinksIfNecessary(true); - let anotherPromise = DirectoryLinksProvider._fetchAndCacheLinksIfNecessary(true); - do_check_true(downloadPromise === anotherPromise); - yield downloadPromise; - - yield promiseCleanDirectoryLinksProvider(); -}); - -add_task(function test_DirectoryLinksProvider_fetchDirectoryOnPrefChange() { - yield DirectoryLinksProvider.init(); - - let testObserver = new LinksChangeObserver(); - DirectoryLinksProvider.addObserver(testObserver); - - yield cleanJsonFile(); - // ensure that provider does not think it needs to download - do_check_false(DirectoryLinksProvider._needsDownload); - - // change the source URL, which should force directory download - yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, kExampleURL); - // then wait for testObserver to fire and test that json is downloaded - yield testObserver.deferred.promise; - let data = yield readJsonFile(); - isIdentical(data, kHttpHandlerData[kExamplePath]); - - yield promiseCleanDirectoryLinksProvider(); -}); - -add_task(function test_DirectoryLinksProvider_fetchDirectoryOnShowCount() { - yield promiseSetupDirectoryLinksProvider(); - - // set lastdownload to 0 to make DirectoryLinksProvider want to download - DirectoryLinksProvider._lastDownloadMS = 0; - do_check_true(DirectoryLinksProvider._needsDownload); - - // Tell DirectoryLinksProvider that newtab has no room for sponsored links - let directoryCount = {sponsored: 0}; - yield DirectoryLinksProvider.reportShownCount(directoryCount); - // the provider must skip download, hence that lastdownload is still 0 - do_check_eq(DirectoryLinksProvider._lastDownloadMS, 0); - - // make room for sponsored links and repeat, download should happen - directoryCount.sponsored = 1; - yield DirectoryLinksProvider.reportShownCount(directoryCount); - do_check_true(DirectoryLinksProvider._lastDownloadMS != 0); - - yield promiseCleanDirectoryLinksProvider(); -}); - -add_task(function test_DirectoryLinksProvider_fetchDirectoryOnInit() { - // ensure preferences are set to defaults - yield promiseSetupDirectoryLinksProvider(); - // now clean to provider, so we can init it again - yield promiseCleanDirectoryLinksProvider(); - - yield cleanJsonFile(); - yield DirectoryLinksProvider.init(); - let data = yield readJsonFile(); - isIdentical(data, kURLData); - - yield promiseCleanDirectoryLinksProvider(); -}); - -add_task(function test_DirectoryLinksProvider_getLinksFromCorruptedFile() { - yield promiseSetupDirectoryLinksProvider(); - - // write bogus json to a file and attempt to fetch from it - let directoryLinksFilePath = OS.Path.join(OS.Constants.Path.profileDir, DIRECTORY_LINKS_FILE); - yield OS.File.writeAtomic(directoryLinksFilePath, '{"en-US":'); - let data = yield fetchData(); - isIdentical(data, []); - - yield promiseCleanDirectoryLinksProvider(); + cleanDirectoryLinksProvider(); });