summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/imap/test/unit/test_imapHdrChunking.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/imap/test/unit/test_imapHdrChunking.js')
-rw-r--r--comm/mailnews/imap/test/unit/test_imapHdrChunking.js168
1 files changed, 168 insertions, 0 deletions
diff --git a/comm/mailnews/imap/test/unit/test_imapHdrChunking.js b/comm/mailnews/imap/test/unit/test_imapHdrChunking.js
new file mode 100644
index 0000000000..8fc23e8502
--- /dev/null
+++ b/comm/mailnews/imap/test/unit/test_imapHdrChunking.js
@@ -0,0 +1,168 @@
+/* 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 imap msg header download chunking
+ */
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+var { MessageGenerator, MessageScenarioFactory } = ChromeUtils.import(
+ "resource://testing-common/mailnews/MessageGenerator.jsm"
+);
+var { PromiseTestUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/PromiseTestUtils.jsm"
+);
+var { TestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/TestUtils.sys.mjs"
+);
+
+/**
+ * Keep it so that OVERALL_MESSAGES % CHUNKING_SIZE !== 0.
+ * With a modulo operator for CHUNKING_SIZE and a prime number for
+ * OVERALL_MESSAGES this should prove that there have been a
+ * chunking process without being depended on the first chunk.
+ */
+const CHUNKING_SIZE = 3;
+const OVERALL_MESSAGES = 137;
+
+// Dummy message window so we can say the inbox is open in a window.
+var dummyMsgWindow = Cc["@mozilla.org/messenger/msgwindow;1"].createInstance(
+ Ci.nsIMsgWindow
+);
+
+function FolderIntPropertyChangedListener() {
+ this._promise = new Promise(resolve => {
+ this._resolve = resolve;
+ });
+ this._gotNewMailBiff = false;
+}
+
+FolderIntPropertyChangedListener.prototype = {
+ onFolderIntPropertyChanged(aItem, aProperty, aOldValue, aNewValue) {
+ if (
+ aProperty == "BiffState" &&
+ aNewValue == Ci.nsIMsgFolder.nsMsgBiffState_NewMail
+ ) {
+ this._gotNewMailBiff = true;
+ this._resolve();
+ }
+ },
+ get promise() {
+ return this._promise;
+ },
+ get gotNewMailBiff() {
+ return this._gotNewMailBiff;
+ },
+};
+
+var gFolderListener = new FolderIntPropertyChangedListener();
+/** Used to store a listener between tasks for inspecting chunking behaviour. */
+var gListener = new PromiseTestUtils.PromiseUrlListener();
+
+add_setup(async function () {
+ Assert.equal(
+ OVERALL_MESSAGES % CHUNKING_SIZE !== 0,
+ true,
+ "const sanity check"
+ );
+ setupIMAPPump();
+ // We need to register the dummyMsgWindow so that we'll think the
+ // Inbox is open in a folder and fetch headers in chunks.
+ dummyMsgWindow.openFolder = IMAPPump.inbox;
+ MailServices.mailSession.AddMsgWindow(dummyMsgWindow);
+ MailServices.mailSession.AddFolderListener(
+ gFolderListener,
+ Ci.nsIFolderListener.intPropertyChanged
+ );
+
+ // Set chunk size to CHUNKING_SIZE, so we'll have to chain several requests to get
+ // OVERALL_MESSAGES headers.
+ Services.prefs.setIntPref("mail.imap.hdr_chunk_size", CHUNKING_SIZE);
+ // Turn off offline sync to avoid complications in verifying that we can
+ // run a url after the first header chunk.
+ Services.prefs.setBoolPref(
+ "mail.server.server1.autosync_offline_stores",
+ false
+ );
+});
+
+// Upload messages to the imap fake server Inbox.
+add_task(async function uploadImapMessages() {
+ // make OVERALL_MESSAGES messages
+ let messageGenerator = new MessageGenerator();
+ let scenarioFactory = new MessageScenarioFactory(messageGenerator);
+
+ // build up a list of messages
+ let messages = [];
+ messages = messages.concat(scenarioFactory.directReply(OVERALL_MESSAGES));
+
+ // Add OVERALL_MESSAGES messages with uids 1,2,3...,OVERALL_MESSAGES.
+ let imapInbox = IMAPPump.daemon.getMailbox("INBOX");
+ // Create the ImapMessages and store them on the mailbox.
+ messages.forEach(function (message) {
+ let dataUri = Services.io.newURI(
+ "data:text/plain;base64," + btoa(message.toMessageString())
+ );
+ imapInbox.addMessage(
+ new ImapMessage(dataUri.spec, imapInbox.uidnext++, [])
+ );
+ });
+ // Do not wait for the listener to finish.
+ // We want to observe the message batches in the update process.
+ // updateFolderWithListener with null for nsIMsgWindow makes biff notify.
+ IMAPPump.inbox.updateFolderWithListener(null, gListener);
+});
+
+add_task(async function testMessageFetched() {
+ // If we're really chunking, then the message fetch should have started before
+ // we finished the updateFolder URL.
+ await TestUtils.waitForCondition(() => {
+ return gFolderListener.gotNewMailBiff === true;
+ });
+ Assert.ok(gFolderListener.gotNewMailBiff);
+
+ // We do not check for the first chunk as this is unreliable without explicit
+ // listeners/events.
+ // Instead we are checking if there's no rest of the division with
+ // CHUNKING_SIZE while the chunking process is ongoing.
+ // It's important that the chunking is intact and as well not failing
+ // randomly in the test infrastructure.
+ // See at the CHUNKING_SIZE and OVERALL_MESSAGES declarations.
+ //
+ // HINT:
+ // If this causes future problems because stuff getting faster,
+ // try to increase the overall message count.
+ await TestUtils.waitForCondition(() => {
+ let messagesDBFolder = IMAPPump.inbox.msgDatabase.dBFolderInfo.numMessages;
+ if (messagesDBFolder !== 0) {
+ Assert.equal(
+ messagesDBFolder % CHUNKING_SIZE,
+ 0,
+ `${messagesDBFolder} messages in folder should be of chunk size ${CHUNKING_SIZE}`
+ ); // This is the primary test.
+ return true;
+ } else if (messagesDBFolder === OVERALL_MESSAGES) {
+ throw new Error(
+ `Batching failed in sizes of ${CHUNKING_SIZE} found instead ${OVERALL_MESSAGES} immediately`
+ );
+ }
+ return false; // Rerun waitForCondition.
+ }, 50);
+});
+
+add_task(async function testHdrsDownloaded() {
+ await gListener.promise; // Now we wait for the finished update of the Folder.
+ // Make sure that we got all OVERALL_MESSAGES headers.
+ Assert.equal(
+ IMAPPump.inbox.msgDatabase.dBFolderInfo.numMessages,
+ OVERALL_MESSAGES
+ );
+});
+
+// Cleanup
+add_task(async function endTest() {
+ teardownIMAPPump();
+});