diff options
Diffstat (limited to 'toolkit/components/contentrelevancy/tests/xpcshell')
4 files changed, 262 insertions, 0 deletions
diff --git a/toolkit/components/contentrelevancy/tests/xpcshell/head.js b/toolkit/components/contentrelevancy/tests/xpcshell/head.js new file mode 100644 index 0000000000..e8c31f589c --- /dev/null +++ b/toolkit/components/contentrelevancy/tests/xpcshell/head.js @@ -0,0 +1,6 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// This requires the profile directory for Places and the content relevancy +// component needs a profile directory for storage. +do_get_profile(); diff --git a/toolkit/components/contentrelevancy/tests/xpcshell/test_ContentRelevancyManager.js b/toolkit/components/contentrelevancy/tests/xpcshell/test_ContentRelevancyManager.js new file mode 100644 index 0000000000..633f9fc49b --- /dev/null +++ b/toolkit/components/contentrelevancy/tests/xpcshell/test_ContentRelevancyManager.js @@ -0,0 +1,149 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +ChromeUtils.defineESModuleGetters(this, { + ContentRelevancyManager: + "resource://gre/modules/ContentRelevancyManager.sys.mjs", + TestUtils: "resource://testing-common/TestUtils.sys.mjs", + setTimeout: "resource://gre/modules/Timer.sys.mjs", + sinon: "resource://testing-common/Sinon.sys.mjs", +}); + +const PREF_CONTENT_RELEVANCY_ENABLED = "toolkit.contentRelevancy.enabled"; +const PREF_TIMER_INTERVAL = "toolkit.contentRelevancy.timerInterval"; + +// These consts are copied from the update timer manager test. See +// `initUpdateTimerManager()`. +const PREF_APP_UPDATE_TIMERMINIMUMDELAY = "app.update.timerMinimumDelay"; +const PREF_APP_UPDATE_TIMERFIRSTINTERVAL = "app.update.timerFirstInterval"; +const MAIN_TIMER_INTERVAL = 1000; // milliseconds +const CATEGORY_UPDATE_TIMER = "update-timer"; + +let gSandbox; + +add_setup(async () => { + gSandbox = sinon.createSandbox(); + initUpdateTimerManager(); + Services.prefs.setBoolPref(PREF_CONTENT_RELEVANCY_ENABLED, true); + await ContentRelevancyManager.init(); + + registerCleanupFunction(() => { + Services.prefs.clearUserPref(PREF_CONTENT_RELEVANCY_ENABLED); + gSandbox.restore(); + }); +}); + +add_task(async function test_init() { + Assert.ok(ContentRelevancyManager.initialized, "Init should succeed"); +}); + +add_task(async function test_uninit() { + ContentRelevancyManager.uninit(); + + Assert.ok(!ContentRelevancyManager.initialized, "Uninit should succeed"); +}); + +add_task(async function test_timer() { + // Set the timer interval to 0 will trigger the timer right away. + Services.prefs.setIntPref(PREF_TIMER_INTERVAL, 0); + gSandbox.spy(ContentRelevancyManager, "notify"); + + await ContentRelevancyManager.init(); + + await TestUtils.waitForCondition( + () => ContentRelevancyManager.notify.called, + "The timer callback should be called" + ); + + Services.prefs.clearUserPref(PREF_TIMER_INTERVAL); + gSandbox.restore(); +}); + +add_task(async function test_feature_toggling() { + Services.prefs.setBoolPref(PREF_CONTENT_RELEVANCY_ENABLED, false); + // Set the timer interval to 0 will trigger the timer right away. + Services.prefs.setIntPref(PREF_TIMER_INTERVAL, 0); + gSandbox.spy(ContentRelevancyManager, "notify"); + + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout + await new Promise(resolve => setTimeout(resolve, 1100)); + Assert.ok( + ContentRelevancyManager.notify.notCalled, + "Timer should not be registered if disabled" + ); + + // Toggle the pref again should re-enable the feature. + Services.prefs.setBoolPref(PREF_CONTENT_RELEVANCY_ENABLED, true); + await TestUtils.waitForTick(); + + await TestUtils.waitForCondition( + () => ContentRelevancyManager.notify.called, + "The timer callback should be called" + ); + + Services.prefs.clearUserPref(PREF_CONTENT_RELEVANCY_ENABLED); + Services.prefs.clearUserPref(PREF_TIMER_INTERVAL); + gSandbox.restore(); +}); + +add_task(async function test_call_disable_twice() { + Services.prefs.setBoolPref(PREF_CONTENT_RELEVANCY_ENABLED, false); + await TestUtils.waitForTick(); + + Services.prefs.setBoolPref(PREF_CONTENT_RELEVANCY_ENABLED, false); + await TestUtils.waitForTick(); + + Assert.ok(true, "`#disable` should be safe to call multiple times"); + + Services.prefs.clearUserPref(PREF_CONTENT_RELEVANCY_ENABLED); +}); + +add_task(async function test_doClassification() { + Services.prefs.setBoolPref(PREF_CONTENT_RELEVANCY_ENABLED, true); + await TestUtils.waitForCondition(() => ContentRelevancyManager._isStoreReady); + await ContentRelevancyManager._test_doClassification([]); + + // Disable it to reset the store. + Services.prefs.setBoolPref(PREF_CONTENT_RELEVANCY_ENABLED, false); + await TestUtils.waitForTick(); + + await Assert.rejects( + ContentRelevancyManager._test_doClassification([]), + /Store is not available/, + "Should throw with an unset store" + ); + + Services.prefs.clearUserPref(PREF_CONTENT_RELEVANCY_ENABLED); +}); + +/** + * Sets up the update timer manager for testing: makes it fire more often, + * removes all existing timers, and initializes it for testing. The body of this + * function is copied from: + * https://searchfox.org/mozilla-central/source/toolkit/components/timermanager/tests/unit/consumerNotifications.js + */ +function initUpdateTimerManager() { + // Set the timer to fire every second + Services.prefs.setIntPref( + PREF_APP_UPDATE_TIMERMINIMUMDELAY, + MAIN_TIMER_INTERVAL / 1000 + ); + Services.prefs.setIntPref( + PREF_APP_UPDATE_TIMERFIRSTINTERVAL, + MAIN_TIMER_INTERVAL + ); + + // Remove existing update timers to prevent them from being notified + for (let { data: entry } of Services.catMan.enumerateCategory( + CATEGORY_UPDATE_TIMER + )) { + Services.catMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, entry, false); + } + + Cc["@mozilla.org/updates/timer-manager;1"] + .getService(Ci.nsIUpdateTimerManager) + .QueryInterface(Ci.nsIObserver) + .observe(null, "utm-test-init", ""); +} diff --git a/toolkit/components/contentrelevancy/tests/xpcshell/test_InputUtils.js b/toolkit/components/contentrelevancy/tests/xpcshell/test_InputUtils.js new file mode 100644 index 0000000000..2bb2b8e62e --- /dev/null +++ b/toolkit/components/contentrelevancy/tests/xpcshell/test_InputUtils.js @@ -0,0 +1,98 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +ChromeUtils.defineESModuleGetters(this, { + getFrecentRecentCombinedUrls: + "resource://gre/modules/contentrelevancy/private/InputUtils.sys.mjs", + getMostRecentUrls: + "resource://gre/modules/contentrelevancy/private/InputUtils.sys.mjs", + getTopFrecentUrls: + "resource://gre/modules/contentrelevancy/private/InputUtils.sys.mjs", + PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs", + PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs", +}); + +const FRECENCY_SCORE_FOR_ONE_VISIT = 100; +const TEST_VISITS = [ + "http://test-1.com/", + "http://test-2.com/", + "http://test-3.com/", + "http://test-4.com/", +]; + +add_task(async function test_GetTopFrecentUrls() { + await PlacesUtils.history.clear(); + let urls = new Set(await getTopFrecentUrls(3, FRECENCY_SCORE_FOR_ONE_VISIT)); + + Assert.strictEqual(urls.size, 0, "Should have no top frecent links."); + + await PlacesTestUtils.addVisits(TEST_VISITS); + urls = new Set(await getTopFrecentUrls(3, FRECENCY_SCORE_FOR_ONE_VISIT)); + + Assert.strictEqual(urls.size, 3, "Should fetch the expected links"); + urls.forEach(url => { + Assert.ok(TEST_VISITS.includes(url), "Should be a link of the test visits"); + }); +}); + +add_task(async function test_GetMostRecentUrls() { + await PlacesUtils.history.clear(); + let urls = new Set(await getMostRecentUrls(3)); + + Assert.strictEqual(urls.size, 0, "Should have no recent links."); + + // Add visits and page meta data. + await PlacesTestUtils.addVisits(TEST_VISITS); + for (let url of TEST_VISITS) { + await PlacesUtils.history.update({ + description: "desc", + previewImageURL: "https://image/", + url, + }); + } + + urls = new Set(await getMostRecentUrls(3)); + + Assert.strictEqual(urls.size, 3, "Should fetch the expected links"); + urls.forEach(url => { + Assert.ok(TEST_VISITS.includes(url), "Should be a link of the test visits"); + }); +}); + +add_task(async function test_GetFrecentRecentCombinedUrls() { + await PlacesUtils.history.clear(); + let urls = new Set(await getFrecentRecentCombinedUrls(3)); + + Assert.strictEqual(urls.size, 0, "Should have no links."); + + // Add visits and page meta data. + await PlacesTestUtils.addVisits(TEST_VISITS); + for (let url of TEST_VISITS) { + await PlacesUtils.history.update({ + description: "desc", + previewImageURL: "https://image/", + url, + }); + } + + urls = new Set(await getFrecentRecentCombinedUrls(3)); + + Assert.strictEqual(urls.size, 3, "Should fetch the expected links"); + urls.forEach(url => { + Assert.ok(TEST_VISITS.includes(url), "Should be a link of the test visits"); + }); + + // Try getting twice as many URLs as the total in Places. + urls = new Set(await getFrecentRecentCombinedUrls(TEST_VISITS.length * 2)); + + Assert.strictEqual( + urls.size, + TEST_VISITS.length, + "Should not include duplicates" + ); + urls.forEach(url => { + Assert.ok(TEST_VISITS.includes(url), "Should be a link of the test visits"); + }); +}); diff --git a/toolkit/components/contentrelevancy/tests/xpcshell/xpcshell.toml b/toolkit/components/contentrelevancy/tests/xpcshell/xpcshell.toml new file mode 100644 index 0000000000..70f6d45c2d --- /dev/null +++ b/toolkit/components/contentrelevancy/tests/xpcshell/xpcshell.toml @@ -0,0 +1,9 @@ +[DEFAULT] +head = "head.js" +firefox-appdir = "browser" + +["test_ContentRelevancyManager.js"] +skip-if = ["os == 'android'"] # bug 1886601 + +["test_InputUtils.js"] +skip-if = ["os == 'android'"] # bug 1886601 |