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 /comm/mailnews/base/test/unit/test_folderCompact2.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 'comm/mailnews/base/test/unit/test_folderCompact2.js')
-rw-r--r-- | comm/mailnews/base/test/unit/test_folderCompact2.js | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/comm/mailnews/base/test/unit/test_folderCompact2.js b/comm/mailnews/base/test/unit/test_folderCompact2.js new file mode 100644 index 0000000000..dc9d0b865a --- /dev/null +++ b/comm/mailnews/base/test/unit/test_folderCompact2.js @@ -0,0 +1,300 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ +var { MailServices } = ChromeUtils.import( + "resource:///modules/MailServices.jsm" +); +const { PromiseTestUtils } = ChromeUtils.import( + "resource://testing-common/mailnews/PromiseTestUtils.jsm" +); + +/* + * A few more specific mbox compaction tests for local folders: + * - mbox file contains exactly what we expect after compaction? + * test_folderCompact.js tends to rely on checking values in the msgDB. + * - works with messages larger than compaction code internal buffer? + * - X-Mozilla-Status/Status2/Keys headers handled as expected? + * + * Note: all these tests perform a seemingly-arbitrary delete. + * This is to trigger the folder compactor to actually do work. Without that + * delete it tends to think that compaction isn't required and does nothing. + */ + +Services.prefs.setCharPref( + "mail.serverDefaultStoreContractID", + "@mozilla.org/msgstore/berkeleystore;1" +); + +// Escape a string for more useful debug output - show EOLs and spaces. +function esc(s) { + s = s.replace(/\r/g, "\\r"); + s = s.replace(/\n/g, "\\n\n"); + s = s.replace(/ /g, "\u2420"); // U+2420 SYMBOL FOR SPACE + return s; +} + +// Load raw messages into folder (and sanitycheck them). +function loadMsgs(folder, inputMsgs) { + folder.addMessageBatch(inputMsgs); + // Make sure all the loaded messages are the expected size. + // If this fails, it probably means addMessageBatch() no longer assumes input + // data is mbox format, which is good! See Bug 1763263. + let hdrs = Array.from(folder.messages); + for (let i = 0; i < hdrs.length; ++i) { + Assert.equal( + inputMsgs[i].length, + hdrs[i].messageSize, + `Loaded message ${i} should match size in msgDB` + ); + } +} + +// Delete the specified messages. +async function deleteMsgs(folder, indexesToDelete) { + let hdrs = Array.from(folder.messages); + let doomed = indexesToDelete.map(i => hdrs[i]); + let listener = new PromiseTestUtils.PromiseCopyListener(); + folder.deleteMessages(doomed, null, false, true, listener, true); + await listener.promise; +} + +// Check the raw mbox file against what we expect to see. +async function checkMbox(folder, outputMsgs) { + let bytes = await IOUtils.read(folder.filePath.path); + let mbox = ""; + for (let b of bytes) { + mbox += String.fromCharCode(b); + } + + let expected = ""; + for (let raw of outputMsgs) { + // mbox has blank line between messages + expected += raw + "\n"; + } + + // Force all EOLs to linefeeds for comparisons. + // EOLs are handled inconsistently - most code will just leave EOLs as they + // come in, but new EOLs (e.g. added between messages in mbox) will use + // platform native EOLs. So our cheap and cheerful hack here is to just + // ditch all CRs and use pure LFs. + mbox = mbox.replace(/\r/g, ""); + expected = expected.replace(/\r/g, ""); + + if (mbox != expected) { + // Pretty-print before we assert. Makes life so much easier. + dump(`=======mbox=========\n${esc(mbox)}\n============\n`); + dump(`=======expected=====\n${esc(expected)}\n============\n`); + } + Assert.ok(mbox == expected, "mbox should contain expected data"); +} + +// Some chunks from which we'll construct test messages. + +// These are the default X-Mozilla- headers for local folders (they are +// re-written in place when flags and keywords are modified). +let xhdrs = + `X-Mozilla-Status: 0000\r\n` + + `X-Mozilla-Status2: 00010000\r\n` + // 'New' flag is set + `X-Mozilla-Keys: \r\n`; + +let hdrs1 = + "Date: Fri, 21 Nov 1997 09:26:06 -0600\r\n" + + "From: bob@invalid\r\n" + + "Subject: Test message 1\r\n" + + "Message-ID: <blah1@invalid>\r\n"; + +let bod1 = "Body of message 1.\r\n"; + +let hdrs2 = + "Date: Fri, 21 Nov 1997 10:55:32 -0600\r\n" + + "From: bob@invalid\r\n" + + "Subject: Test message 2\r\n" + + "Message-ID: <blah2@invalid>\r\n"; + +let bod2 = "Body of message2.\r\n"; + +let hdrs3 = + `Date: Fri, 21 Nov 1997 11:09:14 -0600\r\n` + + `From: bob@invalid\r\n` + + `Message-ID: <blah3@invalid>\r\n` + + `Subject: Test message 3\r\n`; + +let bod3 = `message\r\nthree\r\nis multiple\r\nlines.\r\n`; + +let from = "From \r\n"; + +// Check compact works after a simple delete. +add_task(async function testSimple() { + localAccountUtils.clearAll(); + localAccountUtils.loadLocalMailAccount(); + let inbox = localAccountUtils.inboxFolder; + + let inMsgs = [ + `${from}${xhdrs}${hdrs1}\r\n${bod1}\r\n`, + `${from}${xhdrs}${hdrs2}\r\n${bod2}\r\n`, + `${from}${xhdrs}${hdrs3}\r\n${bod3}\r\n`, + ]; + let doomed = [1]; // Delete message msg2. + // Out expected output: + let outMsgs = [ + `${from}${xhdrs}${hdrs1}\r\n${bod1}\r\n`, + `${from}${xhdrs}${hdrs3}\r\n${bod3}\r\n`, + ]; + + loadMsgs(inbox, inMsgs); + await deleteMsgs(inbox, doomed); + + let l = new PromiseTestUtils.PromiseUrlListener(); + inbox.compact(l, null); + await l.promise; + + await checkMbox(inbox, outMsgs); +}); + +// Check that local folder compact adds missing X-Mozilla- headers. +add_task(async function testMissingXMozillaHdrs() { + localAccountUtils.clearAll(); + localAccountUtils.loadLocalMailAccount(); + let inbox = localAccountUtils.inboxFolder; + + // No X-Mozilla-* headers on input. + let inMsgs = [ + `${from}${hdrs1}\r\n${bod1}\r\n`, + `${from}${hdrs2}\r\n${bod2}\r\n`, + `${from}${hdrs3}\r\n${bod3}\r\n`, + ]; + let doomed = [1]; // Delete msg2. + // Out expected output. + // Compact should have added X-Mozilla-* headers. + let outMsgs = [ + `${from}${xhdrs}${hdrs1}\r\n${bod1}\r\n`, + `${from}${xhdrs}${hdrs3}\r\n${bod3}\r\n`, + ]; + + loadMsgs(inbox, inMsgs); + await deleteMsgs(inbox, doomed); + + let l = new PromiseTestUtils.PromiseUrlListener(); + inbox.compact(l, null); + await l.promise; + + await checkMbox(inbox, outMsgs); +}); + +// Check localfolder compact works on messages are bigger than internal read buffer. +add_task(async function testBigMessages() { + localAccountUtils.clearAll(); + localAccountUtils.loadLocalMailAccount(); + let inbox = localAccountUtils.inboxFolder; + + // Compaction uses buffer of around 16KB, so we'll go way bigger. + let targSize = 256 * 1024; + + let inMsgs = []; + let outMsgs = []; + let doomed = [0, 1]; // We'll delete the first 2 messages. + for (let i = 0; i < 5; ++i) { + let raw = + `From \r\n` + + xhdrs + + `Date: Fri, 21 Nov 1997 09:55:06 -0600\r\n` + + `From: bob${i}@invalid\r\n` + + `Message-ID: <blah${i}@invalid>\r\n` + + `\r\n`; + while (raw.length < targSize) { + raw += + "BlahBlahBlahBlahBlahBlahBlahBlahBlah" + + "BlahBlahBlahBlahBlahBlahBlahBlahBlah\r\n"; + } + raw += `\r\n`; + inMsgs.push(raw); + if (!doomed.includes(i)) { + outMsgs.push(raw); + } + } + + loadMsgs(inbox, inMsgs); + + await deleteMsgs(inbox, doomed); + + let l = new PromiseTestUtils.PromiseUrlListener(); + inbox.compact(l, null); + await l.promise; + + // outMsgs is what we expect to see in the mbox. + await checkMbox(inbox, outMsgs); +}); + +// Check that local folder compact moves X-Mozilla-* headers to start of +// header block. +add_task(async function testMoveXMozillaHdrs() { + localAccountUtils.clearAll(); + localAccountUtils.loadLocalMailAccount(); + let inbox = localAccountUtils.inboxFolder; + + // These have X-Mozilla-* headers after all the other headers. + let inMsgs = [ + `${from}${hdrs1}${xhdrs}\r\n${bod1}\r\n`, + `${from}${hdrs2}${xhdrs}\r\n${bod2}\r\n`, + `${from}${hdrs3}${xhdrs}\r\n${bod3}\r\n`, + ]; + let doomed = [1]; // Delete msg2. + // The messages we expect to see in the final mbox. + // Compact should have moved the X-Mozilla-* headers to the front. + let outMsgs = [ + `${from}${xhdrs}${hdrs1}\r\n${bod1}\r\n`, + `${from}${xhdrs}${hdrs3}\r\n${bod3}\r\n`, + ]; + + loadMsgs(inbox, inMsgs); + await deleteMsgs(inbox, doomed); + + let l = new PromiseTestUtils.PromiseUrlListener(); + inbox.compact(l, null); + await l.promise; + + await checkMbox(inbox, outMsgs); +}); + +// Check that local folder compact handles large X-Mozilla-Keys value. +add_task(async function testBigXMozillaKeys() { + localAccountUtils.clearAll(); + localAccountUtils.loadLocalMailAccount(); + let inbox = localAccountUtils.inboxFolder; + + let bigKeyword = + "HugeGreatBigStupidlyLongKeywordNameWhichWillDefinitelyOverflowThe80" + + "CharactersUsuallyReservedInTheKeywordsHeaderForInPlaceEditing"; + + let inMsgs = [ + `${from}${xhdrs}${hdrs1}\r\n${bod1}\r\n`, + `${from}${xhdrs}${hdrs2}\r\n${bod2}\r\n`, + `${from}${xhdrs}${hdrs3}\r\n${bod3}\r\n`, + ]; + let doomed = [1]; // Delete msg2. + + let bigxhdrs = + `X-Mozilla-Status: 0000\r\n` + + `X-Mozilla-Status2: 00010000\r\n` + // 'New' flag is set + `X-Mozilla-Keys: ${bigKeyword}\r\n`; + + // The messages we expect to see in the final mbox: + let outMsgs = [ + `${from}${bigxhdrs}${hdrs1}\r\n${bod1}\r\n`, + `${from}${xhdrs}${hdrs3}\r\n${bod3}\r\n`, + ]; + + loadMsgs(inbox, inMsgs); + + let msgs = Array.from(inbox.messages); + inbox.addKeywordsToMessages([msgs[0]], bigKeyword); + + await deleteMsgs(inbox, doomed); + + let l = new PromiseTestUtils.PromiseUrlListener(); + inbox.compact(l, null); + await l.promise; + + await checkMbox(inbox, outMsgs); +}); |