Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* Any copyright is dedicated to the Public Domain.
"use strict";
ChromeUtils.defineESModuleGetters(this, {
AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs",
ContentRelevancyManager:
"resource://gre/modules/ContentRelevancyManager.sys.mjs",
exposedForTesting: "resource://gre/modules/ContentRelevancyManager.sys.mjs",
setTimeout: "resource://gre/modules/Timer.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(() => {
gSandbox = sinon.createSandbox();
initUpdateTimerManager();
Services.prefs.setBoolPref(PREF_CONTENT_RELEVANCY_ENABLED, true);
ContentRelevancyManager.init();
registerCleanupFunction(() => {
Services.prefs.clearUserPref(PREF_CONTENT_RELEVANCY_ENABLED);
gSandbox.restore();
});
});
add_task(function test_init() {
Assert.ok(ContentRelevancyManager.initialized, "Init should succeed");
Assert.ok(ContentRelevancyManager.enabled, "Enabled flag should be set");
});
add_task(function test_uninit() {
ContentRelevancyManager.uninit();
Assert.ok(!ContentRelevancyManager.initialized, "Uninit should succeed");
});
add_task(function test_store_manager() {
const RustRelevancyStoreManager = exposedForTesting.RustRelevancyStoreManager;
const fakeStore = {
close: gSandbox.fake(),
};
const fakeRustRelevancyStore = {
init: gSandbox.fake.returns(fakeStore),
};
const storeManager = new RustRelevancyStoreManager(
"test-path",
fakeRustRelevancyStore
);
Assert.equal(fakeRustRelevancyStore.init.callCount, 1);
Assert.deepEqual(fakeRustRelevancyStore.init.firstCall.args, ["test-path"]);
// store should throw before the manager is enabled
Assert.throws(() => storeManager.store, /StoreDisabledError/);
// Once the manager is enabled, store should return the RustRelevancyStore
storeManager.enable();
Assert.equal(storeManager.store, fakeStore);
// Disabling the store should call `close` and make store throw again
Assert.equal(fakeStore.close.callCount, 0);
storeManager.disable();
Assert.equal(fakeStore.close.callCount, 1);
Assert.throws(() => storeManager.store, /StoreDisabledError/);
// Test calling enable() one more time
storeManager.enable();
Assert.equal(storeManager.store, fakeStore);
});
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");
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_shutdown_blocker() {
Services.prefs.setBoolPref(PREF_CONTENT_RELEVANCY_ENABLED, true);
await TestUtils.waitForTick();
gSandbox.spy(ContentRelevancyManager, "interrupt");
// Simulate shutdown.
Services.prefs.setBoolPref("toolkit.asyncshutdown.testing", true);
AsyncShutdown.profileChangeTeardown._trigger();
await TestUtils.waitForCondition(
() => ContentRelevancyManager.interrupt.calledOnce,
"The interrupt shutdown blocker should be called"
);
Services.prefs.clearUserPref("toolkit.asyncshutdown.testing");
Services.prefs.clearUserPref(PREF_CONTENT_RELEVANCY_ENABLED);
gSandbox.restore();
});
/**
* 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:
*/
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", "");
}