Bug 477054 Implement onProgress for the send later service, and fix counts for sending more than once in the same session. r/sr=bienvenu
--- a/mailnews/compose/src/nsMsgSendLater.cpp
+++ b/mailnews/compose/src/nsMsgSendLater.cpp
@@ -551,16 +551,21 @@ nsMsgSendLater::StartNextMailFileSend()
mMessagesToSend.Clear();
mSendingMessages = PR_FALSE;
NotifyListenersOnStopSending(NS_OK, nsnull, mTotalSendCount, mTotalSentSuccessfully);
// XXX Should we be releasing references so that we don't hold onto items
// unnecessarily.
return NS_OK;
}
+ // Let everyone know about our progress if we've already sent more than one
+ // message.
+ if (mTotalSendCount)
+ NotifyListenersOnProgress(mTotalSendCount, mMessagesToSend.Count());
+
nsCOMPtr<nsISupports> currentItem;
rv = mEnumerator->GetNext(getter_AddRefs(currentItem));
NS_ENSURE_SUCCESS(rv, rv);
mMessage = do_QueryInterface(currentItem);
if (!mMessage)
return NS_ERROR_NOT_AVAILABLE;
@@ -667,21 +672,24 @@ nsMsgSendLater::SendUnsentMessages(nsIMs
if (NS_SUCCEEDED(rv))
{
messageHeader = do_QueryInterface(currentItem, &rv);
if (NS_SUCCEEDED(rv))
mMessagesToSend.AppendObject(messageHeader);
}
}
- // now get an enumerator for our array
+ // Now get an enumerator for our array.
rv = NS_NewArrayEnumerator(getter_AddRefs(mEnumerator), mMessagesToSend);
NS_ENSURE_SUCCESS(rv, rv);
+ // We're now sending messages so its time to signal that and reset our counts.
mSendingMessages = PR_TRUE;
+ mTotalSentSuccessfully = 0;
+ mTotalSendCount = 0;
// Notify the listeners that we are starting a send.
NotifyListenersOnStartSending(mMessagesToSend.Count());
return StartNextMailFileSend();
}
nsresult nsMsgSendLater::SetOrigMsgDisposition()
--- a/mailnews/compose/test/unit/data/429891_testcase.eml
+++ b/mailnews/compose/test/unit/data/429891_testcase.eml
@@ -1,10 +1,10 @@
From: Invalid User <invalid@invalid.com>
-To: Invalid User <invalid@invalid.com>
+To: Invalid User <to@invalid.com>
Subject: Big email
012345678901234567890123456789012345678901234567890123456789
012345678901234567890123456789012345678901234567890123456789
012345678901234567890123456789012345678901234567890123456789
012345678901234567890123456789012345678901234567890123456789
012345678901234567890123456789012345678901234567890123456789
012345678901234567890123456789012345678901234567890123456789
--- a/mailnews/compose/test/unit/head_compose.js
+++ b/mailnews/compose/test/unit/head_compose.js
@@ -56,8 +56,40 @@ function do_check_transaction(real, expe
// closed after we have a chance to process it and not them. We therefore
// excise this from the list
if (real.them[real.them.length-1] == "QUIT")
real.them.pop();
do_check_eq(real.them.join(","), expected.join(","));
dump("Passed test " + test + "\n");
}
+
+// This listener is designed just to call OnStopCopy() when its OnStopCopy
+// function is called - the rest of the functions are unneeded for a lot of
+// tests.
+var copyListener = {
+ // nsIMsgSendListener
+ onStartSending: function (aMsgID, aMsgSize) {},
+ onProgress: function (aMsgID, aProgress, aProgressMax) {},
+ onStatus: function (aMsgID, aMsg) {},
+ onStopSending: function (aMsgID, aStatus, aMsg, aReturnFile) {},
+ onGetDraftFolderURI: function (aFolderURI) {},
+ onSendNotPerformed: function (aMsgID, aStatus) {},
+
+ // nsIMsgCopyServiceListener
+ OnStartCopy: function () {},
+ OnProgress: function (aProgress, aProgressMax) {},
+ SetMessageKey: function (aKey) {},
+ GetMessageId: function (aMessageId) {},
+ OnStopCopy: function (aStatus) {
+ OnStopCopy(aStatus);
+ },
+
+ // QueryInterface
+ QueryInterface: function (iid) {
+ if (iid.equals(Ci.nsIMsgSendListener) ||
+ iid.equals(Ci.nsIMsgCopyServiceListener) ||
+ iid.equals(Ci.nsISupports))
+ return this;
+
+ throw Components.results.NS_ERROR_NO_INTERFACE;
+ }
+};
--- a/mailnews/compose/test/unit/test_bug474774.js
+++ b/mailnews/compose/test/unit/test_bug474774.js
@@ -9,17 +9,17 @@ var server;
var sentFolder;
var transaction;
var originalData;
var finished = false;
var identity = null;
var testFile = do_get_file("../mailnews/compose/test/unit/data/429891_testcase.eml");
const kSender = "from@invalid.com";
-const kTo = "invalid@invalid.com";
+const kTo = "to@invalid.com";
var msgSendLater = Cc["@mozilla.org/messengercompose/sendlater;1"]
.getService(Ci.nsIMsgSendLater);
// This listener handles the post-sending of the actual message and checks the
// sequence and ensures the data is correct.
function msll() {
}
@@ -66,97 +66,57 @@ msll.prototype = {
var thread = gThreadManager.currentThread;
while (thread.hasPendingEvents())
thread.processNextEvent(true);
}
}
};
-// This listener is used to find out when the copying of the message to the
-// unsent message folder is completed, and hence can fire off the actual
-// sending of the message.
-function copyListener() {
-}
+function OnStopCopy(aStatus)
+{
+ do_test_finished();
+
+ try {
+ do_check_eq(aStatus, 0);
-copyListener.prototype = {
- // nsIMsgSendListener
- onStartSending: function (aMsgID, aMsgSize) {
- },
- onProgress: function (aMsgID, aProgress, aProgressMax) {
- },
- onStatus: function (aMsgID, aMsg) {
- },
- onStopSending: function (aMsgID, aStatus, aMsg, aReturnFile) {
- },
- onGetDraftFolderURI: function (aFolderURI) {
- },
- onSendNotPerformed: function (aMsgID, aStatus) {
- },
+ // Check this is false before we start sending
+ do_check_eq(msgSendLater.sendingMessages, false);
+
+ let folder = msgSendLater.getUnsentMessagesFolder(identity);
- // nsIMsgCopyServiceListener
- OnStartCopy: function () {
- },
- OnProgress: function (aProgress, aProgressMax) {
- },
- SetMessageKey: function (aKey) {
- },
- GetMessageId: function (aMessageId) {
- },
- OnStopCopy: function (aStatus) {
- do_test_finished();
+ // Check we have a message in the unsent message folder
+ do_check_eq(folder.getTotalMessages(false), 1);
- try {
- do_check_eq(aStatus, 0);
-
- // Check this is false before we start sending
- do_check_eq(msgSendLater.sendingMessages, false);
-
- let folder = msgSendLater.getUnsentMessagesFolder(identity);
+ // Now do a comparison of what is in the sent mail folder
+ var fileData = loadFileToString(folder.filePath);
- // Check we have a message in the unsent message folder
- do_check_eq(folder.getTotalMessages(false), 1);
-
- // Now do a comparison of what is in the sent mail folder
- var fileData = loadFileToString(folder.filePath);
+ // Skip the headers etc that mailnews adds
+ var pos = fileData.indexOf("From:");
+ do_check_neq(pos, -1);
- // Skip the headers etc that mailnews adds
- var pos = fileData.indexOf("From:");
- do_check_neq(pos, -1);
+ fileData = fileData.substr(pos);
- fileData = fileData.substr(pos);
-
- // Check the data is matching.
- do_check_eq(originalData, fileData);
+ // Check the data is matching.
+ do_check_eq(originalData, fileData);
- do_test_pending();
- do_timeout(sendMessageLater(), 0);
- } catch (e) {
- do_throw(e);
- } finally {
- server.stop();
-
- var thread = gThreadManager.currentThread;
- while (thread.hasPendingEvents())
- thread.processNextEvent(true);
+ do_test_pending();
+ do_timeout(sendMessageLater(), 0);
+ } catch (e) {
+ do_throw(e);
+ } finally {
+ server.stop();
- finished = true;
- }
- },
+ var thread = gThreadManager.currentThread;
+ while (thread.hasPendingEvents())
+ thread.processNextEvent(true);
- // QueryInterface
- QueryInterface: function (iid) {
- if (iid.equals(Ci.nsIMsgSendListener) ||
- iid.equals(Ci.nsIMsgCopyServiceListener) ||
- iid.equals(Ci.nsISupports))
- return this;
-
- throw Components.results.NS_ERROR_NO_INTERFACE;
+ finished = true;
}
-};
+}
// This function does the actual send later
function sendMessageLater()
{
do_test_finished();
// Set up the SMTP server.
server = setupServerDaemon();
@@ -229,20 +189,18 @@ function run_test() {
// unsent messages folder.
var compFields = Cc["@mozilla.org/messengercompose/composefields;1"]
.createInstance(Ci.nsIMsgCompFields);
compFields.from = identity.email;
compFields.to = kTo;
- var cl = new copyListener(true);
-
var msgSend = Cc["@mozilla.org/messengercompose/send;1"]
.createInstance(Ci.nsIMsgSend);
msgSend.sendMessageFile(identity, "", compFields, testFile,
false, false, Ci.nsIMsgSend.nsMsgQueueForLater,
- null, cl, null, null);
+ null, copyListener, null, null);
// Now we wait till we get copy notification of completion.
do_test_pending();
}
--- a/mailnews/compose/test/unit/test_sendMessageLater.js
+++ b/mailnews/compose/test/unit/test_sendMessageLater.js
@@ -16,17 +16,17 @@ var server;
var sentFolder;
var transaction;
var originalData;
var finished = false;
var identity = null;
var testFile = do_get_file("../mailnews/compose/test/unit/data/429891_testcase.eml");
const kSender = "from@invalid.com";
-const kTo = "invalid@invalid.com";
+const kTo = "to@invalid.com";
var msgSendLater = Cc["@mozilla.org/messengercompose/sendlater;1"]
.getService(Ci.nsIMsgSendLater);
// This listener handles the post-sending of the actual message and checks the
// sequence and ensures the data is correct.
function msll() {
}
@@ -73,97 +73,56 @@ msll.prototype = {
var thread = gThreadManager.currentThread;
while (thread.hasPendingEvents())
thread.processNextEvent(true);
}
}
};
-// This listener is used to find out when the copying of the message to the
-// unsent message folder is completed, and hence can fire off the actual
-// sending of the message.
-function copyListener() {
-}
+function OnStopCopy(aStatus) {
+ do_test_finished();
+
+ try {
+ do_check_eq(aStatus, 0);
-copyListener.prototype = {
- // nsIMsgSendListener
- onStartSending: function (aMsgID, aMsgSize) {
- },
- onProgress: function (aMsgID, aProgress, aProgressMax) {
- },
- onStatus: function (aMsgID, aMsg) {
- },
- onStopSending: function (aMsgID, aStatus, aMsg, aReturnFile) {
- },
- onGetDraftFolderURI: function (aFolderURI) {
- },
- onSendNotPerformed: function (aMsgID, aStatus) {
- },
+ // Check this is false before we start sending
+ do_check_eq(msgSendLater.sendingMessages, false);
+
+ let folder = msgSendLater.getUnsentMessagesFolder(identity);
- // nsIMsgCopyServiceListener
- OnStartCopy: function () {
- },
- OnProgress: function (aProgress, aProgressMax) {
- },
- SetMessageKey: function (aKey) {
- },
- GetMessageId: function (aMessageId) {
- },
- OnStopCopy: function (aStatus) {
- do_test_finished();
+ // Check we have a message in the unsent message folder
+ do_check_eq(folder.getTotalMessages(false), 1);
- try {
- do_check_eq(aStatus, 0);
-
- // Check this is false before we start sending
- do_check_eq(msgSendLater.sendingMessages, false);
-
- let folder = msgSendLater.getUnsentMessagesFolder(identity);
+ // Now do a comparison of what is in the sent mail folder
+ var fileData = loadFileToString(folder.filePath);
- // Check we have a message in the unsent message folder
- do_check_eq(folder.getTotalMessages(false), 1);
-
- // Now do a comparison of what is in the sent mail folder
- var fileData = loadFileToString(folder.filePath);
+ // Skip the headers etc that mailnews adds
+ var pos = fileData.indexOf("From:");
+ do_check_neq(pos, -1);
- // Skip the headers etc that mailnews adds
- var pos = fileData.indexOf("From:");
- do_check_neq(pos, -1);
+ fileData = fileData.substr(pos);
- fileData = fileData.substr(pos);
-
- // Check the data is matching.
- do_check_eq(originalData, fileData);
+ // Check the data is matching.
+ do_check_eq(originalData, fileData);
- do_test_pending();
- do_timeout(sendMessageLater(), 0);
- } catch (e) {
- do_throw(e);
- } finally {
- server.stop();
-
- var thread = gThreadManager.currentThread;
- while (thread.hasPendingEvents())
- thread.processNextEvent(true);
+ do_test_pending();
+ do_timeout(sendMessageLater(), 0);
+ } catch (e) {
+ do_throw(e);
+ } finally {
+ server.stop();
- finished = true;
- }
- },
+ var thread = gThreadManager.currentThread;
+ while (thread.hasPendingEvents())
+ thread.processNextEvent(true);
- // QueryInterface
- QueryInterface: function (iid) {
- if (iid.equals(Ci.nsIMsgSendListener) ||
- iid.equals(Ci.nsIMsgCopyServiceListener) ||
- iid.equals(Ci.nsISupports))
- return this;
-
- throw Components.results.NS_ERROR_NO_INTERFACE;
+ finished = true;
}
-};
+}
// This function does the actual send later
function sendMessageLater()
{
do_test_finished();
// Set up the SMTP server.
server = setupServerDaemon();
@@ -236,20 +195,18 @@ function run_test() {
// unsent messages folder.
var compFields = Cc["@mozilla.org/messengercompose/composefields;1"]
.createInstance(Ci.nsIMsgCompFields);
compFields.from = identity.email;
compFields.to = kTo;
- var cl = new copyListener(true);
-
var msgSend = Cc["@mozilla.org/messengercompose/send;1"]
.createInstance(Ci.nsIMsgSend);
msgSend.sendMessageFile(identity, "", compFields, testFile,
false, false, Ci.nsIMsgSend.nsMsgQueueForLater,
- null, cl, null, null);
+ null, copyListener, null, null);
// Now we wait till we get copy notification of completion.
do_test_pending();
}
new file mode 100644
--- /dev/null
+++ b/mailnews/compose/test/unit/test_sendMessageLater2.js
@@ -0,0 +1,310 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/**
+ * Complex test for the send message later function - including sending multiple
+ * times in the same session.
+ *
+ * XXX: This test is intended to additionally test sending of multiple messages
+ * from one send later instance, however due to the fact we use one connection
+ * per message sent, it is very difficult to consistently get the fake server
+ * reconected in time for the next connection. Thus, sending of multiple
+ * messages is currently disabled (but commented out for local testing if
+ * required), when we fix bug 136871 we should be able to enable the multiple
+ * messages option.
+ */
+var test = "sendMessageLater";
+var server = null;
+var gSentFolder;
+var transaction;
+var originalData;
+var identity = null;
+var gMsgFile =
+[
+ do_get_file("../mailnews/compose/test/unit/data/message1.eml"),
+ do_get_file("../mailnews/compose/test/unit/data/429891_testcase.eml")
+];
+var gMsgFileData = [];
+var gMsgOrder = [];
+var gCurTestNum = 0;
+var gLastSentMessage = 0;
+
+const kSender = "from@invalid.com";
+const kTo = "to@invalid.com";
+
+var msgSendLater = Cc["@mozilla.org/messengercompose/sendlater;1"]
+ .getService(Ci.nsIMsgSendLater);
+
+// This listener handles the post-sending of the actual message and checks the
+// sequence and ensures the data is correct.
+function msll() {
+}
+
+msll.prototype = {
+ // nsIMsgSendLaterListener
+ onStartSending: function (aTotal) {
+ do_check_eq(aTotal, gMsgOrder.length);
+ do_check_eq(msgSendLater.sendingMessages, true);
+ },
+ onProgress: function (aCurrentMessage, aTotal) {
+ try {
+ do_check_eq(aTotal, gMsgOrder.length);
+ do_check_eq(gLastSentMessage + 1, aCurrentMessage);
+ gLastSentMessage = aCurrentMessage;
+ do_check_eq(msgSendLater.sendingMessages, true);
+
+ do_check_transaction(transaction,
+ ["EHLO test",
+ "MAIL FROM:<" + kSender + "> SIZE=" + gMsgFileData[gMsgOrder[aCurrentMessage - 1]].length,
+ "RCPT TO:<" + kTo + ">",
+ "DATA"]);
+ transaction = null;
+
+ // Compare data file to what the server received
+ do_check_eq(gMsgFileData[gMsgOrder[aCurrentMessage - 1]], server._handler.post);
+
+ // XXX We've got more messages to receive so restart the server for the
+ // new connection, at least until bug 136871 is fixed - we reset and stop
+ // the server on exit, the next test runs the server for the next message.
+ do_timeout(0, "doTest(++gCurTestNum)");
+ } catch (e) {
+ do_throw(e);
+ } finally {
+ // Reset
+ server.resetTest();
+
+ // XXX This is the way we currently try and restart the server which
+ // doesn't always work, once we fix bug 136871 just calling resetTest and
+ // ensuring we play the transaction should be enough.
+ server.stop();
+
+ var thread = gThreadManager.currentThread;
+ while (thread.hasPendingEvents())
+ thread.processNextEvent(true);
+ server.start(SMTP_PORT);
+
+ var thread = gThreadManager.currentThread;
+ while (thread.hasPendingEvents())
+ thread.processNextEvent(true);
+ }
+ },
+ onStatus: function (aMsg) {
+ // XXX Do we really need this?
+ },
+ onStopSending: function (aStatus, aMsg, aTotal, aSuccessful) {
+ try {
+ do_check_eq(aStatus, 0);
+ do_check_eq(aTotal, aSuccessful);
+ do_check_eq(msgSendLater.sendingMessages, false);
+
+ // XXX This is another send multiple messages hack
+ if (!transaction) {
+ server.performTest();
+ transaction = server.playTransaction();
+ }
+
+ do_check_transaction(transaction,
+ ["EHLO test",
+ "MAIL FROM:<" + kSender + "> SIZE=" + gMsgFileData[gMsgOrder[aTotal - 1]].length,
+ "RCPT TO:<" + kTo + ">",
+ "DATA"]);
+ transaction = null;
+
+ // Compare data file to what the server received
+ do_check_eq(gMsgFileData[gMsgOrder[aTotal - 1]], server._handler.post);
+
+ do_timeout(0, "doTest(++gCurTestNum)");
+ } catch (e) {
+ dump(e);
+ do_throw(e);
+ } finally {
+ server.resetTest();
+ server.stop();
+
+ var thread = gThreadManager.currentThread;
+ while (thread.hasPendingEvents())
+ thread.processNextEvent(true);
+ }
+ }
+};
+
+// This function is used to find out when the copying of the message to the
+// unsent message folder is completed, and hence can fire off the actual
+// sending of the message.
+function OnStopCopy(aStatus)
+{
+ do_check_eq(aStatus, 0);
+
+ // Check this is false before we start sending
+ do_check_eq(msgSendLater.sendingMessages, false);
+
+ // Check we have a message in the unsent message folder
+ do_check_eq(gSentFolder.getTotalMessages(false), gMsgOrder.length);
+
+ // Start the next step after a brief time so that functions can finish
+ // properly
+ do_timeout(0, "doTest(++gCurTestNum);");
+}
+
+function sendMessageLater(aTestFileIndex)
+{
+ gMsgOrder.push(aTestFileIndex);
+
+ // Prepare to actually "send" the message later, i.e. dump it in the
+ // unsent messages folder.
+
+ var compFields = Cc["@mozilla.org/messengercompose/composefields;1"]
+ .createInstance(Ci.nsIMsgCompFields);
+
+ compFields.from = identity.email;
+ compFields.to = kTo;
+
+ var msgSend = Cc["@mozilla.org/messengercompose/send;1"]
+ .createInstance(Ci.nsIMsgSend);
+
+ msgSend.sendMessageFile(identity, "", compFields, gMsgFile[aTestFileIndex],
+ false, false, Ci.nsIMsgSend.nsMsgQueueForLater,
+ null, copyListener, null, null);
+}
+
+function resetCounts()
+{
+ gMsgOrder = [];
+ gLastSentMessage = 0;
+ do_timeout(0, "doTest(++gCurTestNum);");
+}
+
+// This function does the actual send later
+function sendUnsentMessages()
+{
+ // Handle the server in a try/catch/finally loop so that we always will stop
+ // the server if something fails.
+ try {
+ // Start the fake SMTP server
+ server.start(SMTP_PORT);
+
+ // Send the unsent message
+ msgSendLater.sendUnsentMessages(identity);
+
+ server.performTest();
+
+ transaction = server.playTransaction();
+ } catch (e) {
+ do_throw(e);
+ } finally {
+ server.stop();
+
+ var thread = gThreadManager.currentThread;
+ while (thread.hasPendingEvents())
+ thread.processNextEvent(true);
+ }
+}
+
+function runServerTest()
+{
+ server.performTest();
+
+ transaction = server.playTransaction();
+}
+
+// Beware before commenting out a test
+// -- later tests might just depend on earlier ones
+const gTestArray =
+[
+ // Copying message from file to folder.
+ function testSendLater1() { sendMessageLater(0); },
+
+ // Now send unsent message
+ function testSendUnsentMessages1() { sendUnsentMessages(); },
+
+ function testSentEmpty() {
+ do_check_eq(gSentFolder.getTotalMessages(false), 0);
+ doTest(++gCurTestNum);
+ },
+
+ // This function just resets a few counts where necessary.
+ function testResetCounts() { resetCounts(); },
+
+ // Now copy more messages...
+ function testCopyFileMessage2() {
+ sendMessageLater(1);
+ // XXX Only do one the second time round, as described at the start of the
+ // file.
+ // sendMessageLater(0);
+ },
+ // ...and send again
+ function testSendUnsentMessages2() { sendUnsentMessages(); },
+
+ // XXX This may be needed if sending more than one message in the second
+ // stage.
+ // function testRunServer() { runServerTest(); }
+];
+
+function run_test() {
+ // Load in the test files so we have a record of length and their data.
+ for (var i = 0; i < gMsgFile.length; ++i) {
+ gMsgFileData[i] = loadFileToString(gMsgFile[i]);
+ }
+
+ // Ensure we have a local mail account, an normal account and appropriate
+ // servers and identities.
+ loadLocalMailAccount();
+
+ var acctMgr = Cc["@mozilla.org/messenger/account-manager;1"]
+ .getService(Ci.nsIMsgAccountManager);
+ acctMgr.setSpecialFolders();
+
+ var account = acctMgr.createAccount();
+ incomingServer = acctMgr.createIncomingServer("test", "localhost", "pop3");
+
+ var smtpServer = getBasicSmtpServer();
+ identity = getSmtpIdentity(kSender, smtpServer);
+
+ account.addIdentity(identity);
+ account.defaultIdentity = identity;
+ account.incomingServer = incomingServer;
+
+ gLocalIncomingServer.rootMsgFolder.addSubfolder("Sent");
+
+ gSentFolder = msgSendLater.getUnsentMessagesFolder(identity);
+
+ // Don't copy messages to sent folder for this test
+ identity.doFcc = false;
+
+ // Create and add a listener
+ var messageListener = new msll();
+
+ msgSendLater.addListener(messageListener);
+
+ // Set up the server
+ server = setupServerDaemon();
+ server.setDebugLevel(fsDebugRecv);
+
+ // "Master" do_test_pending(), paired with a do_test_finished() at the end of
+ // all the operations.
+ do_test_pending();
+
+ // Do the test
+ doTest(1);
+}
+
+function doTest(test)
+{
+ dump("doTest " + test + "\n");
+ if (test <= gTestArray.length) {
+ gCurTestNum = test;
+
+ var testFn = gTestArray[test-1];
+
+ // Set a limit in case the notifications haven't arrived (i.e. a problem)
+ do_timeout(10000, "if (gCurTestNum == "+test+") \
+ do_throw('Notifications not received in 10000 ms for operation "+testFn.name+", current status is '+gCurrStatus);");
+ try {
+ testFn();
+ } catch(ex) {
+ dump(ex);
+ do_throw(ex);
+ }
+ }
+ else {
+ do_test_finished(); // for the one in run_test()
+ }
+}