summaryrefslogtreecommitdiffstats
path: root/browser/components/pagedata/tests/unit/test_queue.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/pagedata/tests/unit/test_queue.js')
-rw-r--r--browser/components/pagedata/tests/unit/test_queue.js527
1 files changed, 527 insertions, 0 deletions
diff --git a/browser/components/pagedata/tests/unit/test_queue.js b/browser/components/pagedata/tests/unit/test_queue.js
new file mode 100644
index 0000000000..3d180edd13
--- /dev/null
+++ b/browser/components/pagedata/tests/unit/test_queue.js
@@ -0,0 +1,527 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+ChromeUtils.defineESModuleGetters(this, {
+ PageDataService: "resource:///modules/pagedata/PageDataService.sys.mjs",
+ PromiseUtils: "resource://gre/modules/PromiseUtils.sys.mjs",
+});
+
+// Test that urls are retrieved in the expected order.
+add_task(async function test_queueOrder() {
+ Services.prefs.setIntPref("browser.pagedata.maxBackgroundFetches", 0);
+ // Pretend we are idle.
+ PageDataService.observe(null, "idle", null);
+
+ let pageDataResults = [
+ {
+ date: Date.now(),
+ url: "http://www.mozilla.org/1",
+ siteName: "Mozilla",
+ data: {},
+ },
+ {
+ date: Date.now() - 3600,
+ url: "http://www.google.com/2",
+ siteName: "Google",
+ data: {},
+ },
+ {
+ date: Date.now() + 3600,
+ url: "http://www.example.com/3",
+ image: "http://www.example.com/banner.jpg",
+ data: {},
+ },
+ {
+ date: Date.now() / 2,
+ url: "http://www.wikipedia.org/4",
+ data: {},
+ },
+ {
+ date: Date.now() / 3,
+ url: "http://www.microsoft.com/5",
+ data: {
+ [PageDataSchema.DATA_TYPE.PRODUCT]: {
+ name: "Windows 11",
+ },
+ },
+ },
+ ];
+
+ let requests = [];
+ PageDataService.fetchPageData = url => {
+ requests.push(url);
+
+ for (let pageData of pageDataResults) {
+ if (pageData.url == url) {
+ return Promise.resolve(pageData);
+ }
+ }
+
+ return Promise.reject(new Error("Unknown url"));
+ };
+
+ let { promise: completePromise, resolve } = PromiseUtils.defer();
+
+ let results = [];
+ let listener = (_, pageData) => {
+ results.push(pageData);
+ if (results.length == pageDataResults.length) {
+ resolve();
+ }
+ };
+
+ PageDataService.on("page-data", listener);
+
+ for (let pageData of pageDataResults) {
+ PageDataService.queueFetch(pageData.url);
+ }
+
+ await completePromise;
+ PageDataService.off("page-data", listener);
+
+ Assert.deepEqual(
+ requests,
+ pageDataResults.map(pd => pd.url)
+ );
+
+ // Because our fetch implementation is essentially synchronous the results
+ // will be in a known order. This isn't guaranteed by the API though.
+ Assert.deepEqual(results, pageDataResults);
+
+ delete PageDataService.fetchPageData;
+});
+
+// Tests that limiting the number of fetches works.
+add_task(async function test_queueLimit() {
+ Services.prefs.setIntPref("browser.pagedata.maxBackgroundFetches", 3);
+ // Pretend we are idle.
+ PageDataService.observe(null, "idle", null);
+
+ let requests = [];
+ PageDataService.fetchPageData = url => {
+ let { promise, resolve, reject } = PromiseUtils.defer();
+ requests.push({ url, resolve, reject });
+
+ return promise;
+ };
+
+ let results = [];
+ let listener = (_, pageData) => {
+ results.push(pageData?.url);
+ };
+
+ PageDataService.on("page-data", listener);
+
+ PageDataService.queueFetch("https://www.mozilla.org/1");
+ PageDataService.queueFetch("https://www.mozilla.org/2");
+ PageDataService.queueFetch("https://www.mozilla.org/3");
+ PageDataService.queueFetch("https://www.mozilla.org/4");
+ PageDataService.queueFetch("https://www.mozilla.org/5");
+ PageDataService.queueFetch("https://www.mozilla.org/6");
+ PageDataService.queueFetch("https://www.mozilla.org/7");
+ PageDataService.queueFetch("https://www.mozilla.org/8");
+ PageDataService.queueFetch("https://www.mozilla.org/9");
+ PageDataService.queueFetch("https://www.mozilla.org/10");
+ PageDataService.queueFetch("https://www.mozilla.org/11");
+
+ // Let a tick pass.
+ await Promise.resolve();
+
+ Assert.deepEqual(
+ requests.map(r => r.url),
+ [
+ "https://www.mozilla.org/1",
+ "https://www.mozilla.org/2",
+ "https://www.mozilla.org/3",
+ ]
+ );
+
+ // Completing or rejecting a request should start new ones.
+
+ requests[1].resolve({
+ date: 2345,
+ url: "https://www.mozilla.org/2",
+ siteName: "Test 2",
+ data: {},
+ });
+
+ // Let a tick pass.
+ await Promise.resolve();
+
+ Assert.deepEqual(
+ requests.map(r => r.url),
+ [
+ "https://www.mozilla.org/1",
+ "https://www.mozilla.org/2",
+ "https://www.mozilla.org/3",
+ "https://www.mozilla.org/4",
+ ]
+ );
+
+ requests[3].reject(new Error("Fail"));
+
+ // Let a tick pass.
+ await Promise.resolve();
+
+ Assert.deepEqual(
+ requests.map(r => r.url),
+ [
+ "https://www.mozilla.org/1",
+ "https://www.mozilla.org/2",
+ "https://www.mozilla.org/3",
+ "https://www.mozilla.org/4",
+ "https://www.mozilla.org/5",
+ ]
+ );
+
+ // Increasing the limit should start more requests.
+ Services.prefs.setIntPref("browser.pagedata.maxBackgroundFetches", 5);
+
+ // Let a tick pass.
+ await Promise.resolve();
+
+ Assert.deepEqual(
+ requests.map(r => r.url),
+ [
+ "https://www.mozilla.org/1",
+ "https://www.mozilla.org/2",
+ "https://www.mozilla.org/3",
+ "https://www.mozilla.org/4",
+ "https://www.mozilla.org/5",
+ "https://www.mozilla.org/6",
+ "https://www.mozilla.org/7",
+ ]
+ );
+
+ // Dropping the limit shouldn't start anything new.
+ Services.prefs.setIntPref("browser.pagedata.maxBackgroundFetches", 3);
+
+ // Let a tick pass.
+ await Promise.resolve();
+
+ Assert.deepEqual(
+ requests.map(r => r.url),
+ [
+ "https://www.mozilla.org/1",
+ "https://www.mozilla.org/2",
+ "https://www.mozilla.org/3",
+ "https://www.mozilla.org/4",
+ "https://www.mozilla.org/5",
+ "https://www.mozilla.org/6",
+ "https://www.mozilla.org/7",
+ ]
+ );
+
+ // But resolving should also not start new requests.
+ requests[5].resolve({
+ date: 345334,
+ url: "https://www.mozilla.org/6",
+ siteName: "Test 6",
+ data: {},
+ });
+
+ requests[0].resolve({
+ date: 343446434,
+ url: "https://www.mozilla.org/1",
+ siteName: "Test 1",
+ data: {},
+ });
+
+ // Let a tick pass.
+ await Promise.resolve();
+
+ Assert.deepEqual(
+ requests.map(r => r.url),
+ [
+ "https://www.mozilla.org/1",
+ "https://www.mozilla.org/2",
+ "https://www.mozilla.org/3",
+ "https://www.mozilla.org/4",
+ "https://www.mozilla.org/5",
+ "https://www.mozilla.org/6",
+ "https://www.mozilla.org/7",
+ ]
+ );
+
+ // Until a previous request completes.
+ requests[4].resolve(null);
+
+ // Let a tick pass.
+ await Promise.resolve();
+
+ Assert.deepEqual(
+ requests.map(r => r.url),
+ [
+ "https://www.mozilla.org/1",
+ "https://www.mozilla.org/2",
+ "https://www.mozilla.org/3",
+ "https://www.mozilla.org/4",
+ "https://www.mozilla.org/5",
+ "https://www.mozilla.org/6",
+ "https://www.mozilla.org/7",
+ "https://www.mozilla.org/8",
+ ]
+ );
+
+ // Inifinite queue should work.
+ Services.prefs.setIntPref("browser.pagedata.maxBackgroundFetches", 0);
+
+ // Let a tick pass.
+ await Promise.resolve();
+
+ Assert.deepEqual(
+ requests.map(r => r.url),
+ [
+ "https://www.mozilla.org/1",
+ "https://www.mozilla.org/2",
+ "https://www.mozilla.org/3",
+ "https://www.mozilla.org/4",
+ "https://www.mozilla.org/5",
+ "https://www.mozilla.org/6",
+ "https://www.mozilla.org/7",
+ "https://www.mozilla.org/8",
+ "https://www.mozilla.org/9",
+ "https://www.mozilla.org/10",
+ "https://www.mozilla.org/11",
+ ]
+ );
+
+ requests[10].resolve({
+ date: 345334,
+ url: "https://www.mozilla.org/11",
+ data: {},
+ });
+ requests[2].resolve({
+ date: 345334,
+ url: "https://www.mozilla.org/3",
+ data: {},
+ });
+ requests[7].resolve({
+ date: 345334,
+ url: "https://www.mozilla.org/8",
+ data: {},
+ });
+ requests[6].resolve({
+ date: 345334,
+ url: "https://www.mozilla.org/7",
+ data: {},
+ });
+ requests[8].resolve({
+ date: 345334,
+ url: "https://www.mozilla.org/9",
+ data: {},
+ });
+ requests[9].resolve({
+ date: 345334,
+ url: "https://www.mozilla.org/10",
+ data: {},
+ });
+
+ // Let a tick pass.
+ await Promise.resolve();
+
+ Assert.deepEqual(
+ requests.map(r => r.url),
+ [
+ "https://www.mozilla.org/1",
+ "https://www.mozilla.org/2",
+ "https://www.mozilla.org/3",
+ "https://www.mozilla.org/4",
+ "https://www.mozilla.org/5",
+ "https://www.mozilla.org/6",
+ "https://www.mozilla.org/7",
+ "https://www.mozilla.org/8",
+ "https://www.mozilla.org/9",
+ "https://www.mozilla.org/10",
+ "https://www.mozilla.org/11",
+ ]
+ );
+
+ PageDataService.off("page-data", listener);
+
+ delete PageDataService.fetchPageData;
+
+ Assert.deepEqual(results, [
+ "https://www.mozilla.org/2",
+ "https://www.mozilla.org/6",
+ "https://www.mozilla.org/1",
+ "https://www.mozilla.org/11",
+ "https://www.mozilla.org/3",
+ "https://www.mozilla.org/8",
+ "https://www.mozilla.org/7",
+ "https://www.mozilla.org/9",
+ "https://www.mozilla.org/10",
+ ]);
+});
+
+// Tests that the user idle state stops and starts fetches.
+add_task(async function test_idle() {
+ Services.prefs.setIntPref("browser.pagedata.maxBackgroundFetches", 3);
+ // Pretend we are active.
+ PageDataService.observe(null, "active", null);
+
+ let requests = [];
+ PageDataService.fetchPageData = url => {
+ let { promise, resolve, reject } = PromiseUtils.defer();
+ requests.push({ url, resolve, reject });
+
+ return promise;
+ };
+
+ let results = [];
+ let listener = (_, pageData) => {
+ results.push(pageData?.url);
+ };
+
+ PageDataService.on("page-data", listener);
+
+ PageDataService.queueFetch("https://www.mozilla.org/1");
+ PageDataService.queueFetch("https://www.mozilla.org/2");
+ PageDataService.queueFetch("https://www.mozilla.org/3");
+ PageDataService.queueFetch("https://www.mozilla.org/4");
+ PageDataService.queueFetch("https://www.mozilla.org/5");
+ PageDataService.queueFetch("https://www.mozilla.org/6");
+ PageDataService.queueFetch("https://www.mozilla.org/7");
+
+ // Let a tick pass.
+ await Promise.resolve();
+
+ // Nothing will start when active.
+ Assert.deepEqual(
+ requests.map(r => r.url),
+ []
+ );
+
+ // Pretend we are idle.
+ PageDataService.observe(null, "idle", null);
+
+ // Let a tick pass.
+ await Promise.resolve();
+
+ Assert.deepEqual(
+ requests.map(r => r.url),
+ [
+ "https://www.mozilla.org/1",
+ "https://www.mozilla.org/2",
+ "https://www.mozilla.org/3",
+ ]
+ );
+
+ // Completing or rejecting a request should start new ones.
+
+ requests[1].resolve({
+ date: 2345,
+ url: "https://www.mozilla.org/2",
+ data: {},
+ });
+
+ // Let a tick pass.
+ await Promise.resolve();
+
+ Assert.deepEqual(
+ requests.map(r => r.url),
+ [
+ "https://www.mozilla.org/1",
+ "https://www.mozilla.org/2",
+ "https://www.mozilla.org/3",
+ "https://www.mozilla.org/4",
+ ]
+ );
+
+ // But not when active
+ PageDataService.observe(null, "active", null);
+
+ requests[3].resolve({
+ date: 2345,
+ url: "https://www.mozilla.org/4",
+ data: {},
+ });
+ requests[0].resolve({
+ date: 2345,
+ url: "https://www.mozilla.org/1",
+ data: {},
+ });
+ requests[2].resolve({
+ date: 2345,
+ url: "https://www.mozilla.org/3",
+ data: {},
+ });
+
+ // Let a tick pass.
+ await Promise.resolve();
+
+ Assert.deepEqual(
+ requests.map(r => r.url),
+ [
+ "https://www.mozilla.org/1",
+ "https://www.mozilla.org/2",
+ "https://www.mozilla.org/3",
+ "https://www.mozilla.org/4",
+ ]
+ );
+
+ // Going idle should start more workers
+ PageDataService.observe(null, "idle", null);
+
+ // Let a tick pass.
+ await Promise.resolve();
+
+ Assert.deepEqual(
+ requests.map(r => r.url),
+ [
+ "https://www.mozilla.org/1",
+ "https://www.mozilla.org/2",
+ "https://www.mozilla.org/3",
+ "https://www.mozilla.org/4",
+ "https://www.mozilla.org/5",
+ "https://www.mozilla.org/6",
+ "https://www.mozilla.org/7",
+ ]
+ );
+
+ requests[4].resolve({
+ date: 2345,
+ url: "https://www.mozilla.org/5",
+ data: {},
+ });
+ requests[5].resolve({
+ date: 2345,
+ url: "https://www.mozilla.org/6",
+ data: {},
+ });
+ requests[6].resolve({
+ date: 2345,
+ url: "https://www.mozilla.org/7",
+ data: {},
+ });
+
+ // Let a tick pass.
+ await Promise.resolve();
+
+ Assert.deepEqual(
+ requests.map(r => r.url),
+ [
+ "https://www.mozilla.org/1",
+ "https://www.mozilla.org/2",
+ "https://www.mozilla.org/3",
+ "https://www.mozilla.org/4",
+ "https://www.mozilla.org/5",
+ "https://www.mozilla.org/6",
+ "https://www.mozilla.org/7",
+ ]
+ );
+
+ PageDataService.off("page-data", listener);
+
+ delete PageDataService.fetchPageData;
+
+ Assert.deepEqual(results, [
+ "https://www.mozilla.org/2",
+ "https://www.mozilla.org/4",
+ "https://www.mozilla.org/1",
+ "https://www.mozilla.org/3",
+ "https://www.mozilla.org/5",
+ "https://www.mozilla.org/6",
+ "https://www.mozilla.org/7",
+ ]);
+});