diff options
Diffstat (limited to '')
-rw-r--r-- | comm/mailnews/db/gloda/test/unit/test_msg_search.js | 155 |
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); +} |