diff options
Diffstat (limited to 'browser/modules/test/xpcshell/test_DirectoryLinksProvider.js')
-rw-r--r-- | browser/modules/test/xpcshell/test_DirectoryLinksProvider.js | 1854 |
1 files changed, 0 insertions, 1854 deletions
diff --git a/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js b/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js deleted file mode 100644 index 712f52fa6..000000000 --- a/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js +++ /dev/null @@ -1,1854 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ -"use strict"; - -/** - * This file tests the DirectoryLinksProvider singleton in the DirectoryLinksProvider.jsm module. - */ - -var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu, Constructor: CC } = Components; -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource:///modules/DirectoryLinksProvider.jsm"); -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"); -Cu.import("resource://gre/modules/PlacesUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", - "resource://gre/modules/NetUtil.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils", - "resource://gre/modules/NewTabUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils", - "resource://testing-common/PlacesTestUtils.jsm"); - -do_get_profile(); - -const DIRECTORY_LINKS_FILE = "directoryLinks.json"; -const DIRECTORY_FRECENCY = 1000; -const SUGGESTED_FRECENCY = Infinity; -const kURLData = {"directory": [{"url":"http://example.com", "title":"LocalSource"}]}; -const kTestURL = 'data:application/json,' + JSON.stringify(kURLData); - -// DirectoryLinksProvider preferences -const kLocalePref = DirectoryLinksProvider._observedPrefs.prefSelectedLocale; -const kSourceUrlPref = DirectoryLinksProvider._observedPrefs.linksURL; -const kPingUrlPref = "browser.newtabpage.directory.ping"; -const kNewtabEnhancedPref = "browser.newtabpage.enhanced"; - -// httpd settings -var server; -const kDefaultServerPort = 9000; -const kBaseUrl = "http://localhost:" + kDefaultServerPort; -const kExamplePath = "/exampleTest/"; -const kFailPath = "/fail/"; -const kPingPath = "/ping/"; -const kExampleURL = kBaseUrl + kExamplePath; -const kFailURL = kBaseUrl + kFailPath; -const kPingUrl = kBaseUrl + kPingPath; - -// app/profile/firefox.js are not avaialble in xpcshell: hence, preset them -Services.prefs.setCharPref(kLocalePref, "en-US"); -Services.prefs.setCharPref(kSourceUrlPref, kTestURL); -Services.prefs.setCharPref(kPingUrlPref, kPingUrl); -Services.prefs.setBoolPref(kNewtabEnhancedPref, true); - -const kHttpHandlerData = {}; -kHttpHandlerData[kExamplePath] = {"directory": [{"url":"http://example.com", "title":"RemoteSource"}]}; - -const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1", - "nsIBinaryInputStream", - "setInputStream"); - -var gLastRequestPath; - -var suggestedTile1 = { - url: "http://turbotax.com", - type: "affiliate", - lastVisitDate: 4, - adgroup_name: "Adgroup1", - frecent_sites: [ - "taxact.com", - "hrblock.com", - "1040.com", - "taxslayer.com" - ] -}; -var suggestedTile2 = { - url: "http://irs.gov", - type: "affiliate", - lastVisitDate: 3, - adgroup_name: "Adgroup2", - frecent_sites: [ - "taxact.com", - "hrblock.com", - "freetaxusa.com", - "taxslayer.com" - ] -}; -var suggestedTile3 = { - url: "http://hrblock.com", - type: "affiliate", - lastVisitDate: 2, - adgroup_name: "Adgroup3", - frecent_sites: [ - "taxact.com", - "freetaxusa.com", - "1040.com", - "taxslayer.com" - ] -}; -var suggestedTile4 = { - url: "http://sponsoredtile.com", - type: "sponsored", - lastVisitDate: 1, - adgroup_name: "Adgroup4", - frecent_sites: [ - "sponsoredtarget.com" - ] -} -var suggestedTile5 = { - url: "http://eviltile.com", - type: "affiliate", - lastVisitDate: 5, - explanation: "This is an evil tile <form><button formaction='javascript:alert(1)''>X</button></form> muhahaha", - adgroup_name: "WE ARE EVIL <link rel='import' href='test.svg'/>", - frecent_sites: [ - "eviltarget.com" - ] -} -var someOtherSite = {url: "http://someothersite.com", title: "Not_A_Suggested_Site"}; - -function getHttpHandler(path) { - let code = 200; - let body = JSON.stringify(kHttpHandlerData[path]); - if (path == kFailPath) { - code = 204; - } - return function(aRequest, aResponse) { - gLastRequestPath = aRequest.path; - aResponse.setStatusLine(null, code); - aResponse.setHeader("Content-Type", "application/json"); - aResponse.write(body); - }; -} - -function isIdentical(actual, expected) { - if (expected == null) { - do_check_eq(actual, expected); - } - else if (typeof expected == "object") { - // Make sure all the keys match up - do_check_eq(Object.keys(actual).sort() + "", Object.keys(expected).sort()); - - // Recursively check each value individually - Object.keys(expected).forEach(key => { - isIdentical(actual[key], expected[key]); - }); - } - else { - do_check_eq(actual, expected); - } -} - -function fetchData() { - let deferred = Promise.defer(); - - DirectoryLinksProvider.getLinks(linkData => { - deferred.resolve(linkData); - }); - return deferred.promise; -} - -function readJsonFile(jsonFile = DIRECTORY_LINKS_FILE) { - let decoder = new TextDecoder(); - let directoryLinksFilePath = OS.Path.join(OS.Constants.Path.localProfileDir, jsonFile); - return OS.File.read(directoryLinksFilePath).then(array => { - let json = decoder.decode(array); - return JSON.parse(json); - }, () => { return "" }); -} - -function cleanJsonFile(jsonFile = DIRECTORY_LINKS_FILE) { - let directoryLinksFilePath = OS.Path.join(OS.Constants.Path.localProfileDir, jsonFile); - return OS.File.remove(directoryLinksFilePath); -} - -function LinksChangeObserver() { - this.deferred = Promise.defer(); - this.onManyLinksChanged = () => this.deferred.resolve(); - this.onDownloadFail = this.onManyLinksChanged; -} - -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.then(() => { - DirectoryLinksProvider.removeObserver(observer); - }); - } - 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); - yield DirectoryLinksProvider._clearFrequencyCap(); - yield DirectoryLinksProvider._loadInadjacentSites(); - DirectoryLinksProvider._lastDownloadMS = 0; - DirectoryLinksProvider.reset(); - }); -} - -function run_test() { - // Set up a mock HTTP server to serve a directory page - server = new HttpServer(); - server.registerPrefixHandler(kExamplePath, getHttpHandler(kExamplePath)); - server.registerPrefixHandler(kFailPath, getHttpHandler(kFailPath)); - server.start(kDefaultServerPort); - NewTabUtils.init(); - - run_next_test(); - - // Teardown. - do_register_cleanup(function() { - server.stop(function() { }); - DirectoryLinksProvider.reset(); - Services.prefs.clearUserPref(kLocalePref); - Services.prefs.clearUserPref(kSourceUrlPref); - Services.prefs.clearUserPref(kPingUrlPref); - Services.prefs.clearUserPref(kNewtabEnhancedPref); - }); -} - - -function setTimeout(fun, timeout) { - let timer = Components.classes["@mozilla.org/timer;1"] - .createInstance(Components.interfaces.nsITimer); - var event = { - notify: function () { - fun(); - } - }; - timer.initWithCallback(event, timeout, - Components.interfaces.nsITimer.TYPE_ONE_SHOT); - return timer; -} - -add_task(function test_shouldUpdateSuggestedTile() { - let suggestedLink = { - targetedSite: "somesite.com" - }; - - // DirectoryLinksProvider has no suggested tile and no top sites => no need to update - do_check_eq(DirectoryLinksProvider._getCurrentTopSiteCount(), 0); - isIdentical(NewTabUtils.getProviderLinks(), []); - do_check_eq(DirectoryLinksProvider._shouldUpdateSuggestedTile(), false); - - // DirectoryLinksProvider has a suggested tile and no top sites => need to update - let origGetProviderLinks = NewTabUtils.getProviderLinks; - NewTabUtils.getProviderLinks = (provider) => [suggestedLink]; - - do_check_eq(DirectoryLinksProvider._getCurrentTopSiteCount(), 0); - isIdentical(NewTabUtils.getProviderLinks(), [suggestedLink]); - do_check_eq(DirectoryLinksProvider._shouldUpdateSuggestedTile(), true); - - // DirectoryLinksProvider has a suggested tile and 8 top sites => no need to update - let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount; - DirectoryLinksProvider._getCurrentTopSiteCount = () => 8; - - do_check_eq(DirectoryLinksProvider._getCurrentTopSiteCount(), 8); - isIdentical(NewTabUtils.getProviderLinks(), [suggestedLink]); - do_check_eq(DirectoryLinksProvider._shouldUpdateSuggestedTile(), false); - - // DirectoryLinksProvider has no suggested tile and 8 top sites => need to update - NewTabUtils.getProviderLinks = origGetProviderLinks; - do_check_eq(DirectoryLinksProvider._getCurrentTopSiteCount(), 8); - isIdentical(NewTabUtils.getProviderLinks(), []); - do_check_eq(DirectoryLinksProvider._shouldUpdateSuggestedTile(), true); - - // Cleanup - DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount; -}); - -add_task(function* test_updateSuggestedTile() { - let topSites = ["site0.com", "1040.com", "site2.com", "hrblock.com", "site4.com", "freetaxusa.com", "site6.com"]; - - // Initial setup - let data = {"suggested": [suggestedTile1, suggestedTile2, suggestedTile3], "directory": [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; - } - - let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount; - DirectoryLinksProvider._getCurrentTopSiteCount = () => 8; - - do_check_eq(DirectoryLinksProvider._updateSuggestedTile(), undefined); - - function TestFirstRun() { - this.promise = new Promise(resolve => { - this.onLinkChanged = (directoryLinksProvider, link) => { - links.unshift(link); - let possibleLinks = [suggestedTile1.url, suggestedTile2.url, suggestedTile3.url]; - - isIdentical([...DirectoryLinksProvider._topSitesWithSuggestedLinks], ["hrblock.com", "1040.com", "freetaxusa.com"]); - do_check_true(possibleLinks.indexOf(link.url) > -1); - do_check_eq(link.frecency, SUGGESTED_FRECENCY); - do_check_eq(link.type, "affiliate"); - resolve(); - }; - }); - } - - function TestChangingSuggestedTile() { - this.count = 0; - this.promise = new Promise(resolve => { - this.onLinkChanged = (directoryLinksProvider, link) => { - this.count++; - let possibleLinks = [suggestedTile1.url, suggestedTile2.url, suggestedTile3.url]; - - do_check_true(possibleLinks.indexOf(link.url) > -1); - do_check_eq(link.type, "affiliate"); - do_check_true(this.count <= 2); - - if (this.count == 1) { - // The removed suggested link is the one we added initially. - do_check_eq(link.url, links.shift().url); - do_check_eq(link.frecency, SUGGESTED_FRECENCY); - } else { - links.unshift(link); - do_check_eq(link.frecency, SUGGESTED_FRECENCY); - } - isIdentical([...DirectoryLinksProvider._topSitesWithSuggestedLinks], ["hrblock.com", "freetaxusa.com"]); - resolve(); - } - }); - } - - function TestRemovingSuggestedTile() { - this.count = 0; - this.promise = new Promise(resolve => { - this.onLinkChanged = (directoryLinksProvider, link) => { - this.count++; - - do_check_eq(link.type, "affiliate"); - do_check_eq(this.count, 1); - do_check_eq(link.frecency, SUGGESTED_FRECENCY); - do_check_eq(link.url, links.shift().url); - isIdentical([...DirectoryLinksProvider._topSitesWithSuggestedLinks], []); - resolve(); - } - }); - } - - // Test first call to '_updateSuggestedTile()', called when fetching directory links. - yield testObserver.promise; - DirectoryLinksProvider.removeObserver(testObserver); - - // Removing a top site that doesn't have a suggested link should - // not change the current suggested tile. - let removedTopsite = topSites.shift(); - do_check_eq(removedTopsite, "site0.com"); - do_check_false(NewTabUtils.isTopPlacesSite(removedTopsite)); - let updateSuggestedTile = DirectoryLinksProvider._handleLinkChanged({ - url: "http://" + removedTopsite, - type: "history", - }); - do_check_false(updateSuggestedTile); - - // Removing a top site that has a suggested link should - // remove any current suggested tile and add a new one. - testObserver = new TestChangingSuggestedTile(); - 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 suggested links should remove - // the current suggested link and not replace it. - topSites = []; - testObserver = new TestRemovingSuggestedTile(); - DirectoryLinksProvider.addObserver(testObserver); - DirectoryLinksProvider.onManyLinksChanged(); - yield testObserver.promise; - - // Cleanup - yield promiseCleanDirectoryLinksProvider(); - NewTabUtils.isTopPlacesSite = origIsTopPlacesSite; - NewTabUtils.getProviderLinks = origGetProviderLinks; - DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount; -}); - -add_task(function* test_suggestedLinksMap() { - let data = {"suggested": [suggestedTile1, suggestedTile2, suggestedTile3, suggestedTile4], "directory": [someOtherSite]}; - let dataURI = 'data:application/json,' + JSON.stringify(data); - - yield promiseSetupDirectoryLinksProvider({linksURL: dataURI}); - let links = yield fetchData(); - - // Ensure the suggested tiles were not considered directory tiles. - do_check_eq(links.length, 1); - let expected_data = [{url: "http://someothersite.com", title: "Not_A_Suggested_Site", frecency: DIRECTORY_FRECENCY, lastVisitDate: 1}]; - isIdentical(links, expected_data); - - // Check for correctly saved suggested tiles data. - expected_data = { - "taxact.com": [suggestedTile1, suggestedTile2, suggestedTile3], - "hrblock.com": [suggestedTile1, suggestedTile2], - "1040.com": [suggestedTile1, suggestedTile3], - "taxslayer.com": [suggestedTile1, suggestedTile2, suggestedTile3], - "freetaxusa.com": [suggestedTile2, suggestedTile3], - "sponsoredtarget.com": [suggestedTile4], - }; - - let suggestedSites = [...DirectoryLinksProvider._suggestedLinks.keys()]; - do_check_eq(suggestedSites.indexOf("sponsoredtarget.com"), 5); - do_check_eq(suggestedSites.length, Object.keys(expected_data).length); - - DirectoryLinksProvider._suggestedLinks.forEach((suggestedLinks, site) => { - let suggestedLinksItr = suggestedLinks.values(); - for (let link of expected_data[site]) { - let linkCopy = JSON.parse(JSON.stringify(link)); - linkCopy.targetedName = link.adgroup_name; - linkCopy.explanation = ""; - isIdentical(suggestedLinksItr.next().value, linkCopy); - } - }) - - yield promiseCleanDirectoryLinksProvider(); -}); - -add_task(function* test_topSitesWithSuggestedLinks() { - 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 suggested links. - do_check_eq(DirectoryLinksProvider._topSitesWithSuggestedLinks.size, 0); - - let data = {"suggested": [suggestedTile1, suggestedTile2, suggestedTile3], "directory": [someOtherSite]}; - let dataURI = 'data:application/json,' + JSON.stringify(data); - - yield promiseSetupDirectoryLinksProvider({linksURL: dataURI}); - yield fetchData(); - - // Check we've populated suggested links as expected. - do_check_eq(DirectoryLinksProvider._suggestedLinks.size, 5); - - // When many sites change, we update _topSitesWithSuggestedLinks as expected. - let expectedTopSitesWithSuggestedLinks = ["hrblock.com", "1040.com", "freetaxusa.com"]; - DirectoryLinksProvider._handleManyLinksChanged(); - isIdentical([...DirectoryLinksProvider._topSitesWithSuggestedLinks], expectedTopSitesWithSuggestedLinks); - - // Removing site6.com as a topsite has no impact on _topSitesWithSuggestedLinks. - let popped = topSites.pop(); - DirectoryLinksProvider._handleLinkChanged({url: "http://" + popped}); - isIdentical([...DirectoryLinksProvider._topSitesWithSuggestedLinks], expectedTopSitesWithSuggestedLinks); - - // Removing freetaxusa.com as a topsite will remove it from _topSitesWithSuggestedLinks. - popped = topSites.pop(); - expectedTopSitesWithSuggestedLinks.pop(); - DirectoryLinksProvider._handleLinkChanged({url: "http://" + popped}); - isIdentical([...DirectoryLinksProvider._topSitesWithSuggestedLinks], expectedTopSitesWithSuggestedLinks); - - // Re-adding freetaxusa.com as a topsite will add it to _topSitesWithSuggestedLinks. - topSites.push(popped); - expectedTopSitesWithSuggestedLinks.push(popped); - DirectoryLinksProvider._handleLinkChanged({url: "http://" + popped}); - isIdentical([...DirectoryLinksProvider._topSitesWithSuggestedLinks], expectedTopSitesWithSuggestedLinks); - - // Cleanup. - NewTabUtils.isTopPlacesSite = origIsTopPlacesSite; - NewTabUtils.getProviderLinks = origGetProviderLinks; -}); - -add_task(function* test_suggestedAttributes() { - let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite; - NewTabUtils.isTopPlacesSite = () => true; - - let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount; - DirectoryLinksProvider._getCurrentTopSiteCount = () => 8; - - let frecent_sites = "addons.mozilla.org,air.mozilla.org,blog.mozilla.org,bugzilla.mozilla.org,developer.mozilla.org,etherpad.mozilla.org,forums.mozillazine.org,hacks.mozilla.org,hg.mozilla.org,mozilla.org,planet.mozilla.org,quality.mozilla.org,support.mozilla.org,treeherder.mozilla.org,wiki.mozilla.org".split(","); - let imageURI = "https://image/"; - let title = "the title"; - let type = "affiliate"; - let url = "http://test.url/"; - let adgroup_name = "Mozilla"; - let data = { - suggested: [{ - frecent_sites, - imageURI, - title, - type, - url, - adgroup_name - }] - }; - let dataURI = "data:application/json," + escape(JSON.stringify(data)); - - yield promiseSetupDirectoryLinksProvider({linksURL: dataURI}); - - // Wait for links to get loaded - let gLinks = NewTabUtils.links; - gLinks.addProvider(DirectoryLinksProvider); - gLinks.populateCache(); - yield new Promise(resolve => { - NewTabUtils.allPages.register({ - observe: _ => _, - update() { - NewTabUtils.allPages.unregister(this); - resolve(); - } - }); - }); - - // Make sure we get the expected attributes on the suggested tile - let link = gLinks.getLinks()[0]; - do_check_eq(link.imageURI, imageURI); - do_check_eq(link.targetedName, "Mozilla"); - do_check_eq(link.targetedSite, frecent_sites[0]); - do_check_eq(link.title, title); - do_check_eq(link.type, type); - do_check_eq(link.url, url); - - // Cleanup. - NewTabUtils.isTopPlacesSite = origIsTopPlacesSite; - DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount; - gLinks.removeProvider(DirectoryLinksProvider); - DirectoryLinksProvider.removeObserver(gLinks); -}); - -add_task(function* test_frequencyCappedSites_views() { - Services.prefs.setCharPref(kPingUrlPref, ""); - let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite; - NewTabUtils.isTopPlacesSite = () => true; - - let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount; - DirectoryLinksProvider._getCurrentTopSiteCount = () => 8; - - let testUrl = "http://frequency.capped/link"; - let targets = ["top.site.com"]; - let data = { - suggested: [{ - type: "affiliate", - frecent_sites: targets, - url: testUrl, - frequency_caps: {daily: 5}, - adgroup_name: "Test" - }], - directory: [{ - type: "organic", - url: "http://directory.site/" - }] - }; - let dataURI = "data:application/json," + JSON.stringify(data); - - yield promiseSetupDirectoryLinksProvider({linksURL: dataURI}); - - // Wait for links to get loaded - let gLinks = NewTabUtils.links; - gLinks.addProvider(DirectoryLinksProvider); - gLinks.populateCache(); - yield new Promise(resolve => { - NewTabUtils.allPages.register({ - observe: _ => _, - update() { - NewTabUtils.allPages.unregister(this); - resolve(); - } - }); - }); - - function synthesizeAction(action) { - DirectoryLinksProvider.reportSitesAction([{ - link: { - targetedSite: targets[0], - url: testUrl - } - }], action, 0); - } - - function checkFirstTypeAndLength(type, length) { - let links = gLinks.getLinks(); - do_check_eq(links[0].type, type); - do_check_eq(links.length, length); - } - - // Make sure we get 5 views of the link before it is removed - checkFirstTypeAndLength("affiliate", 2); - synthesizeAction("view"); - checkFirstTypeAndLength("affiliate", 2); - synthesizeAction("view"); - checkFirstTypeAndLength("affiliate", 2); - synthesizeAction("view"); - checkFirstTypeAndLength("affiliate", 2); - synthesizeAction("view"); - checkFirstTypeAndLength("affiliate", 2); - synthesizeAction("view"); - checkFirstTypeAndLength("organic", 1); - - // Cleanup. - NewTabUtils.isTopPlacesSite = origIsTopPlacesSite; - DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount; - gLinks.removeProvider(DirectoryLinksProvider); - DirectoryLinksProvider.removeObserver(gLinks); - Services.prefs.setCharPref(kPingUrlPref, kPingUrl); -}); - -add_task(function* test_frequencyCappedSites_click() { - Services.prefs.setCharPref(kPingUrlPref, ""); - let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite; - NewTabUtils.isTopPlacesSite = () => true; - - let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount; - DirectoryLinksProvider._getCurrentTopSiteCount = () => 8; - - let testUrl = "http://frequency.capped/link"; - let targets = ["top.site.com"]; - let data = { - suggested: [{ - type: "affiliate", - frecent_sites: targets, - url: testUrl, - adgroup_name: "Test" - }], - directory: [{ - type: "organic", - url: "http://directory.site/" - }] - }; - let dataURI = "data:application/json," + JSON.stringify(data); - - yield promiseSetupDirectoryLinksProvider({linksURL: dataURI}); - - // Wait for links to get loaded - let gLinks = NewTabUtils.links; - gLinks.addProvider(DirectoryLinksProvider); - gLinks.populateCache(); - yield new Promise(resolve => { - NewTabUtils.allPages.register({ - observe: _ => _, - update() { - NewTabUtils.allPages.unregister(this); - resolve(); - } - }); - }); - - function synthesizeAction(action) { - DirectoryLinksProvider.reportSitesAction([{ - link: { - targetedSite: targets[0], - url: testUrl - } - }], action, 0); - } - - function checkFirstTypeAndLength(type, length) { - let links = gLinks.getLinks(); - do_check_eq(links[0].type, type); - do_check_eq(links.length, length); - } - - // Make sure the link disappears after the first click - checkFirstTypeAndLength("affiliate", 2); - synthesizeAction("view"); - checkFirstTypeAndLength("affiliate", 2); - synthesizeAction("click"); - checkFirstTypeAndLength("organic", 1); - - // Cleanup. - NewTabUtils.isTopPlacesSite = origIsTopPlacesSite; - DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount; - gLinks.removeProvider(DirectoryLinksProvider); - DirectoryLinksProvider.removeObserver(gLinks); - Services.prefs.setCharPref(kPingUrlPref, kPingUrl); -}); - -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); - let data = yield readJsonFile(); - isIdentical(data, kURLData); -}); - -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 promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, kExampleURL + "%LOCALE%"); - do_check_eq(gLastRequestPath, kExamplePath + "en-US"); - let data = yield readJsonFile(); - isIdentical(data, kHttpHandlerData[kExamplePath]); -}); - -add_task(function* test_fetchAndCacheLinks_malformedURI() { - yield DirectoryLinksProvider.init(); - yield cleanJsonFile(); - let someJunk = "some junk"; - try { - yield DirectoryLinksProvider._fetchAndCacheLinks(someJunk); - do_throw("Malformed URIs should fail") - } catch (e) { - do_check_eq(e, "Error fetching " + someJunk) - } - - // File should be empty. - let data = yield readJsonFile(); - isIdentical(data, ""); -}); - -add_task(function* test_fetchAndCacheLinks_unknownHost() { - yield DirectoryLinksProvider.init(); - yield cleanJsonFile(); - let nonExistentServer = "http://localhost:56789/"; - try { - yield DirectoryLinksProvider._fetchAndCacheLinks(nonExistentServer); - do_throw("BAD URIs should fail"); - } catch (e) { - do_check_true(e.startsWith("Fetching " + nonExistentServer + " results in error code: ")) - } - - // File should be empty. - let data = yield readJsonFile(); - isIdentical(data, ""); -}); - -add_task(function* test_fetchAndCacheLinks_non200Status() { - yield DirectoryLinksProvider.init(); - yield cleanJsonFile(); - yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, kFailURL); - do_check_eq(gLastRequestPath, kFailPath); - let data = yield readJsonFile(); - isIdentical(data, {}); -}); - -// To test onManyLinksChanged observer, trigger a fetch -add_task(function* test_DirectoryLinksProvider__linkObservers() { - yield DirectoryLinksProvider.init(); - - let testObserver = new LinksChangeObserver(); - DirectoryLinksProvider.addObserver(testObserver); - do_check_eq(DirectoryLinksProvider._observers.size, 1); - DirectoryLinksProvider._fetchAndCacheLinksIfNecessary(true); - - yield testObserver.deferred.promise; - DirectoryLinksProvider._removeObservers(); - do_check_eq(DirectoryLinksProvider._observers.size, 0); - - yield promiseCleanDirectoryLinksProvider(); -}); - -add_task(function* test_DirectoryLinksProvider__prefObserver_url() { - yield promiseSetupDirectoryLinksProvider({linksURL: kTestURL}); - - let links = yield fetchData(); - do_check_eq(links.length, 1); - let expectedData = [{url: "http://example.com", title: "LocalSource", frecency: DIRECTORY_FRECENCY, lastVisitDate: 1}]; - isIdentical(links, expectedData); - - // tests these 2 things: - // 1. _linksURL is properly set after the pref change - // 2. invalid source url is correctly handled - let exampleUrl = 'http://localhost:56789/bad'; - yield promiseDirectoryDownloadOnPrefChange(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(); -}); - -add_task(function* test_DirectoryLinksProvider_getLinks_noDirectoryData() { - let data = { - "directory": [], - }; - let dataURI = 'data:application/json,' + JSON.stringify(data); - yield promiseSetupDirectoryLinksProvider({linksURL: dataURI}); - - let links = yield fetchData(); - do_check_eq(links.length, 0); - yield promiseCleanDirectoryLinksProvider(); -}); - -add_task(function* test_DirectoryLinksProvider_getLinks_badData() { - let data = { - "en-US": { - "en-US": [{url: "http://example.com", title: "US"}], - }, - }; - let dataURI = 'data:application/json,' + JSON.stringify(data); - yield promiseSetupDirectoryLinksProvider({linksURL: dataURI}); - - // Make sure we get nothing for incorrectly formatted data - 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; - do_check_eq(gLastRequestPath, kExamplePath); - let data = yield readJsonFile(); - isIdentical(data, kHttpHandlerData[kExamplePath]); - - yield promiseCleanDirectoryLinksProvider(); -}); - -add_task(function* test_DirectoryLinksProvider_fetchDirectoryOnShow() { - yield promiseSetupDirectoryLinksProvider(); - - // set lastdownload to 0 to make DirectoryLinksProvider want to download - DirectoryLinksProvider._lastDownloadMS = 0; - do_check_true(DirectoryLinksProvider._needsDownload); - - // download should happen on view - yield DirectoryLinksProvider.reportSitesAction([], "view"); - 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(); -}); - -add_task(function* test_DirectoryLinksProvider_getAllowedLinks() { - let data = {"directory": [ - {url: "ftp://example.com"}, - {url: "http://example.net"}, - {url: "javascript:5"}, - {url: "https://example.com"}, - {url: "httpJUNKjavascript:42"}, - {url: "data:text/plain,hi"}, - {url: "http/bork:eh"}, - ]}; - let dataURI = 'data:application/json,' + JSON.stringify(data); - yield promiseSetupDirectoryLinksProvider({linksURL: dataURI}); - - let links = yield fetchData(); - do_check_eq(links.length, 2); - - // The only remaining url should be http and https - do_check_eq(links[0].url, data["directory"][1].url); - do_check_eq(links[1].url, data["directory"][3].url); -}); - -add_task(function* test_DirectoryLinksProvider_getAllowedImages() { - let data = {"directory": [ - {url: "http://example.com", imageURI: "ftp://example.com"}, - {url: "http://example.com", imageURI: "http://example.net"}, - {url: "http://example.com", imageURI: "javascript:5"}, - {url: "http://example.com", imageURI: "https://example.com"}, - {url: "http://example.com", imageURI: "httpJUNKjavascript:42"}, - {url: "http://example.com", imageURI: "data:text/plain,hi"}, - {url: "http://example.com", imageURI: "http/bork:eh"}, - ]}; - let dataURI = 'data:application/json,' + JSON.stringify(data); - yield promiseSetupDirectoryLinksProvider({linksURL: dataURI}); - - let links = yield fetchData(); - do_check_eq(links.length, 2); - - // The only remaining images should be https and data - do_check_eq(links[0].imageURI, data["directory"][3].imageURI); - do_check_eq(links[1].imageURI, data["directory"][5].imageURI); -}); - -add_task(function* test_DirectoryLinksProvider_getAllowedImages_base() { - let data = {"directory": [ - {url: "http://example1.com", imageURI: "https://example.com"}, - {url: "http://example2.com", imageURI: "https://tiles.cdn.mozilla.net"}, - {url: "http://example3.com", imageURI: "https://tiles2.cdn.mozilla.net"}, - {url: "http://example4.com", enhancedImageURI: "https://mozilla.net"}, - {url: "http://example5.com", imageURI: "data:text/plain,hi"}, - ]}; - let dataURI = 'data:application/json,' + JSON.stringify(data); - yield promiseSetupDirectoryLinksProvider({linksURL: dataURI}); - - // Pretend we're using the default pref to trigger base matching - DirectoryLinksProvider.__linksURLModified = false; - - let links = yield fetchData(); - do_check_eq(links.length, 4); - - // The only remaining images should be https with mozilla.net or data URI - do_check_eq(links[0].url, data["directory"][1].url); - do_check_eq(links[1].url, data["directory"][2].url); - do_check_eq(links[2].url, data["directory"][3].url); - do_check_eq(links[3].url, data["directory"][4].url); -}); - -add_task(function* test_DirectoryLinksProvider_getAllowedEnhancedImages() { - let data = {"directory": [ - {url: "http://example.com", enhancedImageURI: "ftp://example.com"}, - {url: "http://example.com", enhancedImageURI: "http://example.net"}, - {url: "http://example.com", enhancedImageURI: "javascript:5"}, - {url: "http://example.com", enhancedImageURI: "https://example.com"}, - {url: "http://example.com", enhancedImageURI: "httpJUNKjavascript:42"}, - {url: "http://example.com", enhancedImageURI: "data:text/plain,hi"}, - {url: "http://example.com", enhancedImageURI: "http/bork:eh"}, - ]}; - let dataURI = 'data:application/json,' + JSON.stringify(data); - yield promiseSetupDirectoryLinksProvider({linksURL: dataURI}); - - let links = yield fetchData(); - do_check_eq(links.length, 2); - - // The only remaining enhancedImages should be http and https and data - do_check_eq(links[0].enhancedImageURI, data["directory"][3].enhancedImageURI); - do_check_eq(links[1].enhancedImageURI, data["directory"][5].enhancedImageURI); -}); - -add_task(function* test_DirectoryLinksProvider_getEnhancedLink() { - let data = {"enhanced": [ - {url: "http://example.net", enhancedImageURI: "data:,net1"}, - {url: "http://example.com", enhancedImageURI: "data:,com1"}, - {url: "http://example.com", enhancedImageURI: "data:,com2"}, - ]}; - let dataURI = 'data:application/json,' + JSON.stringify(data); - yield promiseSetupDirectoryLinksProvider({linksURL: dataURI}); - - let links = yield fetchData(); - do_check_eq(links.length, 0); // There are no directory links. - - function checkEnhanced(url, image) { - let enhanced = DirectoryLinksProvider.getEnhancedLink({url: url}); - do_check_eq(enhanced && enhanced.enhancedImageURI, image); - } - - // Get the expected image for the same site - checkEnhanced("http://example.net/", "data:,net1"); - checkEnhanced("http://example.net/path", "data:,net1"); - checkEnhanced("https://www.example.net/", "data:,net1"); - checkEnhanced("https://www3.example.net/", "data:,net1"); - - // Get the image of the last entry - checkEnhanced("http://example.com", "data:,com2"); - - // Get the inline enhanced image - let inline = DirectoryLinksProvider.getEnhancedLink({ - url: "http://example.com/echo", - enhancedImageURI: "data:,echo", - }); - do_check_eq(inline.enhancedImageURI, "data:,echo"); - do_check_eq(inline.url, "http://example.com/echo"); - - // Undefined for not enhanced - checkEnhanced("http://sub.example.net/", undefined); - checkEnhanced("http://example.org", undefined); - checkEnhanced("http://localhost", undefined); - checkEnhanced("http://127.0.0.1", undefined); - - // Make sure old data is not cached - data = {"enhanced": [ - {url: "http://example.com", enhancedImageURI: "data:,fresh"}, - ]}; - dataURI = 'data:application/json,' + JSON.stringify(data); - yield promiseSetupDirectoryLinksProvider({linksURL: dataURI}); - links = yield fetchData(); - do_check_eq(links.length, 0); // There are no directory links. - checkEnhanced("http://example.net", undefined); - checkEnhanced("http://example.com", "data:,fresh"); -}); - -add_task(function* test_DirectoryLinksProvider_enhancedURIs() { - let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite; - NewTabUtils.isTopPlacesSite = () => true; - let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount; - DirectoryLinksProvider._getCurrentTopSiteCount = () => 8; - - let data = { - "suggested": [ - {url: "http://example.net", enhancedImageURI: "data:,net1", title:"SuggestedTitle", adgroup_name: "Test", frecent_sites: ["test.com"]} - ], - "directory": [ - {url: "http://example.net", enhancedImageURI: "data:,net2", title:"DirectoryTitle"} - ] - }; - let dataURI = 'data:application/json,' + JSON.stringify(data); - yield promiseSetupDirectoryLinksProvider({linksURL: dataURI}); - - // Wait for links to get loaded - let gLinks = NewTabUtils.links; - gLinks.addProvider(DirectoryLinksProvider); - gLinks.populateCache(); - yield new Promise(resolve => { - NewTabUtils.allPages.register({ - observe: _ => _, - update() { - NewTabUtils.allPages.unregister(this); - resolve(); - } - }); - }); - - // Check that we've saved the directory tile. - let links = yield fetchData(); - do_check_eq(links.length, 1); - do_check_eq(links[0].title, "DirectoryTitle"); - do_check_eq(links[0].enhancedImageURI, "data:,net2"); - - // Check that the suggested tile with the same URL replaces the directory tile. - links = gLinks.getLinks(); - do_check_eq(links.length, 1); - do_check_eq(links[0].title, "SuggestedTitle"); - do_check_eq(links[0].enhancedImageURI, "data:,net1"); - - // Cleanup. - NewTabUtils.isTopPlacesSite = origIsTopPlacesSite; - DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount; - gLinks.removeProvider(DirectoryLinksProvider); -}); - -add_task(function test_DirectoryLinksProvider_setDefaultEnhanced() { - function checkDefault(expected) { - Services.prefs.clearUserPref(kNewtabEnhancedPref); - do_check_eq(Services.prefs.getBoolPref(kNewtabEnhancedPref), expected); - } - - // Use the default donottrack prefs (enabled = false) - Services.prefs.clearUserPref("privacy.donottrackheader.enabled"); - checkDefault(true); - - // Turn on DNT - no track - Services.prefs.setBoolPref("privacy.donottrackheader.enabled", true); - checkDefault(false); - - // Turn off DNT header - Services.prefs.clearUserPref("privacy.donottrackheader.enabled"); - checkDefault(true); - - // Clean up - Services.prefs.clearUserPref("privacy.donottrackheader.value"); -}); - -add_task(function* test_timeSensetiveSuggestedTiles() { - // make tile json with start and end dates - let testStartTime = Date.now(); - // start date is now + 1 seconds - let startDate = new Date(testStartTime + 1000); - // end date is now + 3 seconds - let endDate = new Date(testStartTime + 3000); - let suggestedTile = Object.assign({ - time_limits: { - start: startDate.toISOString(), - end: endDate.toISOString(), - } - }, suggestedTile1); - - // Initial setup - let topSites = ["site0.com", "1040.com", "site2.com", "hrblock.com", "site4.com", "freetaxusa.com", "site6.com"]; - let data = {"suggested": [suggestedTile], "directory": [someOtherSite]}; - let dataURI = 'data:application/json,' + JSON.stringify(data); - - let testObserver = new TestTimingRun(); - 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; - } - - let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount; - DirectoryLinksProvider._getCurrentTopSiteCount = () => 8; - - do_check_eq(DirectoryLinksProvider._updateSuggestedTile(), undefined); - - // this tester will fire twice: when start limit is reached and when tile link - // is removed upon end of the campaign, in which case deleteFlag will be set - function TestTimingRun() { - this.promise = new Promise(resolve => { - this.onLinkChanged = (directoryLinksProvider, link, ignoreFlag, deleteFlag) => { - // if we are not deleting, add link to links, so we can catch it's removal - if (!deleteFlag) { - links.unshift(link); - } - - isIdentical([...DirectoryLinksProvider._topSitesWithSuggestedLinks], ["hrblock.com", "1040.com"]); - do_check_eq(link.frecency, SUGGESTED_FRECENCY); - do_check_eq(link.type, "affiliate"); - do_check_eq(link.url, suggestedTile.url); - let timeDelta = Date.now() - testStartTime; - if (!deleteFlag) { - // this is start timeout corresponding to campaign start - // a seconds must pass and targetedSite must be set - do_print("TESTING START timeDelta: " + timeDelta); - do_check_true(timeDelta >= 1000 / 2); // check for at least half time - do_check_eq(link.targetedSite, "hrblock.com"); - do_check_true(DirectoryLinksProvider._campaignTimeoutID); - } - else { - // this is the campaign end timeout, so 3 seconds must pass - // and timeout should be cleared - do_print("TESTING END timeDelta: " + timeDelta); - do_check_true(timeDelta >= 3000 / 2); // check for at least half time - do_check_false(link.targetedSite); - do_check_false(DirectoryLinksProvider._campaignTimeoutID); - resolve(); - } - }; - }); - } - - // _updateSuggestedTile() is called when fetching directory links. - yield testObserver.promise; - DirectoryLinksProvider.removeObserver(testObserver); - - // shoudl suggest nothing - do_check_eq(DirectoryLinksProvider._updateSuggestedTile(), undefined); - - // set links back to contain directory tile only - links.shift(); - - // drop the end time - we should pick up the tile - suggestedTile.time_limits.end = null; - data = {"suggested": [suggestedTile], "directory": [someOtherSite]}; - dataURI = 'data:application/json,' + JSON.stringify(data); - - // redownload json and getLinks to force time recomputation - yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, dataURI); - - // ensure that there's a link returned by _updateSuggestedTile and no timeout - let deferred = Promise.defer(); - DirectoryLinksProvider.getLinks(() => { - let link = DirectoryLinksProvider._updateSuggestedTile(); - // we should have a suggested tile and no timeout - do_check_eq(link.type, "affiliate"); - do_check_eq(link.url, suggestedTile.url); - do_check_false(DirectoryLinksProvider._campaignTimeoutID); - deferred.resolve(); - }); - yield deferred.promise; - - // repeat the test for end time only - suggestedTile.time_limits.start = null; - suggestedTile.time_limits.end = (new Date(Date.now() + 3000)).toISOString(); - - data = {"suggested": [suggestedTile], "directory": [someOtherSite]}; - dataURI = 'data:application/json,' + JSON.stringify(data); - - // redownload json and call getLinks() to force time recomputation - yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, dataURI); - - // ensure that there's a link returned by _updateSuggestedTile and timeout set - deferred = Promise.defer(); - DirectoryLinksProvider.getLinks(() => { - let link = DirectoryLinksProvider._updateSuggestedTile(); - // we should have a suggested tile and timeout set - do_check_eq(link.type, "affiliate"); - do_check_eq(link.url, suggestedTile.url); - do_check_true(DirectoryLinksProvider._campaignTimeoutID); - DirectoryLinksProvider._clearCampaignTimeout(); - deferred.resolve(); - }); - yield deferred.promise; - - // Cleanup - yield promiseCleanDirectoryLinksProvider(); - NewTabUtils.isTopPlacesSite = origIsTopPlacesSite; - NewTabUtils.getProviderLinks = origGetProviderLinks; - DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount; -}); - -add_task(function test_setupStartEndTime() { - let currentTime = Date.now(); - let dt = new Date(currentTime); - let link = { - time_limits: { - start: dt.toISOString() - } - }; - - // test ISO translation - DirectoryLinksProvider._setupStartEndTime(link); - do_check_eq(link.startTime, currentTime); - - // test localtime translation - let shiftedDate = new Date(currentTime - dt.getTimezoneOffset()*60*1000); - link.time_limits.start = shiftedDate.toISOString().replace(/Z$/, ""); - - DirectoryLinksProvider._setupStartEndTime(link); - do_check_eq(link.startTime, currentTime); - - // throw some garbage into date string - delete link.startTime; - link.time_limits.start = "no date" - DirectoryLinksProvider._setupStartEndTime(link); - do_check_false(link.startTime); - - link.time_limits.start = "2015-99999-01T00:00:00" - DirectoryLinksProvider._setupStartEndTime(link); - do_check_false(link.startTime); - - link.time_limits.start = "20150501T00:00:00" - DirectoryLinksProvider._setupStartEndTime(link); - do_check_false(link.startTime); -}); - -add_task(function* test_DirectoryLinksProvider_frequencyCapSetup() { - yield promiseSetupDirectoryLinksProvider(); - yield DirectoryLinksProvider.init(); - - yield promiseCleanDirectoryLinksProvider(); - yield DirectoryLinksProvider._readFrequencyCapFile(); - isIdentical(DirectoryLinksProvider._frequencyCaps, {}); - - // setup few links - DirectoryLinksProvider._updateFrequencyCapSettings({ - url: "1", - }); - DirectoryLinksProvider._updateFrequencyCapSettings({ - url: "2", - frequency_caps: {daily: 1, total: 2} - }); - DirectoryLinksProvider._updateFrequencyCapSettings({ - url: "3", - frequency_caps: {total: 2} - }); - DirectoryLinksProvider._updateFrequencyCapSettings({ - url: "4", - frequency_caps: {daily: 1} - }); - let freqCapsObject = DirectoryLinksProvider._frequencyCaps; - let capObject = freqCapsObject["1"]; - let defaultDaily = capObject.dailyCap; - let defaultTotal = capObject.totalCap; - // check if we have defaults set - do_check_true(capObject.dailyCap > 0); - do_check_true(capObject.totalCap > 0); - // check if defaults are properly handled - do_check_eq(freqCapsObject["2"].dailyCap, 1); - do_check_eq(freqCapsObject["2"].totalCap, 2); - do_check_eq(freqCapsObject["3"].dailyCap, defaultDaily); - do_check_eq(freqCapsObject["3"].totalCap, 2); - do_check_eq(freqCapsObject["4"].dailyCap, 1); - do_check_eq(freqCapsObject["4"].totalCap, defaultTotal); - - // write object to file - yield DirectoryLinksProvider._writeFrequencyCapFile(); - // empty out freqCapsObject and read file back - DirectoryLinksProvider._frequencyCaps = {}; - yield DirectoryLinksProvider._readFrequencyCapFile(); - // re-ran tests - they should all pass - do_check_eq(freqCapsObject["2"].dailyCap, 1); - do_check_eq(freqCapsObject["2"].totalCap, 2); - do_check_eq(freqCapsObject["3"].dailyCap, defaultDaily); - do_check_eq(freqCapsObject["3"].totalCap, 2); - do_check_eq(freqCapsObject["4"].dailyCap, 1); - do_check_eq(freqCapsObject["4"].totalCap, defaultTotal); - - // wait a second and prune frequency caps - yield new Promise(resolve => { - setTimeout(resolve, 1100); - }); - - // update one link and create another - DirectoryLinksProvider._updateFrequencyCapSettings({ - url: "3", - frequency_caps: {daily: 1, total: 2} - }); - DirectoryLinksProvider._updateFrequencyCapSettings({ - url: "7", - frequency_caps: {daily: 1, total: 2} - }); - // now prune the ones that have been in the object longer than 1 second - DirectoryLinksProvider._pruneFrequencyCapUrls(1000); - // make sure all keys but "3" and "7" are deleted - Object.keys(DirectoryLinksProvider._frequencyCaps).forEach(key => { - do_check_true(key == "3" || key == "7"); - }); - - yield promiseCleanDirectoryLinksProvider(); -}); - -add_task(function* test_DirectoryLinksProvider_getFrequencyCapLogic() { - yield promiseSetupDirectoryLinksProvider(); - yield DirectoryLinksProvider.init(); - - // setup suggested links - DirectoryLinksProvider._updateFrequencyCapSettings({ - url: "1", - frequency_caps: {daily: 2, total: 4} - }); - - do_check_true(DirectoryLinksProvider._testFrequencyCapLimits("1")); - // exhaust daily views - DirectoryLinksProvider._addFrequencyCapView("1") - do_check_true(DirectoryLinksProvider._testFrequencyCapLimits("1")); - DirectoryLinksProvider._addFrequencyCapView("1") - do_check_false(DirectoryLinksProvider._testFrequencyCapLimits("1")); - - // now step into the furture - let _wasTodayOrig = DirectoryLinksProvider._wasToday; - DirectoryLinksProvider._wasToday = function () { return false; } - // exhaust total views - DirectoryLinksProvider._addFrequencyCapView("1") - do_check_true(DirectoryLinksProvider._testFrequencyCapLimits("1")); - DirectoryLinksProvider._addFrequencyCapView("1") - // reached totalViews 4, should return false - do_check_false(DirectoryLinksProvider._testFrequencyCapLimits("1")); - - // add more views by updating configuration - DirectoryLinksProvider._updateFrequencyCapSettings({ - url: "1", - frequency_caps: {daily: 5, total: 10} - }); - // should be true, since we have more total views - do_check_true(DirectoryLinksProvider._testFrequencyCapLimits("1")); - - // set click flag - DirectoryLinksProvider._setFrequencyCapClick("1"); - // always false after click - do_check_false(DirectoryLinksProvider._testFrequencyCapLimits("1")); - - // use unknown urls and ensure nothing breaks - DirectoryLinksProvider._addFrequencyCapView("nosuch.url"); - DirectoryLinksProvider._setFrequencyCapClick("nosuch.url"); - // testing unknown url should always return false - do_check_false(DirectoryLinksProvider._testFrequencyCapLimits("nosuch.url")); - - // reset _wasToday back to original function - DirectoryLinksProvider._wasToday = _wasTodayOrig; - yield promiseCleanDirectoryLinksProvider(); -}); - -add_task(function* test_DirectoryLinksProvider_getFrequencyCapReportSiteAction() { - yield promiseSetupDirectoryLinksProvider(); - yield DirectoryLinksProvider.init(); - - // setup suggested links - DirectoryLinksProvider._updateFrequencyCapSettings({ - url: "bar.com", - frequency_caps: {daily: 2, total: 4} - }); - - do_check_true(DirectoryLinksProvider._testFrequencyCapLimits("bar.com")); - // report site action - yield DirectoryLinksProvider.reportSitesAction([{ - link: { - targetedSite: "foo.com", - url: "bar.com" - }, - isPinned: function() { return false; }, - }], "view", 0); - - // read file content and ensure that view counters are updated - let data = yield readJsonFile(DirectoryLinksProvider._frequencyCapFilePath); - do_check_eq(data["bar.com"].dailyViews, 1); - do_check_eq(data["bar.com"].totalViews, 1); - - yield promiseCleanDirectoryLinksProvider(); -}); - -add_task(function* test_DirectoryLinksProvider_ClickRemoval() { - yield promiseSetupDirectoryLinksProvider(); - yield DirectoryLinksProvider.init(); - let landingUrl = "http://foo.com"; - - // setup suggested links - DirectoryLinksProvider._updateFrequencyCapSettings({ - url: landingUrl, - frequency_caps: {daily: 2, total: 4} - }); - - // add views - DirectoryLinksProvider._addFrequencyCapView(landingUrl) - DirectoryLinksProvider._addFrequencyCapView(landingUrl) - // make a click - DirectoryLinksProvider._setFrequencyCapClick(landingUrl); - - // views must be 2 and click must be set - do_check_eq(DirectoryLinksProvider._frequencyCaps[landingUrl].totalViews, 2); - do_check_true(DirectoryLinksProvider._frequencyCaps[landingUrl].clicked); - - // now insert a visit into places - yield new Promise(resolve => { - PlacesUtils.asyncHistory.updatePlaces( - { - uri: NetUtil.newURI(landingUrl), - title: "HELLO", - visits: [{ - visitDate: Date.now()*1000, - transitionType: Ci.nsINavHistoryService.TRANSITION_LINK - }] - }, - { - handleError: function () { do_check_true(false); }, - handleResult: function () {}, - handleCompletion: function () { resolve(); } - } - ); - }); - - function UrlDeletionTester() { - this.promise = new Promise(resolve => { - this.onDeleteURI = (directoryLinksProvider, link) => { - resolve(); - }; - this.onClearHistory = (directoryLinksProvider) => { - resolve(); - }; - }); - } - - let testObserver = new UrlDeletionTester(); - DirectoryLinksProvider.addObserver(testObserver); - - PlacesUtils.bhistory.removePage(NetUtil.newURI(landingUrl)); - yield testObserver.promise; - DirectoryLinksProvider.removeObserver(testObserver); - // views must be 2 and click should not exist - do_check_eq(DirectoryLinksProvider._frequencyCaps[landingUrl].totalViews, 2); - do_check_false(DirectoryLinksProvider._frequencyCaps[landingUrl].hasOwnProperty("clicked")); - - // verify that disk written data is kosher - let data = yield readJsonFile(DirectoryLinksProvider._frequencyCapFilePath); - do_check_eq(data[landingUrl].totalViews, 2); - do_check_false(data[landingUrl].hasOwnProperty("clicked")); - - // now test clear history - DirectoryLinksProvider._updateFrequencyCapSettings({ - url: landingUrl, - frequency_caps: {daily: 2, total: 4} - }); - DirectoryLinksProvider._updateFrequencyCapSettings({ - url: "http://bar.com", - frequency_caps: {daily: 2, total: 4} - }); - - DirectoryLinksProvider._setFrequencyCapClick(landingUrl); - DirectoryLinksProvider._setFrequencyCapClick("http://bar.com"); - // both tiles must have clicked - do_check_true(DirectoryLinksProvider._frequencyCaps[landingUrl].clicked); - do_check_true(DirectoryLinksProvider._frequencyCaps["http://bar.com"].clicked); - - testObserver = new UrlDeletionTester(); - DirectoryLinksProvider.addObserver(testObserver); - yield PlacesTestUtils.clearHistory(); - - yield testObserver.promise; - DirectoryLinksProvider.removeObserver(testObserver); - // no clicks should remain in the cap object - do_check_false(DirectoryLinksProvider._frequencyCaps[landingUrl].hasOwnProperty("clicked")); - do_check_false(DirectoryLinksProvider._frequencyCaps["http://bar.com"].hasOwnProperty("clicked")); - - // verify that disk written data is kosher - data = yield readJsonFile(DirectoryLinksProvider._frequencyCapFilePath); - do_check_false(data[landingUrl].hasOwnProperty("clicked")); - do_check_false(data["http://bar.com"].hasOwnProperty("clicked")); - - yield promiseCleanDirectoryLinksProvider(); -}); - -add_task(function test_DirectoryLinksProvider_anonymous() { - do_check_true(DirectoryLinksProvider._newXHR().mozAnon); -}); - -add_task(function* test_sanitizeExplanation() { - // Note: this is a basic test to ensure we applied sanitization to the link explanation. - // Full testing for appropriate sanitization is done in parser/xml/test/unit/test_sanitizer.js. - let data = {"suggested": [suggestedTile5]}; - let dataURI = 'data:application/json,' + encodeURIComponent(JSON.stringify(data)); - - yield promiseSetupDirectoryLinksProvider({linksURL: dataURI}); - yield fetchData(); - - let suggestedSites = [...DirectoryLinksProvider._suggestedLinks.keys()]; - do_check_eq(suggestedSites.indexOf("eviltarget.com"), 0); - do_check_eq(suggestedSites.length, 1); - - let suggestedLink = [...DirectoryLinksProvider._suggestedLinks.get(suggestedSites[0]).values()][0]; - do_check_eq(suggestedLink.explanation, "This is an evil tile X muhahaha"); - do_check_eq(suggestedLink.targetedName, "WE ARE EVIL "); -}); - -add_task(function* test_inadjecentSites() { - let suggestedTile = Object.assign({ - check_inadjacency: true - }, suggestedTile1); - - // Initial setup - let topSites = ["1040.com", "site2.com", "hrblock.com", "site4.com", "freetaxusa.com", "site6.com"]; - let data = {"suggested": [suggestedTile], "directory": [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; - } - - let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount; - DirectoryLinksProvider._getCurrentTopSiteCount = () => { - origCurrentTopSiteCount.apply(DirectoryLinksProvider); - return 8; - }; - - // store oroginal inadjacent sites url - let origInadjacentSitesUrl = DirectoryLinksProvider._inadjacentSitesUrl; - - // loading inadjacent sites list function - function setInadjacentSites(sites) { - let badSiteB64 = []; - sites.forEach(site => { - badSiteB64.push(DirectoryLinksProvider._generateHash(site)); - }); - let theList = {"domains": badSiteB64}; - let uri = 'data:application/json,' + JSON.stringify(theList); - DirectoryLinksProvider._inadjacentSitesUrl = uri; - return DirectoryLinksProvider._loadInadjacentSites(); - } - - // setup gLinks loader - let gLinks = NewTabUtils.links; - gLinks.addProvider(DirectoryLinksProvider); - - function updateNewTabCache() { - gLinks.populateCache(); - return new Promise(resolve => { - NewTabUtils.allPages.register({ - observe: _ => _, - update() { - NewTabUtils.allPages.unregister(this); - resolve(); - } - }); - }); - } - - // no suggested file - do_check_eq(DirectoryLinksProvider._updateSuggestedTile(), undefined); - // _avoidInadjacentSites should be set, since link.check_inadjacency is on - do_check_true(DirectoryLinksProvider._avoidInadjacentSites); - // make sure example.com is included in inadjacent sites list - do_check_true(DirectoryLinksProvider._isInadjacentLink({baseDomain: "example.com"})); - - function TestFirstRun() { - this.promise = new Promise(resolve => { - this.onLinkChanged = (directoryLinksProvider, link) => { - do_check_eq(link.url, suggestedTile.url); - do_check_eq(link.type, "affiliate"); - resolve(); - }; - }); - } - - // Test first call to '_updateSuggestedTile()', called when fetching directory links. - yield testObserver.promise; - DirectoryLinksProvider.removeObserver(testObserver); - - // update newtab cache - yield updateNewTabCache(); - // this should have set - do_check_true(DirectoryLinksProvider._avoidInadjacentSites); - - // there should be siggested link - let link = DirectoryLinksProvider._updateSuggestedTile(); - do_check_eq(link.url, "http://turbotax.com"); - // and it should have avoidInadjacentSites flag - do_check_true(link.check_inadjacency); - - // make someothersite.com inadjacent - yield setInadjacentSites(["someothersite.com"]); - - // there should be no suggested link - link = DirectoryLinksProvider._updateSuggestedTile(); - do_check_false(link); - do_check_true(DirectoryLinksProvider._newTabHasInadjacentSite); - - // _handleLinkChanged must return true on inadjacent site - do_check_true(DirectoryLinksProvider._handleLinkChanged({ - url: "http://someothersite.com", - type: "history", - })); - // _handleLinkChanged must return false on ok site - do_check_false(DirectoryLinksProvider._handleLinkChanged({ - url: "http://foobar.com", - type: "history", - })); - - // change inadjacent list to sites not on newtab page - yield setInadjacentSites(["foo.com", "bar.com"]); - - link = DirectoryLinksProvider._updateSuggestedTile(); - // we should now have a link - do_check_true(link); - do_check_eq(link.url, "http://turbotax.com"); - - // make newtab offending again - yield setInadjacentSites(["someothersite.com", "foo.com"]); - // there should be no suggested link - link = DirectoryLinksProvider._updateSuggestedTile(); - do_check_false(link); - do_check_true(DirectoryLinksProvider._newTabHasInadjacentSite); - - // remove avoidInadjacentSites flag from suggested tile and reload json - delete suggestedTile.check_inadjacency; - data = {"suggested": [suggestedTile], "directory": [someOtherSite]}; - dataURI = 'data:application/json,' + JSON.stringify(data); - yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, dataURI); - yield fetchData(); - - // inadjacent checking should be disabled - do_check_false(DirectoryLinksProvider._avoidInadjacentSites); - link = DirectoryLinksProvider._updateSuggestedTile(); - do_check_true(link); - do_check_eq(link.url, "http://turbotax.com"); - do_check_false(DirectoryLinksProvider._newTabHasInadjacentSite); - - // _handleLinkChanged should return false now, even if newtab has bad site - do_check_false(DirectoryLinksProvider._handleLinkChanged({ - url: "http://someothersite.com", - type: "history", - })); - - // test _isInadjacentLink - do_check_true(DirectoryLinksProvider._isInadjacentLink({baseDomain: "someothersite.com"})); - do_check_false(DirectoryLinksProvider._isInadjacentLink({baseDomain: "bar.com"})); - do_check_true(DirectoryLinksProvider._isInadjacentLink({url: "http://www.someothersite.com"})); - do_check_false(DirectoryLinksProvider._isInadjacentLink({url: "http://www.bar.com"})); - // try to crash _isInadjacentLink - do_check_false(DirectoryLinksProvider._isInadjacentLink({baseDomain: ""})); - do_check_false(DirectoryLinksProvider._isInadjacentLink({url: ""})); - do_check_false(DirectoryLinksProvider._isInadjacentLink({url: "http://localhost:8081/"})); - do_check_false(DirectoryLinksProvider._isInadjacentLink({url: "abracodabra"})); - do_check_false(DirectoryLinksProvider._isInadjacentLink({})); - - // test _checkForInadjacentSites - do_check_true(DirectoryLinksProvider._checkForInadjacentSites()); - - // Cleanup - gLinks.removeProvider(DirectoryLinksProvider); - DirectoryLinksProvider._inadjacentSitesUrl = origInadjacentSitesUrl; - NewTabUtils.isTopPlacesSite = origIsTopPlacesSite; - NewTabUtils.getProviderLinks = origGetProviderLinks; - DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount; - yield promiseCleanDirectoryLinksProvider(); -}); - -add_task(function* test_blockSuggestedTiles() { - // Initial setup - let topSites = ["site0.com", "1040.com", "site2.com", "hrblock.com", "site4.com", "freetaxusa.com", "site6.com"]; - let data = {"suggested": [suggestedTile1, suggestedTile2, suggestedTile3], "directory": [someOtherSite]}; - let dataURI = 'data:application/json,' + JSON.stringify(data); - - 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; - } - - let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount; - DirectoryLinksProvider._getCurrentTopSiteCount = () => 8; - - // load the links - yield new Promise(resolve => { - DirectoryLinksProvider.getLinks(resolve); - }); - - // ensure that tile is suggested - let suggestedLink = DirectoryLinksProvider._updateSuggestedTile(); - do_check_true(suggestedLink.frecent_sites); - - // block suggested tile in a regular way - DirectoryLinksProvider.reportSitesAction([{ - isPinned: function() { return false; }, - link: Object.assign({frecency: 1000}, suggestedLink) - }], "block", 0); - - // suggested tile still must be recommended - suggestedLink = DirectoryLinksProvider._updateSuggestedTile(); - do_check_true(suggestedLink.frecent_sites); - - // timestamp suggested_block in the frequency cap object - DirectoryLinksProvider.handleSuggestedTileBlock(); - // no more recommendations should be seen - do_check_eq(DirectoryLinksProvider._updateSuggestedTile(), undefined); - - // move lastUpdated for suggested tile into the past - DirectoryLinksProvider._frequencyCaps["ignore://suggested_block"].lastUpdated = Date.now() - 25*60*60*1000; - // ensure that suggested tile updates again - suggestedLink = DirectoryLinksProvider._updateSuggestedTile(); - do_check_true(suggestedLink.frecent_sites); - - // Cleanup - yield promiseCleanDirectoryLinksProvider(); - NewTabUtils.isTopPlacesSite = origIsTopPlacesSite; - NewTabUtils.getProviderLinks = origGetProviderLinks; - DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount; -}); |