/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ do_get_profile(); ("use strict"); const { sinon } = ChromeUtils.importESModule( "resource://testing-common/Sinon.sys.mjs" ); const { MemoriesHistoryScheduler } = ChromeUtils.importESModule( "moz-src:///browser/components/aiwindow/models/memories/MemoriesHistoryScheduler.sys.mjs" ); const { MemoriesDriftDetector } = ChromeUtils.importESModule( "moz-src:///browser/components/aiwindow/models/memories/MemoriesDriftDetector.sys.mjs" ); const { MemoriesManager } = ChromeUtils.importESModule( "moz-src:///browser/components/aiwindow/models/memories/MemoriesManager.sys.mjs" ); const { PREF_GENERATE_MEMORIES } = ChromeUtils.importESModule( "moz-src:///browser/components/aiwindow/models/memories/MemoriesConstants.sys.mjs" ); // insert N visits so the scheduler crosses its page threshold. async function addTestVisits(count) { let seeded = []; let base = Date.now(); for (let i = 0; i < count; i++) { seeded.push({ url: `https://example${i}.com/`, title: `Example ${i}`, visits: [{ date: new Date(base - i * 1000) }], }); } await PlacesUtils.history.insertMany(seeded); } registerCleanupFunction(async () => { Services.prefs.clearUserPref(PREF_GENERATE_MEMORIES); await PlacesUtils.history.clear(); }); // Drift triggers => memories run add_task(async function test_scheduler_runs_when_drift_triggers() { Services.prefs.setBoolPref(PREF_GENERATE_MEMORIES, true); const generateStub = sinon .stub(MemoriesManager, "generateMemoriesFromBrowsingHistory") .resolves(); const driftStub = sinon .stub(MemoriesDriftDetector, "computeHistoryDriftAndTrigger") .resolves({ baselineMetrics: [{ sessionId: 1, jsScore: 0.1, avgSurprisal: 1.0 }], deltaMetrics: [{ sessionId: 2, jsScore: 0.9, avgSurprisal: 3.0 }], trigger: { jsThreshold: 0.5, surpriseThreshold: 2.0, triggered: true, triggeredSessionIds: [2], }, }); try { let scheduler = MemoriesHistoryScheduler.maybeInit(); // Force pagesVisited above threshold for the test. scheduler.setPagesVisitedForTesting(100); // Run the interval logic once. await scheduler.runNowForTesting(); sinon.assert.calledOnce(generateStub); } finally { generateStub.restore(); driftStub.restore(); } }); // Drift does NOT trigger => memories skipped add_task(async function test_scheduler_skips_when_drift_not_triggered() { Services.prefs.setBoolPref(PREF_GENERATE_MEMORIES, true); const generateStub = sinon .stub(MemoriesManager, "generateMemoriesFromBrowsingHistory") .resolves(); const driftStub = sinon .stub(MemoriesDriftDetector, "computeHistoryDriftAndTrigger") .resolves({ baselineMetrics: [{ sessionId: 1, jsScore: 0.1, avgSurprisal: 1.0 }], deltaMetrics: [{ sessionId: 2, jsScore: 0.2, avgSurprisal: 1.2 }], trigger: { jsThreshold: 0.5, surpriseThreshold: 2.0, triggered: false, triggeredSessionIds: [], }, }); try { let scheduler = MemoriesHistoryScheduler.maybeInit(); await addTestVisits(60); await scheduler.runNowForTesting(); sinon.assert.notCalled(generateStub); } finally { generateStub.restore(); driftStub.restore(); } }); // First run (no previous memories) => memories run even with small history. add_task(async function test_scheduler_runs_on_first_run_with_small_history() { Services.prefs.setBoolPref(PREF_GENERATE_MEMORIES, true); const generateStub = sinon .stub(MemoriesManager, "generateMemoriesFromBrowsingHistory") .resolves(); const driftStub = sinon .stub(MemoriesDriftDetector, "computeHistoryDriftAndTrigger") .resolves({ baselineMetrics: [], deltaMetrics: [], trigger: { jsThreshold: 0, surpriseThreshold: 0, triggered: false, triggeredSessionIds: [], }, }); const lastTsStub = sinon .stub(MemoriesManager, "getLastHistoryMemoryTimestamp") .resolves(0); try { let scheduler = MemoriesHistoryScheduler.maybeInit(); Assert.ok(scheduler, "Scheduler should be initialized when pref is true"); // Set a number of pages that is: // - below the normal threshold (25), but // - high enough for the special first-run threshold (e.g. 15). scheduler.setPagesVisitedForTesting(20); // Run the interval logic once. await scheduler.runNowForTesting(); sinon.assert.calledOnce(generateStub); } finally { generateStub.restore(); driftStub.restore(); lastTsStub.restore(); } });