diff options
Diffstat (limited to '')
-rw-r--r-- | browser/components/pagedata/tests/unit/test_queue.js | 527 |
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", + ]); +}); |