summaryrefslogtreecommitdiffstats
path: root/browser/components/urlbar/tests/quicksuggest/unit/test_suggestionsMap.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/urlbar/tests/quicksuggest/unit/test_suggestionsMap.js')
-rw-r--r--browser/components/urlbar/tests/quicksuggest/unit/test_suggestionsMap.js217
1 files changed, 217 insertions, 0 deletions
diff --git a/browser/components/urlbar/tests/quicksuggest/unit/test_suggestionsMap.js b/browser/components/urlbar/tests/quicksuggest/unit/test_suggestionsMap.js
new file mode 100644
index 0000000000..598f0d89a5
--- /dev/null
+++ b/browser/components/urlbar/tests/quicksuggest/unit/test_suggestionsMap.js
@@ -0,0 +1,217 @@
+/* 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/. */
+
+// Tests the chunking feature of `RemoteSettingsClient.#addResults()`.
+
+"use strict";
+
+ChromeUtils.defineESModuleGetters(this, {
+ SuggestionsMap:
+ "resource:///modules/urlbar/private/QuickSuggestRemoteSettings.sys.mjs",
+});
+
+XPCOMUtils.defineLazyModuleGetters(this, {
+ ObjectUtils: "resource://gre/modules/ObjectUtils.jsm",
+});
+
+// This overrides `SuggestionsMap.chunkSize`. Testing the actual value can make
+// the test run too long. This is OK because the correctness of the chunking
+// behavior doesn't depend on the chunk size.
+const TEST_CHUNK_SIZE = 100;
+
+add_task(async function init() {
+ // Sanity check the actual `chunkSize` value.
+ Assert.equal(
+ typeof SuggestionsMap.chunkSize,
+ "number",
+ "Sanity check: chunkSize is a number"
+ );
+ Assert.greater(SuggestionsMap.chunkSize, 0, "Sanity check: chunkSize > 0");
+
+ // Set our test value.
+ SuggestionsMap.chunkSize = TEST_CHUNK_SIZE;
+});
+
+// Tests many suggestions with one keyword each.
+add_task(async function chunking_singleKeyword() {
+ let suggestionCounts = [
+ 1 * SuggestionsMap.chunkSize - 1,
+ 1 * SuggestionsMap.chunkSize,
+ 1 * SuggestionsMap.chunkSize + 1,
+ 2 * SuggestionsMap.chunkSize - 1,
+ 2 * SuggestionsMap.chunkSize,
+ 2 * SuggestionsMap.chunkSize + 1,
+ 3 * SuggestionsMap.chunkSize - 1,
+ 3 * SuggestionsMap.chunkSize,
+ 3 * SuggestionsMap.chunkSize + 1,
+ ];
+ for (let count of suggestionCounts) {
+ await doChunkingTest(count, 1);
+ }
+});
+
+// Tests a small number of suggestions with many keywords each.
+add_task(async function chunking_manyKeywords() {
+ let keywordCounts = [
+ 1 * SuggestionsMap.chunkSize - 1,
+ 1 * SuggestionsMap.chunkSize,
+ 1 * SuggestionsMap.chunkSize + 1,
+ 2 * SuggestionsMap.chunkSize - 1,
+ 2 * SuggestionsMap.chunkSize,
+ 2 * SuggestionsMap.chunkSize + 1,
+ 3 * SuggestionsMap.chunkSize - 1,
+ 3 * SuggestionsMap.chunkSize,
+ 3 * SuggestionsMap.chunkSize + 1,
+ ];
+ for (let suggestionCount = 1; suggestionCount <= 3; suggestionCount++) {
+ for (let keywordCount of keywordCounts) {
+ await doChunkingTest(suggestionCount, keywordCount);
+ }
+ }
+});
+
+async function doChunkingTest(suggestionCount, keywordCountPerSuggestion) {
+ info(
+ "Running chunking test: " +
+ JSON.stringify({ suggestionCount, keywordCountPerSuggestion })
+ );
+
+ // Create `suggestionCount` suggestions, each with `keywordCountPerSuggestion`
+ // keywords.
+ let suggestions = [];
+ for (let i = 0; i < suggestionCount; i++) {
+ let keywords = [];
+ for (let k = 0; k < keywordCountPerSuggestion; k++) {
+ keywords.push(`keyword-${i}-${k}`);
+ }
+ suggestions.push({
+ keywords,
+ id: i,
+ url: "http://example.com/" + i,
+ title: "Suggestion " + i,
+ click_url: "http://example.com/click",
+ impression_url: "http://example.com/impression",
+ advertiser: "TestAdvertiser",
+ iab_category: "22 - Shopping",
+ });
+ }
+
+ // Add the suggestions.
+ let map = new SuggestionsMap();
+ await map.add(suggestions);
+
+ // Make sure all keyword-suggestion pairs have been added.
+ for (let i = 0; i < suggestionCount; i++) {
+ for (let k = 0; k < keywordCountPerSuggestion; k++) {
+ let keyword = `keyword-${i}-${k}`;
+
+ // Check the map. Logging all assertions takes a ton of time and makes the
+ // test run much longer than it otherwise would, especially if `chunkSize`
+ // is large, so only log failing assertions.
+ let actualSuggestions = map.get(keyword);
+ if (!ObjectUtils.deepEqual(actualSuggestions, [suggestions[i]])) {
+ Assert.deepEqual(
+ actualSuggestions,
+ [suggestions[i]],
+ `Suggestion ${i} is present for keyword ${keyword}`
+ );
+ }
+ }
+ }
+}
+
+add_task(async function duplicateKeywords() {
+ let suggestions = [
+ {
+ title: "suggestion 0",
+ keywords: ["a", "a", "a", "b", "b", "c"],
+ },
+ {
+ title: "suggestion 1",
+ keywords: ["b", "c", "d"],
+ },
+ {
+ title: "suggestion 2",
+ keywords: ["c", "d", "e"],
+ },
+ {
+ title: "suggestion 3",
+ keywords: ["f", "f"],
+ },
+ ];
+
+ let expectedIndexesByKeyword = {
+ a: [0],
+ b: [0, 1],
+ c: [0, 1, 2],
+ d: [1, 2],
+ e: [2],
+ f: [3],
+ };
+
+ let map = new SuggestionsMap();
+ await map.add(suggestions);
+
+ for (let [keyword, indexes] of Object.entries(expectedIndexesByKeyword)) {
+ Assert.deepEqual(
+ map.get(keyword),
+ indexes.map(i => suggestions[i]),
+ "get() with keyword: " + keyword
+ );
+ }
+});
+
+add_task(async function mapKeywords() {
+ let suggestions = [
+ {
+ title: "suggestion 0",
+ keywords: ["a", "a", "a", "b", "b", "c"],
+ },
+ {
+ title: "suggestion 1",
+ keywords: ["b", "c", "d"],
+ },
+ {
+ title: "suggestion 2",
+ keywords: ["c", "d", "e"],
+ },
+ {
+ title: "suggestion 3",
+ keywords: ["f", "f"],
+ },
+ ];
+
+ let expectedIndexesByKeyword = {
+ a: [],
+ b: [],
+ c: [],
+ d: [],
+ e: [],
+ f: [],
+ ax: [0],
+ bx: [0, 1],
+ cx: [0, 1, 2],
+ dx: [1, 2],
+ ex: [2],
+ fx: [3],
+ fy: [3],
+ fz: [3],
+ };
+
+ let map = new SuggestionsMap();
+ await map.add(suggestions, keyword => {
+ if (keyword == "f") {
+ return [keyword + "x", keyword + "y", keyword + "z"];
+ }
+ return [keyword + "x"];
+ });
+
+ for (let [keyword, indexes] of Object.entries(expectedIndexesByKeyword)) {
+ Assert.deepEqual(
+ map.get(keyword),
+ indexes.map(i => suggestions[i]),
+ "get() with keyword: " + keyword
+ );
+ }
+});