summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/db/gloda/test/unit/test_msg_search.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/db/gloda/test/unit/test_msg_search.js')
-rw-r--r--comm/mailnews/db/gloda/test/unit/test_msg_search.js155
1 files changed, 155 insertions, 0 deletions
diff --git a/comm/mailnews/db/gloda/test/unit/test_msg_search.js b/comm/mailnews/db/gloda/test/unit/test_msg_search.js
new file mode 100644
index 0000000000..2c8ea1c528
--- /dev/null
+++ b/comm/mailnews/db/gloda/test/unit/test_msg_search.js
@@ -0,0 +1,155 @@
+/* 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/. */
+
+/*
+ * Test GlodaMsgSearcher.jsm our heuristic-based fulltext search mechanism. Things we
+ * generally want to verify:
+ * - fulltext weighting by where the match happened works.
+ * - static interestingness impacts things appropriately.
+ *
+ * Our general strategy is to create two messages each with a unique string
+ * placed in controlled places and whatever intentional message manipulation
+ * is required to set things up. Then we query using a GlodaMsgSearcher with
+ * the limit set to 1. Only the message we expect should come back.
+ * Keep in mind in all tests that our underlying ranking mechanism is based on
+ * time so the date of each message is relevant but should not be significant
+ * because our score boost factor should always be well in excess of the one
+ * hour increment between messages.
+ *
+ * Previously, we relied on the general equivalence of the logic in
+ * test_query_core to our message search logic.
+ */
+
+var {
+ assertExpectedMessagesIndexed,
+ glodaTestHelperInitialize,
+ waitForGlodaIndexer,
+} = ChromeUtils.import("resource://testing-common/gloda/GlodaTestHelper.jsm");
+var { queryExpect } = ChromeUtils.import(
+ "resource://testing-common/gloda/GlodaQueryHelper.jsm"
+);
+var { GlodaMsgSearcher } = ChromeUtils.import(
+ "resource:///modules/gloda/GlodaMsgSearcher.jsm"
+);
+var { waitForGlodaDBFlush } = ChromeUtils.import(
+ "resource://testing-common/gloda/GlodaTestHelperFunctions.jsm"
+);
+var { MessageGenerator } = ChromeUtils.import(
+ "resource://testing-common/mailnews/MessageGenerator.jsm"
+);
+var { MessageInjection } = ChromeUtils.import(
+ "resource://testing-common/mailnews/MessageInjection.jsm"
+);
+
+var uniqueCounter = 0;
+var messageInjection;
+
+add_setup(async function () {
+ let msgGen = new MessageGenerator();
+ messageInjection = new MessageInjection({ mode: "local" }, msgGen);
+ glodaTestHelperInitialize(messageInjection);
+});
+
+/**
+ * Verify that the ranking function is using the weights as expected. We do not
+ * need to test all the permutations
+ */
+add_task(async function test_fulltext_weighting_by_column() {
+ let ustr = unique_string();
+ let [, subjSet, bodySet] = await messageInjection.makeFoldersWithSets(1, [
+ { count: 1, subject: ustr },
+ { count: 1, body: { body: ustr } },
+ ]);
+ await waitForGlodaIndexer();
+ Assert.ok(...assertExpectedMessagesIndexed([subjSet, bodySet]));
+ await asyncMsgSearcherExpect(ustr, subjSet);
+});
+
+/**
+ * A term mentioned 3 times in the body is worth more than twice in the subject.
+ * (This is because the subject saturates at one occurrence worth 2.0 and the
+ * body does not saturate until 10, each worth 1.0.)
+ */
+add_task(async function test_fulltext_weighting_saturation() {
+ let ustr = unique_string();
+ let double_ustr = ustr + " " + ustr;
+ let thrice_ustr = ustr + " " + ustr + " " + ustr;
+ let [, subjSet, bodySet] = await messageInjection.makeFoldersWithSets(1, [
+ { count: 1, subject: double_ustr },
+ { count: 1, body: { body: thrice_ustr } },
+ ]);
+ await waitForGlodaIndexer();
+ Assert.ok(...assertExpectedMessagesIndexed([subjSet, bodySet]));
+ await asyncMsgSearcherExpect(ustr, bodySet);
+});
+
+/**
+ * Use a starred message with the same fulltext match characteristics as another
+ * message to verify the preference goes the right way. Have the starred
+ * message be the older message for safety.
+ */
+add_task(async function test_static_interestingness_boost_works() {
+ let ustr = unique_string();
+ let [, starred, notStarred] = await messageInjection.makeFoldersWithSets(1, [
+ { count: 1, subject: ustr },
+ { count: 1, subject: ustr },
+ ]);
+ // Index in their native state.
+ await waitForGlodaIndexer();
+ Assert.ok(...assertExpectedMessagesIndexed([starred, notStarred]));
+ // Star and index.
+ starred.setStarred(true);
+ await waitForGlodaIndexer();
+ Assert.ok(...assertExpectedMessagesIndexed([starred]));
+ // Stars upon thars wins.
+ await asyncMsgSearcherExpect(ustr, starred);
+});
+
+/**
+ * Make sure that the query does not retrieve more than actually matches.
+ */
+add_task(async function test_joins_do_not_return_everybody() {
+ let ustr = unique_string();
+ let [, subjSet] = await messageInjection.makeFoldersWithSets(1, [
+ { count: 1, subject: ustr },
+ ]);
+ await waitForGlodaIndexer();
+ Assert.ok(...assertExpectedMessagesIndexed([subjSet]));
+ await asyncMsgSearcherExpect(ustr, subjSet, 2);
+});
+
+/**
+ * Generate strings like "aaaaa", "aabaa", "aacaa", etc. The idea with the
+ * suffix is to avoid the porter stemmer from doing something weird that
+ * collapses things.
+ */
+function unique_string() {
+ let uval = uniqueCounter++;
+ let s =
+ String.fromCharCode(97 + Math.floor(uval / (26 * 26))) +
+ String.fromCharCode(97 + (Math.floor(uval / 26) % 26)) +
+ String.fromCharCode(97 + (uval % 26)) +
+ "aa";
+ return s;
+}
+
+/**
+ * Wrap the construction of a GlodaMsgSearcher with a limit of 1 and feed it to
+ * queryExpect.
+ *
+ * @param aFulltextStr The fulltext query string which GlodaMsgSearcher will
+ * parse.
+ * @param aExpectedSet The expected result set. Make sure that the size of the
+ * set is consistent with aLimit.
+ * @param [aLimit=1]
+ *
+ * Use like so:
+ * await asyncMsgSearchExpect("foo bar", someSynMsgSet);
+ */
+async function asyncMsgSearcherExpect(aFulltextStr, aExpectedSet, aLimit) {
+ let limit = aLimit ? aLimit : 1;
+ Services.prefs.setIntPref("mailnews.database.global.search.msg.limit", limit);
+ let searcher = new GlodaMsgSearcher(null, aFulltextStr);
+ await queryExpect(searcher.buildFulltextQuery(), aExpectedSet);
+}