Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/* Any copyright is dedicated to the Public Domain.
// Test PlacesFrecencyRecalculator scheduling.
// Enable the collection (during test) for all products so even products
// that don't collect the data will be able to run the test without failure.
Services.prefs.setBoolPref(
"toolkit.telemetry.testing.overrideProductsCheck",
true
);
async function getOriginFrecency(origin) {
let db = await PlacesUtils.promiseDBConnection();
return (
await db.execute(
`SELECT frecency
FROM moz_origins
WHERE host = :origin`,
{ origin }
)
)[0].getResultByIndex(0);
}
async function resetOriginFrecency(origin) {
await PlacesUtils.withConnectionWrapper(
"test_frecency_recalculator reset origin",
async db => {
await db.executeCached(
`UPDATE moz_origins
SET frecency = -1
WHERE host = :origin`,
{ origin }
);
}
);
}
async function addVisitsAndSetRecalc(urls) {
await PlacesTestUtils.addVisits(urls);
await PlacesUtils.withConnectionWrapper(
"test_frecency_recalculator set recalc",
async db => {
await db.executeCached(
`UPDATE moz_places
SET frecency = -1
WHERE url in (
${PlacesUtils.sqlBindPlaceholders(urls)}
)`,
urls
);
await db.executeCached(
`UPDATE moz_places
SET recalc_frecency = (CASE WHEN url in (
${PlacesUtils.sqlBindPlaceholders(urls)}
) THEN 1 ELSE 0 END)`,
urls
);
}
);
}
add_task(async function test() {
info("On startup a recalculation is always pending.");
Assert.ok(
PlacesFrecencyRecalculator.isRecalculationPending,
"Recalculation should be pending"
);
// If everything gets recalculated, then it should not be pending anymore.
await PlacesFrecencyRecalculator.recalculateAnyOutdatedFrecencies();
Assert.ok(
!PlacesFrecencyRecalculator.isRecalculationPending,
"Recalculation should not be pending"
);
// If after a recalculation there's outdated entries left, a new recalculation
// should be pending.
info("Insert outdated frecencies");
const url1 = new URL("https://test1.moz.org/");
const url2 = new URL("https://test2.moz.org/");
await addVisitsAndSetRecalc([url1.href, url2.href]);
await resetOriginFrecency(url1.host);
await resetOriginFrecency(url2.host);
Assert.ok(
PlacesUtils.history.shouldStartFrecencyRecalculation,
"Should have set shouldStartFrecencyRecalculation"
);
await PlacesFrecencyRecalculator.recalculateSomeFrecencies({ chunkSize: 1 });
Assert.ok(
PlacesFrecencyRecalculator.isRecalculationPending,
"Recalculation should be pending"
);
// Recalculating uri1 will set its origin to recalc, that means there's 2
// origins to recalc now. Passing chunkSize: 2 here would then retrigger the
// recalc, thinking we saturated the chunk, thus we use 3.
await PlacesFrecencyRecalculator.recalculateSomeFrecencies({ chunkSize: 3 });
Assert.ok(
!PlacesFrecencyRecalculator.isRecalculationPending,
"Recalculation should not be pending"
);
Assert.ok(
!PlacesUtils.history.shouldStartFrecencyRecalculation,
"Should have unset shouldStartFrecencyRecalculation"
);
Assert.greater(await getOriginFrecency(url1.host), 0);
Assert.greater(await getOriginFrecency(url2.host), 0);
info("Changing recalc_frecency of an entry adds a pending recalculation.");
PlacesUtils.history.shouldStartFrecencyRecalculation = false;
let promiseNotify = TestUtils.topicObserved("frecency-recalculation-needed");
await PlacesUtils.withConnectionWrapper(
"test_frecency_recalculator",
async db => {
await db.executeCached(
`UPDATE moz_places SET recalc_frecency = 1 WHERE url = :url`,
{ url: url1.href }
);
}
);
Assert.ok(
PlacesUtils.history.shouldStartFrecencyRecalculation,
"Should have set shouldStartFrecencyRecalculation"
);
await promiseNotify;
Assert.ok(
PlacesFrecencyRecalculator.isRecalculationPending,
"Recalculation should be pending"
);
await PlacesFrecencyRecalculator.recalculateAnyOutdatedFrecencies();
Assert.ok(
!PlacesUtils.history.shouldStartFrecencyRecalculation,
"Should have unset shouldStartFrecencyRecalculation"
);
});
add_task(async function test_chunk_time_telemetry() {
await PlacesUtils.bookmarks.insert({
parentGuid: PlacesUtils.bookmarks.toolbarGuid,
});
Assert.ok(
PlacesUtils.history.shouldStartFrecencyRecalculation,
"Should have set shouldStartFrecencyRecalculation"
);
let histogram = TelemetryTestUtils.getAndClearHistogram(
"PLACES_FRECENCY_RECALC_CHUNK_TIME_MS"
);
let subject = {};
PlacesFrecencyRecalculator.observe(subject, "test-execute-taskFn", "");
await subject.promise;
let snapshot = histogram.snapshot();
Assert.equal(
Object.values(snapshot.values).reduce((a, b) => a + b, 0),
1
);
Assert.greater(snapshot.sum, 0);
Assert.ok(
!PlacesUtils.history.shouldStartFrecencyRecalculation,
"Should have unset shouldStartFrecencyRecalculation"
);
// It should now not report any new time, since there's nothing to recalculate.
histogram.clear();
PlacesFrecencyRecalculator.observe(subject, "test-execute-taskFn", "");
await subject.promise;
snapshot = histogram.snapshot();
Assert.equal(
Object.values(snapshot.values).reduce((a, b) => a + b, 0),
0
);
Assert.ok(
!PlacesUtils.history.shouldStartFrecencyRecalculation,
"Should still not have set shouldStartFrecencyRecalculation"
);
});
add_task(async function test_acceleration() {
await PlacesTestUtils.addVisits(
new Array(300).fill("https://www.mozilla.org/")
);
Assert.ok(
PlacesFrecencyRecalculator.maybeUpdateRecalculationSpeed(),
"Recalculation accelerated"
);
await PlacesFrecencyRecalculator.recalculateAnyOutdatedFrecencies();
Assert.ok(
!PlacesFrecencyRecalculator.maybeUpdateRecalculationSpeed(),
"Recalculation back to normal rate"
);
});