diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /toolkit/components/search/tests/xpcshell/test_engine_selector_remote_settings.js | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/search/tests/xpcshell/test_engine_selector_remote_settings.js')
-rw-r--r-- | toolkit/components/search/tests/xpcshell/test_engine_selector_remote_settings.js | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/toolkit/components/search/tests/xpcshell/test_engine_selector_remote_settings.js b/toolkit/components/search/tests/xpcshell/test_engine_selector_remote_settings.js new file mode 100644 index 0000000000..336ffb1ee5 --- /dev/null +++ b/toolkit/components/search/tests/xpcshell/test_engine_selector_remote_settings.js @@ -0,0 +1,343 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +ChromeUtils.defineESModuleGetters(this, { + PromiseUtils: "resource://gre/modules/PromiseUtils.sys.mjs", + SearchEngineSelector: "resource://gre/modules/SearchEngineSelector.sys.mjs", +}); + +const TEST_CONFIG = [ + { + engineName: "aol", + orderHint: 500, + webExtension: { + locales: ["default"], + }, + appliesTo: [ + { + included: { everywhere: true }, + }, + { + included: { regions: ["us"] }, + webExtension: { + locales: ["$USER_LOCALE"], + }, + }, + ], + }, + { + engineName: "lycos", + orderHint: 1000, + default: "yes", + appliesTo: [ + { + included: { everywhere: true }, + excluded: { locales: { matches: ["zh-CN"] } }, + }, + ], + }, + { + engineName: "altavista", + orderHint: 2000, + defaultPrivate: "yes", + appliesTo: [ + { + included: { locales: { matches: ["en-US"] } }, + }, + { + included: { regions: ["default"] }, + }, + ], + }, + { + engineName: "excite", + default: "yes-if-no-other", + appliesTo: [ + { + included: { everywhere: true }, + excluded: { regions: ["us"] }, + }, + { + included: { everywhere: true }, + cohort: "acohortid", + }, + ], + }, + { + engineName: "askjeeves", + }, +]; + +let getStub; + +add_task(async function setup() { + const searchConfigSettings = await RemoteSettings(SearchUtils.SETTINGS_KEY); + getStub = sinon.stub(searchConfigSettings, "get"); + + // We expect this error from remove settings as we're invalidating the + // signature. + consoleAllowList.push("Invalid content signature (abc)"); + // We also test returning an empty configuration. + consoleAllowList.push("Received empty search configuration"); +}); + +add_task(async function test_selector_basic_get() { + const listenerSpy = sinon.spy(); + const engineSelector = new SearchEngineSelector(listenerSpy); + getStub.onFirstCall().returns(TEST_CONFIG); + + const { engines } = await engineSelector.fetchEngineConfiguration({ + locale: "en-US", + region: "default", + }); + + Assert.deepEqual( + engines.map(e => e.engineName), + ["lycos", "altavista", "aol", "excite"], + "Should have obtained the correct data from the database." + ); + Assert.ok(listenerSpy.notCalled, "Should not have called the listener"); +}); + +add_task(async function test_selector_get_reentry() { + const listenerSpy = sinon.spy(); + const engineSelector = new SearchEngineSelector(listenerSpy); + let promise = PromiseUtils.defer(); + getStub.resetHistory(); + getStub.onFirstCall().returns(promise.promise); + delete engineSelector._configuration; + + let firstResult; + let secondResult; + + const firstCallPromise = engineSelector + .fetchEngineConfiguration({ + locale: "en-US", + region: "default", + }) + .then(result => (firstResult = result.engines)); + + const secondCallPromise = engineSelector + .fetchEngineConfiguration({ + locale: "en-US", + region: "default", + }) + .then(result => (secondResult = result.engines)); + + Assert.strictEqual( + firstResult, + undefined, + "Should not have returned the first result yet." + ); + + Assert.strictEqual( + secondResult, + undefined, + "Should not have returned the second result yet." + ); + + promise.resolve(TEST_CONFIG); + + await Promise.all([firstCallPromise, secondCallPromise]); + Assert.deepEqual( + firstResult.map(e => e.engineName), + ["lycos", "altavista", "aol", "excite"], + "Should have returned the correct data to the first call" + ); + + Assert.deepEqual( + secondResult.map(e => e.engineName), + ["lycos", "altavista", "aol", "excite"], + "Should have returned the correct data to the second call" + ); + Assert.ok(listenerSpy.notCalled, "Should not have called the listener"); +}); + +add_task(async function test_selector_config_update() { + const listenerSpy = sinon.spy(); + const engineSelector = new SearchEngineSelector(listenerSpy); + getStub.resetHistory(); + getStub.onFirstCall().returns(TEST_CONFIG); + + const { engines } = await engineSelector.fetchEngineConfiguration({ + locale: "en-US", + region: "default", + }); + + Assert.deepEqual( + engines.map(e => e.engineName), + ["lycos", "altavista", "aol", "excite"], + "Should have got the correct configuration" + ); + + Assert.ok(listenerSpy.notCalled, "Should not have called the listener yet"); + + const NEW_DATA = [ + { + default: "yes", + engineName: "askjeeves", + appliesTo: [{ included: { everywhere: true } }], + schema: 1553857697843, + last_modified: 1553859483588, + }, + ]; + + getStub.resetHistory(); + getStub.onFirstCall().returns(NEW_DATA); + await RemoteSettings(SearchUtils.SETTINGS_KEY).emit("sync", { + data: { + current: NEW_DATA, + }, + }); + + Assert.ok(listenerSpy.called, "Should have called the listener"); + + const result = await engineSelector.fetchEngineConfiguration({ + locale: "en-US", + region: "default", + }); + + Assert.deepEqual( + result.engines.map(e => e.engineName), + ["askjeeves"], + "Should have updated the configuration with the new data" + ); +}); + +add_task(async function test_selector_db_modification() { + const engineSelector = new SearchEngineSelector(); + // Fill the database with some values that we can use to test that it is cleared. + const db = RemoteSettings(SearchUtils.SETTINGS_KEY).db; + await db.importChanges( + {}, + Date.now(), + [ + { + id: "85e1f268-9ca5-4b52-a4ac-922df5c07264", + default: "yes", + engineName: "askjeeves", + appliesTo: [{ included: { everywhere: true } }], + }, + ], + { clear: true } + ); + + // Stub the get() so that the first call simulates a signature error, and + // the second simulates success reading from the dump. + getStub.resetHistory(); + getStub + .onFirstCall() + .rejects(new RemoteSettingsClient.InvalidSignatureError("abc")); + getStub.onSecondCall().returns(TEST_CONFIG); + + let result = await engineSelector.fetchEngineConfiguration({ + locale: "en-US", + region: "default", + }); + + Assert.ok( + getStub.calledTwice, + "Should have called the get() function twice." + ); + + const databaseEntries = await db.list(); + Assert.equal(databaseEntries.length, 0, "Should have cleared the database."); + + Assert.deepEqual( + result.engines.map(e => e.engineName), + ["lycos", "altavista", "aol", "excite"], + "Should have returned the correct data." + ); +}); + +add_task(async function test_selector_db_modification_never_succeeds() { + const engineSelector = new SearchEngineSelector(); + // Fill the database with some values that we can use to test that it is cleared. + const db = RemoteSettings(SearchUtils.SETTINGS_KEY).db; + await db.importChanges( + {}, + Date.now(), + [ + { + id: "b70edfdd-1c3f-4b7b-ab55-38cb048636c0", + default: "yes", + engineName: "askjeeves", + appliesTo: [{ included: { everywhere: true } }], + }, + ], + { + clear: true, + } + ); + + // Now simulate the condition where for some reason we never get a + // valid result. + getStub.reset(); + getStub.rejects(new RemoteSettingsClient.InvalidSignatureError("abc")); + + await Assert.rejects( + engineSelector.fetchEngineConfiguration({ + locale: "en-US", + region: "default", + }), + ex => ex.result == Cr.NS_ERROR_UNEXPECTED, + "Should have rejected loading the engine configuration" + ); + + Assert.ok( + getStub.calledTwice, + "Should have called the get() function twice." + ); + + const databaseEntries = await db.list(); + Assert.equal(databaseEntries.length, 0, "Should have cleared the database."); +}); + +add_task(async function test_empty_results() { + // Check that returning an empty result re-tries. + const engineSelector = new SearchEngineSelector(); + // Fill the database with some values that we can use to test that it is cleared. + const db = RemoteSettings(SearchUtils.SETTINGS_KEY).db; + await db.importChanges( + {}, + Date.now(), + [ + { + id: "df5655ca-e045-4f8c-a7ee-047eeb654722", + default: "yes", + engineName: "askjeeves", + appliesTo: [{ included: { everywhere: true } }], + }, + ], + { + clear: true, + } + ); + + // Stub the get() so that the first call simulates an empty database, and + // the second simulates success reading from the dump. + getStub.resetHistory(); + getStub.onFirstCall().returns([]); + getStub.onSecondCall().returns(TEST_CONFIG); + + let result = await engineSelector.fetchEngineConfiguration({ + locale: "en-US", + region: "default", + }); + + Assert.ok( + getStub.calledTwice, + "Should have called the get() function twice." + ); + + const databaseEntries = await db.list(); + Assert.equal(databaseEntries.length, 0, "Should have cleared the database."); + + Assert.deepEqual( + result.engines.map(e => e.engineName), + ["lycos", "altavista", "aol", "excite"], + "Should have returned the correct data." + ); +}); |