summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/news/test
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--comm/mailnews/news/test/moz.build6
-rw-r--r--comm/mailnews/news/test/unit/head_server_setup.js244
-rw-r--r--comm/mailnews/news/test/unit/postings/auto-add/post1.eml14
-rw-r--r--comm/mailnews/news/test/unit/postings/auto-add/post2.eml14
-rw-r--r--comm/mailnews/news/test/unit/postings/auto-add/post3.eml14
-rw-r--r--comm/mailnews/news/test/unit/postings/auto-add/post4.eml14
-rw-r--r--comm/mailnews/news/test/unit/postings/auto-add/post5.eml50
-rw-r--r--comm/mailnews/news/test/unit/postings/auto-add/post6.eml14
-rw-r--r--comm/mailnews/news/test/unit/postings/auto-add/post7.eml14
-rw-r--r--comm/mailnews/news/test/unit/postings/auto-add/post8.eml14
-rw-r--r--comm/mailnews/news/test/unit/postings/bug403242.eml25
-rw-r--r--comm/mailnews/news/test/unit/postings/bug670935.eml7
-rw-r--r--comm/mailnews/news/test/unit/postings/post1.eml7
-rw-r--r--comm/mailnews/news/test/unit/postings/post2.eml6
-rw-r--r--comm/mailnews/news/test/unit/postings/post3.eml10
-rw-r--r--comm/mailnews/news/test/unit/test_NntpChannel.js74
-rw-r--r--comm/mailnews/news/test/unit/test_biff.js57
-rw-r--r--comm/mailnews/news/test/unit/test_bug170727.js61
-rw-r--r--comm/mailnews/news/test/unit/test_bug37465.js49
-rw-r--r--comm/mailnews/news/test/unit/test_bug403242.js55
-rw-r--r--comm/mailnews/news/test/unit/test_bug540288.js114
-rw-r--r--comm/mailnews/news/test/unit/test_bug695309.js121
-rw-r--r--comm/mailnews/news/test/unit/test_cancelPasswordDialog.js59
-rw-r--r--comm/mailnews/news/test/unit/test_filter.js179
-rw-r--r--comm/mailnews/news/test/unit/test_getNewsMessage.js101
-rw-r--r--comm/mailnews/news/test/unit/test_internalUris.js305
-rw-r--r--comm/mailnews/news/test/unit/test_newsAutocomplete.js107
-rw-r--r--comm/mailnews/news/test/unit/test_nntpContentLength.js80
-rw-r--r--comm/mailnews/news/test/unit/test_nntpGroupPassword.js99
-rw-r--r--comm/mailnews/news/test/unit/test_nntpPassword.js54
-rw-r--r--comm/mailnews/news/test/unit/test_nntpPassword2.js106
-rw-r--r--comm/mailnews/news/test/unit/test_nntpPassword3.js46
-rw-r--r--comm/mailnews/news/test/unit/test_nntpPasswordFailure.js196
-rw-r--r--comm/mailnews/news/test/unit/test_nntpPost.js37
-rw-r--r--comm/mailnews/news/test/unit/test_nntpProtocols.js55
-rw-r--r--comm/mailnews/news/test/unit/test_nntpProxy.js38
-rw-r--r--comm/mailnews/news/test/unit/test_nntpUrl.js30
-rw-r--r--comm/mailnews/news/test/unit/test_server.js179
-rw-r--r--comm/mailnews/news/test/unit/test_uriParser.js221
-rw-r--r--comm/mailnews/news/test/unit/test_xover.js42
-rw-r--r--comm/mailnews/news/test/unit/xpcshell.ini35
41 files changed, 2953 insertions, 0 deletions
diff --git a/comm/mailnews/news/test/moz.build b/comm/mailnews/news/test/moz.build
new file mode 100644
index 0000000000..6b37fdbe09
--- /dev/null
+++ b/comm/mailnews/news/test/moz.build
@@ -0,0 +1,6 @@
+# vim: set filetype=python:
+# 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/.
+
+XPCSHELL_TESTS_MANIFESTS += ["unit/xpcshell.ini"]
diff --git a/comm/mailnews/news/test/unit/head_server_setup.js b/comm/mailnews/news/test/unit/head_server_setup.js
new file mode 100644
index 0000000000..6a5bcbda9f
--- /dev/null
+++ b/comm/mailnews/news/test/unit/head_server_setup.js
@@ -0,0 +1,244 @@
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+var { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+var { localAccountUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/LocalAccountUtils.jsm"
+);
+
+var test = null;
+
+// WebApps.jsm called by ProxyAutoConfig (PAC) requires a valid nsIXULAppInfo.
+var { getAppInfo, newAppInfo, updateAppInfo } = ChromeUtils.importESModule(
+ "resource://testing-common/AppInfo.sys.mjs"
+);
+updateAppInfo();
+
+// Ensure the profile directory is set up
+do_get_profile();
+
+var gDEPTH = "../../../../";
+
+// Import the servers
+var { fsDebugAll, gThreadManager, nsMailServer } = ChromeUtils.import(
+ "resource://testing-common/mailnews/Maild.jsm"
+);
+var {
+ NewsArticle,
+ NNTP_Giganews_handler,
+ NNTP_RFC2980_handler,
+ NNTP_RFC4643_extension,
+ NNTP_RFC977_handler,
+ NntpDaemon,
+} = ChromeUtils.import("resource://testing-common/mailnews/Nntpd.jsm");
+
+var kSimpleNewsArticle =
+ "From: John Doe <john.doe@example.com>\n" +
+ "Date: Sat, 24 Mar 1990 10:59:24 -0500\n" +
+ "Newsgroups: test.subscribe.simple\n" +
+ "Subject: H2G2 -- What does it mean?\n" +
+ "Message-ID: <TSS1@nntp.invalid>\n" +
+ "\n" +
+ "What does the acronym H2G2 stand for? I've seen it before...\n";
+
+// The groups to set up on the fake server.
+// It is an array of tuples, where the first element is the group name and the
+// second element is whether or not we should subscribe to it.
+var groups = [
+ ["misc.test", false],
+ ["test.empty", false],
+ ["test.subscribe.empty", true],
+ ["test.subscribe.simple", true],
+ ["test.filter", true],
+];
+// Sets up the NNTP daemon object for use in fake server
+function setupNNTPDaemon() {
+ var daemon = new NntpDaemon();
+
+ groups.forEach(function (element) {
+ daemon.addGroup(element[0]);
+ });
+
+ var auto_add = do_get_file("postings/auto-add/");
+ var files = [...auto_add.directoryEntries];
+
+ files.sort(function (a, b) {
+ if (a.leafName == b.leafName) {
+ return 0;
+ }
+ return a.leafName < b.leafName ? -1 : 1;
+ });
+
+ files.forEach(function (file) {
+ var fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(
+ Ci.nsIFileInputStream
+ );
+ var sstream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(
+ Ci.nsIScriptableInputStream
+ );
+ fstream.init(file, -1, 0, 0);
+ sstream.init(fstream);
+
+ var post = "";
+ let part = sstream.read(4096);
+ while (part.length > 0) {
+ post += part;
+ part = sstream.read(4096);
+ }
+ sstream.close();
+ fstream.close();
+ daemon.addArticle(new NewsArticle(post));
+ });
+
+ var article = new NewsArticle(kSimpleNewsArticle);
+ daemon.addArticleToGroup(article, "test.subscribe.simple", 1);
+
+ return daemon;
+}
+
+function makeServer(handler, daemon) {
+ function createHandler(d) {
+ return new handler(d);
+ }
+ return new nsMailServer(createHandler, daemon);
+}
+
+// Enable strict threading
+Services.prefs.setBoolPref("mail.strict_threading", true);
+
+// Make sure we don't try to use a protected port. I like adding 1024 to the
+// default port when doing so...
+var NNTP_PORT = 1024 + 119;
+
+var _server = null;
+var _account = null;
+
+function subscribeServer(incomingServer) {
+ // Subscribe to newsgroups
+ incomingServer.QueryInterface(Ci.nsINntpIncomingServer);
+ groups.forEach(function (element) {
+ if (element[1]) {
+ incomingServer.subscribeToNewsgroup(element[0]);
+ }
+ });
+ // Only allow one connection
+ incomingServer.maximumConnectionsNumber = 1;
+}
+
+// Sets up the client-side portion of fakeserver
+function setupLocalServer(port, host = "localhost") {
+ if (_server != null) {
+ return _server;
+ }
+ let serverAndAccount = localAccountUtils.create_incoming_server_and_account(
+ "nntp",
+ port,
+ null,
+ null,
+ host
+ );
+ let server = serverAndAccount.server;
+ subscribeServer(server);
+
+ _server = server;
+ _account = serverAndAccount.account;
+
+ return server;
+}
+
+// Sets up a protocol object and prepares to run the test for the news url
+function setupProtocolTest(port, newsUrl, incomingServer) {
+ var url;
+ if (newsUrl instanceof Ci.nsIMsgMailNewsUrl) {
+ url = newsUrl;
+ } else {
+ url = Services.io.newURI(newsUrl);
+ }
+
+ var newsServer = incomingServer;
+ if (!newsServer) {
+ newsServer = setupLocalServer(port);
+ }
+
+ var listener = {
+ onStartRequest() {},
+ onStopRequest() {
+ if (!this.called) {
+ this.called = true;
+ newsServer.closeCachedConnections();
+ this.called = false;
+ }
+ },
+ onDataAvailable() {},
+ QueryInterface: ChromeUtils.generateQI(["nsIStreamListener"]),
+ };
+ listener.called = false;
+ newsServer.loadNewsUrl(url, null, listener);
+}
+
+function create_post(baseURL, file) {
+ var url = Services.io.newURI(baseURL);
+ url.QueryInterface(Ci.nsINntpUrl);
+
+ var post = Cc["@mozilla.org/messenger/nntpnewsgrouppost;1"].createInstance(
+ Ci.nsINNTPNewsgroupPost
+ );
+ post.postMessageFile = do_get_file(file);
+ url.messageToPost = post;
+ return url;
+}
+
+function resetFolder(folder) {
+ var headers = [...folder.messages];
+
+ var db = folder.msgDatabase;
+ db.dBFolderInfo.knownArtsSet = "";
+ for (var header of headers) {
+ db.deleteHeader(header, null, true, false);
+ }
+ dump("resetting folder\n");
+ folder.msgDatabase = null;
+}
+
+function do_check_transaction(real, expected) {
+ if (Array.isArray(real)) {
+ real = real.at(-1);
+ }
+
+ // real.them may have an extra QUIT on the end, where the stream is only
+ // 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();
+ }
+
+ Assert.equal(real.them.join(","), expected.join(","));
+ dump("Passed test " + test + "\n");
+}
+
+function make_article(file) {
+ var fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(
+ Ci.nsIFileInputStream
+ );
+ var sstream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(
+ Ci.nsIScriptableInputStream
+ );
+ fstream.init(file, -1, 0, 0);
+ sstream.init(fstream);
+
+ var post = "";
+ let part = sstream.read(4096);
+ while (part.length > 0) {
+ post += part;
+ part = sstream.read(4096);
+ }
+ sstream.close();
+ fstream.close();
+ return new NewsArticle(post);
+}
+
+registerCleanupFunction(function () {
+ load("../../../resources/mailShutdown.js");
+});
diff --git a/comm/mailnews/news/test/unit/postings/auto-add/post1.eml b/comm/mailnews/news/test/unit/postings/auto-add/post1.eml
new file mode 100644
index 0000000000..9e1f3e7265
--- /dev/null
+++ b/comm/mailnews/news/test/unit/postings/auto-add/post1.eml
@@ -0,0 +1,14 @@
+Path: border1.nntp.dca.giganews.com!nntp.giganews.com!local02.nntp.dca.giganews.com!nntp.mozilla.org!news.mozilla.org.POSTED!not-for-mail
+Date: Mon, 23 Jun 2008 19:58:07 +0400
+From: Normal Person <fake@acme.invalid>
+User-Agent: Program/1.0
+MIME-Version: 1.0
+Newsgroups: test.filter
+Subject: First post!
+Content-Type: text/plain; charset=ISO-8859-1; format=flowed
+Content-Transfer-Encoding: 7bit
+Message-ID: <1@regular.invalid>
+NNTP-Posting-Host: 127.0.0.1
+Xref: test.filter:1
+
+This is the first body post.
diff --git a/comm/mailnews/news/test/unit/postings/auto-add/post2.eml b/comm/mailnews/news/test/unit/postings/auto-add/post2.eml
new file mode 100644
index 0000000000..d5a4591bb3
--- /dev/null
+++ b/comm/mailnews/news/test/unit/postings/auto-add/post2.eml
@@ -0,0 +1,14 @@
+Path: border1.nntp.dca.giganews.com!nntp.giganews.com!local02.nntp.dca.giganews.com!nntp.mozilla.org!news.mozilla.org.POSTED!not-for-mail
+Date: Mon, 23 Jun 2008 19:58:07 +0400
+From: Normal Person <fake@acme.invalid>
+User-Agent: Program/1.0
+MIME-Version: 1.0
+Newsgroups: test.filter
+Subject: Odd Subject
+Content-Type: text/plain; charset=ISO-8859-1; format=flowed
+Content-Transfer-Encoding: 7bit
+Message-ID: <2@regular.invalid>
+NNTP-Posting-Host: 127.0.0.1
+Xref: test.filter:2
+
+This is the second body post.
diff --git a/comm/mailnews/news/test/unit/postings/auto-add/post3.eml b/comm/mailnews/news/test/unit/postings/auto-add/post3.eml
new file mode 100644
index 0000000000..fdfc2d69c1
--- /dev/null
+++ b/comm/mailnews/news/test/unit/postings/auto-add/post3.eml
@@ -0,0 +1,14 @@
+Path: border1.nntp.dca.giganews.com!nntp.giganews.com!local02.nntp.dca.giganews.com!nntp.mozilla.org!news.mozilla.org.POSTED!not-for-mail
+Date: Mon, 23 Jun 2008 19:58:07 +0400
+From: Odd Person <fake@acme.invalid>
+User-Agent: Program/1.0
+MIME-Version: 1.0
+Newsgroups: test.filter
+Subject: Regular subject
+Content-Type: text/plain; charset=ISO-8859-1; format=flowed
+Content-Transfer-Encoding: 7bit
+Message-ID: <3@regular.invalid>
+NNTP-Posting-Host: 127.0.0.1
+Xref: test.filter:3
+
+This is the third body post.
diff --git a/comm/mailnews/news/test/unit/postings/auto-add/post4.eml b/comm/mailnews/news/test/unit/postings/auto-add/post4.eml
new file mode 100644
index 0000000000..11a53b7035
--- /dev/null
+++ b/comm/mailnews/news/test/unit/postings/auto-add/post4.eml
@@ -0,0 +1,14 @@
+Path: border1.nntp.dca.giganews.com!nntp.giganews.com!local02.nntp.dca.giganews.com!nntp.mozilla.org!news.mozilla.org.POSTED!not-for-mail
+Date: Sat, 1 Jan 2000 19:58:07 +0400
+From: Normal Person <fake@acme.invalid>
+User-Agent: Program/1.0
+MIME-Version: 1.0
+Newsgroups: test.filter
+Subject: Regular subject
+Content-Type: text/plain; charset=ISO-8859-1; format=flowed
+Content-Transfer-Encoding: 7bit
+Message-ID: <4@regular.invalid>
+NNTP-Posting-Host: 127.0.0.1
+Xref: test.filter:4
+
+This is the fourth body post.
diff --git a/comm/mailnews/news/test/unit/postings/auto-add/post5.eml b/comm/mailnews/news/test/unit/postings/auto-add/post5.eml
new file mode 100644
index 0000000000..55ba89c022
--- /dev/null
+++ b/comm/mailnews/news/test/unit/postings/auto-add/post5.eml
@@ -0,0 +1,50 @@
+Path: border1.nntp.dca.giganews.com!nntp.giganews.com!local02.nntp.dca.giganews.com!nntp.mozilla.org!news.mozilla.org.POSTED!not-for-mail
+Date: Mon, 23 Jun 2008 19:58:07 +0400
+From: Normal Person <fake@acme.invalid>
+User-Agent: Program/1.0
+MIME-Version: 1.0
+Newsgroups: test.filter
+Subject: Regular subject
+Content-Type: text/plain; charset=ISO-8859-1; format=flowed
+Content-Transfer-Encoding: 7bit
+Message-ID: <5@regular.invalid>
+NNTP-Posting-Host: 127.0.0.1
+Xref: test.filter:5
+Bytes: 2057
+
+This is the fifth body post, with extra special padding to make sure
+that no one else has the same length as it. You see, we have to ensure
+that we have at least two KB of data because search is stupid and
+searches in terms of KB. If we didn't, we'd be stuck with a lot of
+messages merely matching 1, so we use this to pad the size.
+
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
+tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
+veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
+commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
+velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
+occaecat cupidatat non proident, sunt in culpa qui officia deserunt
+mollit anim id est laborum.
+
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
+tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
+veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
+commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
+velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
+occaecat cupidatat non proident, sunt in culpa qui officia deserunt
+mollit anim id est laborum.
+
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
+tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
+veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
+commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
+velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
+occaecat cupidatat non proident, sunt in culpa qui officia deserunt
+mollit anim id est laborum.
+
+.
+
+But that wasn't all :-)
+
+--
+A signature for the heck of it.
diff --git a/comm/mailnews/news/test/unit/postings/auto-add/post6.eml b/comm/mailnews/news/test/unit/postings/auto-add/post6.eml
new file mode 100644
index 0000000000..fe9d536203
--- /dev/null
+++ b/comm/mailnews/news/test/unit/postings/auto-add/post6.eml
@@ -0,0 +1,14 @@
+Path: border1.nntp.dca.giganews.com!nntp.giganews.com!local02.nntp.dca.giganews.com!nntp.mozilla.org!news.mozilla.org.POSTED!not-for-mail
+Date: Mon, 23 Jun 2008 19:58:07 +0400
+From: Normal Person <fake@acme.invalid>
+User-Agent: Program/1.0
+MIME-Version: 1.0
+Newsgroups: test.filter
+Subject: Regular subject
+Content-Type: text/plain; charset=ISO-8859-1; format=flowed
+Content-Transfer-Encoding: 7bit
+Message-ID: <6.odd@regular.invalid>
+NNTP-Posting-Host: 127.0.0.1
+Xref: test.filter:6
+
+This is the sixth body post.
diff --git a/comm/mailnews/news/test/unit/postings/auto-add/post7.eml b/comm/mailnews/news/test/unit/postings/auto-add/post7.eml
new file mode 100644
index 0000000000..f12b708a9d
--- /dev/null
+++ b/comm/mailnews/news/test/unit/postings/auto-add/post7.eml
@@ -0,0 +1,14 @@
+Path: border1.nntp.dca.giganews.com!nntp.giganews.com!local02.nntp.dca.giganews.com!nntp.mozilla.org!news.mozilla.org.POSTED!not-for-mail
+Date: Mon, 23 Jun 2008 19:58:07 +0400
+From: Normal Person <fake@acme.invalid>
+User-Agent: Odd/1.0
+MIME-Version: 1.0
+Newsgroups: test.filter
+Subject: Regular subject
+Content-Type: text/plain; charset=ISO-8859-1; format=flowed
+Content-Transfer-Encoding: 7bit
+Message-ID: <7@regular.invalid>
+NNTP-Posting-Host: 127.0.0.1
+Xref: test.filter:7
+
+This is the seventh body post.
diff --git a/comm/mailnews/news/test/unit/postings/auto-add/post8.eml b/comm/mailnews/news/test/unit/postings/auto-add/post8.eml
new file mode 100644
index 0000000000..265b1f5a4a
--- /dev/null
+++ b/comm/mailnews/news/test/unit/postings/auto-add/post8.eml
@@ -0,0 +1,14 @@
+Path: border1.nntp.dca.giganews.com!nntp.giganews.com!local02.nntp.dca.giganews.com!nntp.mozilla.org!news.mozilla.org.POSTED!not-for-mail
+Date: Mon, 23 Jun 2008 19:58:07 +0400
+From: Normal Person <fake@acme.invalid>
+User-Agent: Odd/1.0
+MIME-Version: 1.0
+Newsgroups: test.filter
+Subject: Regular subject
+Content-Type: text/plain; charset=ISO-8859-1; format=flowed
+Content-Transfer-Encoding: 7bit
+Message-ID: <8.unread@regular.invalid>
+NNTP-Posting-Host: 127.0.0.1
+Xref: test.filter:8
+
+This is the eight body post.
diff --git a/comm/mailnews/news/test/unit/postings/bug403242.eml b/comm/mailnews/news/test/unit/postings/bug403242.eml
new file mode 100644
index 0000000000..741ccf8624
--- /dev/null
+++ b/comm/mailnews/news/test/unit/postings/bug403242.eml
@@ -0,0 +1,25 @@
+Message-ID: <89550684-f0df-4e9a-aea6-07645e238dd2>
+Subject: Attachment test
+From: =?ISO-8859-1?Q?Marcin_Miko=3Fajczak?= <marcin.mikolajczak@hotmail.invalid>
+Date: 2007-11-09 18:37:09
+Newsgroups: test1
+Content-Type: multipart/mixed; boundary="------------060805070701070202060104"
+MIME-Version: 1.0
+User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.6) Gecko/20070728 Thunderbird/2.0.0.6 Mnenhy/0.7.5.666
+
+This is a multi-part message in MIME format.
+--------------060805070701070202060104
+Content-Type: text/plain; charset=ISO-8859-1
+Content-Transfer-Encoding: 7bit
+
+This message has an attachment.
+
+--------------060805070701070202060104
+Content-Type: text/plain;
+ name="Test.txt"
+Content-Transfer-Encoding: base64
+Content-Disposition: inline;
+ filename="Test.txt"
+
+VGhpcyBpcyBhIHRlc3QgYXR0YWNobWVudC4=
+--------------060805070701070202060104--
diff --git a/comm/mailnews/news/test/unit/postings/bug670935.eml b/comm/mailnews/news/test/unit/postings/bug670935.eml
new file mode 100644
index 0000000000..7762586a2f
--- /dev/null
+++ b/comm/mailnews/news/test/unit/postings/bug670935.eml
@@ -0,0 +1,7 @@
+From: Robert Kagan <Robert.Kagan@test.invalid>
+Date: Fri, 24 Mar 1989 00:04:18 -0900
+Newsgroups: test.malformed&name
+Subject: I think we have a problem
+
+This is an automated report. There may be some structural damage in
+sectors 10 and 9. Please respond to confirm.
diff --git a/comm/mailnews/news/test/unit/postings/post1.eml b/comm/mailnews/news/test/unit/postings/post1.eml
new file mode 100644
index 0000000000..b767aca453
--- /dev/null
+++ b/comm/mailnews/news/test/unit/postings/post1.eml
@@ -0,0 +1,7 @@
+From: Robert Kagan <Robert.Kagan@test.invalid>
+Date: Fri, 24 Mar 1989 00:04:18 -0900
+Newsgroups: test.news.problems test.news.fictional
+Subject: I think we have a problem
+
+This is an automated report. There may be some structural damage in
+sectors 10 and 9. Please respond to confirm.
diff --git a/comm/mailnews/news/test/unit/postings/post2.eml b/comm/mailnews/news/test/unit/postings/post2.eml
new file mode 100644
index 0000000000..c64818c6df
--- /dev/null
+++ b/comm/mailnews/news/test/unit/postings/post2.eml
@@ -0,0 +1,6 @@
+From: "Demo User" <nobody@example.net>
+Newsgroups: misc.test
+Subject: I am just a test article
+Organization: An Example Net
+
+This is just a test article.
diff --git a/comm/mailnews/news/test/unit/postings/post3.eml b/comm/mailnews/news/test/unit/postings/post3.eml
new file mode 100644
index 0000000000..7769fbf3d7
--- /dev/null
+++ b/comm/mailnews/news/test/unit/postings/post3.eml
@@ -0,0 +1,10 @@
+From: "Demo User" <nobody@example.net>
+Message-ID: <2@dot.invalid>
+Newsgroups: dot.test
+Subject: Bug 170727: Test article with dots
+
+. 1 dot
+.. 2 dots
+ .indented dot
+.
+no - that wasn't the end of the message!
diff --git a/comm/mailnews/news/test/unit/test_NntpChannel.js b/comm/mailnews/news/test/unit/test_NntpChannel.js
new file mode 100644
index 0000000000..0da7963c78
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_NntpChannel.js
@@ -0,0 +1,74 @@
+/* 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 { NntpChannel } = ChromeUtils.import("resource:///modules/NntpChannel.jsm");
+var { PromiseTestUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/PromiseTestUtils.jsm"
+);
+
+let server;
+
+add_setup(function setup() {
+ let daemon = setupNNTPDaemon();
+ server = new nsMailServer(() => {
+ let handler = new NNTP_RFC977_handler(daemon);
+ // Test NntpClient works with 201 response.
+ handler.onStartup = () => {
+ return "201 posting prohibited";
+ };
+ return handler;
+ }, daemon);
+ server.start(NNTP_PORT);
+ registerCleanupFunction(() => {
+ server.stop();
+ });
+
+ setupLocalServer(NNTP_PORT);
+});
+
+/**
+ * Test a ?list-ids news url will trigger LISTGROUP request.
+ */
+add_task(async function test_listIds() {
+ // Init the uri and streamListener.
+ let uri = Services.io.newURI(
+ `news://localhost:${NNTP_PORT}/test.filter?list-ids`
+ );
+ let streamListener = new PromiseTestUtils.PromiseStreamListener();
+
+ // Run the uri with NntpChannel.
+ let channel = new NntpChannel(uri);
+ channel.asyncOpen(streamListener);
+ await streamListener.promise;
+
+ // Test LISTGROUP request was sent correctly.
+ let transaction = server.playTransaction();
+ do_check_transaction(transaction, ["MODE READER", "LISTGROUP test.filter"]);
+});
+
+/**
+ * Test a ?group=name&key=x news url will trigger ARTICLE request.
+ */
+add_task(async function test_fetchArticle() {
+ _server.closeCachedConnections();
+
+ // Init the uri and streamListener.
+ let uri = Services.io.newURI(
+ `news://localhost:${NNTP_PORT}?group=test.filter&key=1`
+ );
+ let streamListener = new PromiseTestUtils.PromiseStreamListener();
+
+ // Run the uri with NntpChannel.
+ let channel = new NntpChannel(uri);
+ channel.asyncOpen(streamListener);
+ await streamListener.promise;
+
+ // Test ARTICLE request was sent correctly.
+ let transaction = server.playTransaction();
+ do_check_transaction(transaction, [
+ "MODE READER",
+ "GROUP test.filter",
+ "ARTICLE 1",
+ ]);
+});
diff --git a/comm/mailnews/news/test/unit/test_biff.js b/comm/mailnews/news/test/unit/test_biff.js
new file mode 100644
index 0000000000..ba6266ef25
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_biff.js
@@ -0,0 +1,57 @@
+// This tests that we can execute biff properly, specifically that filters are
+// run during biff, producing correct counts.
+
+/* import-globals-from ../../../test/resources/filterTestUtils.js */
+load("../../../resources/filterTestUtils.js");
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+function run_test() {
+ // Set up the server and add in filters
+ let daemon = setupNNTPDaemon();
+ let server = makeServer(NNTP_RFC2980_handler, daemon);
+ server.start();
+ let localserver = setupLocalServer(server.port);
+ // Remove all but the test.filter folder
+ let rootFolder = localserver.rootFolder;
+ for (let folder of rootFolder.subFolders) {
+ if (folder.name != "test.filter") {
+ rootFolder.propagateDelete(folder, true);
+ }
+ }
+
+ // Create a filter to mark one message read.
+ let filters = localserver.getFilterList(null);
+ filters.loggingEnabled = true;
+ createFilter(filters, "subject", "Odd", "read");
+ localserver.setFilterList(filters);
+
+ // This is a bit hackish, but we don't have any really functional callbacks
+ // for biff. Instead, we use the notifier to look for all 7 messages to be
+ // added and take that as our sign that the download is finished.
+ let expectCount = 7,
+ seen = 0;
+ let listener = {
+ msgAdded() {
+ if (++seen == expectCount) {
+ localserver.closeCachedConnections();
+ }
+ },
+ };
+ MailServices.mfn.addListener(
+ listener,
+ Ci.nsIMsgFolderNotificationService.msgAdded
+ );
+ localserver.performBiff(null);
+ server.performTest();
+ MailServices.mfn.removeListener(listener);
+
+ // We marked, via our filters, one of the messages read. So if we do not
+ // have 1 read message, either we're not running the filters on biff, or the
+ // filters aren't working. This is disambiguated by the test_filter.js test.
+ let folder = localserver.rootFolder.getChildNamed("test.filter");
+ Assert.equal(folder.getTotalMessages(false), folder.getNumUnread(false) + 1);
+ server.stop();
+}
diff --git a/comm/mailnews/news/test/unit/test_bug170727.js b/comm/mailnews/news/test/unit/test_bug170727.js
new file mode 100644
index 0000000000..50bda7b096
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_bug170727.js
@@ -0,0 +1,61 @@
+// Bug 170727 - Remove the escaped dot from body lines before saving in the offline store.
+
+const { PromiseTestUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/PromiseTestUtils.jsm"
+);
+
+add_task(async function testloadMessage() {
+ let daemon = setupNNTPDaemon();
+ daemon.addGroup("dot.test");
+ daemon.addArticle(make_article(do_get_file("postings/post3.eml")));
+
+ let server = makeServer(NNTP_RFC2980_handler, daemon);
+ server.start();
+ let localserver = setupLocalServer(server.port);
+ localserver.subscribeToNewsgroup("dot.test");
+
+ let folder = localserver.rootFolder.getChildNamed("dot.test");
+ folder.setFlag(Ci.nsMsgFolderFlags.Offline);
+ folder.getNewMessages(null, {
+ OnStopRunningUrl() {
+ localserver.closeCachedConnections();
+ },
+ });
+ server.performTest();
+
+ let uri = folder.generateMessageURI(1);
+ let msgService = Cc[
+ "@mozilla.org/messenger/messageservice;1?type=news"
+ ].getService(Ci.nsIMsgMessageService);
+
+ // Pretend to display the message: During the first run, the article is downloaded,
+ // displayed directly and simultaneously saved in the offline storage.
+ {
+ let listener = new PromiseTestUtils.PromiseStreamListener();
+ msgService.loadMessage(uri, listener, null, null, false);
+ let msgText = await listener.promise;
+ localserver.closeCachedConnections();
+
+ // Correct text? (original file uses LF only, so strip CR)
+ Assert.equal(
+ msgText.replaceAll("\r", ""),
+ daemon.getArticle("<2@dot.invalid>").fullText
+ );
+ }
+
+ // In the second run, the offline store serves as the source of the article.
+ {
+ let listener = new PromiseTestUtils.PromiseStreamListener();
+ msgService.loadMessage(uri, listener, null, null, false);
+ let msgText = await listener.promise;
+ localserver.closeCachedConnections();
+
+ // Correct text? (original file uses LF only, so strip CR)
+ Assert.equal(
+ msgText.replaceAll("\r", ""),
+ daemon.getArticle("<2@dot.invalid>").fullText
+ );
+ }
+
+ server.stop();
+});
diff --git a/comm/mailnews/news/test/unit/test_bug37465.js b/comm/mailnews/news/test/unit/test_bug37465.js
new file mode 100644
index 0000000000..e3d61c9dbe
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_bug37465.js
@@ -0,0 +1,49 @@
+// Bug 37465 -- assertions with no accounts
+
+const { PromiseTestUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/PromiseTestUtils.jsm"
+);
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+add_task(async function textChannelAsync() {
+ let daemon = setupNNTPDaemon();
+ let server = makeServer(NNTP_RFC2980_handler, daemon);
+ server.start();
+
+ // Correct URI?
+ let uri = Services.io.newURI(
+ "news://localhost:" + server.port + "/1@regular.invalid"
+ );
+ let newsUri = uri
+ .QueryInterface(Ci.nsINntpUrl)
+ .QueryInterface(Ci.nsIMsgMailNewsUrl);
+ Assert.equal(uri.port, server.port);
+ Assert.equal(newsUri.server, null);
+ Assert.equal(newsUri.messageID, "1@regular.invalid");
+ Assert.equal(newsUri.folder, null);
+
+ // Run the URI and make sure we get the message
+ let channel = Services.io.newChannelFromURI(
+ uri,
+ null,
+ Services.scriptSecurityManager.getSystemPrincipal(),
+ null,
+ Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
+ Ci.nsIContentPolicy.TYPE_OTHER
+ );
+ let listener = new PromiseTestUtils.PromiseStreamListener();
+ channel.asyncOpen(listener, null);
+ let msgText = await listener.promise;
+ // Correct text? (original file uses LF only, so strip CR)
+ Assert.equal(
+ msgText.replaceAll("\r", ""),
+ daemon.getArticle("<1@regular.invalid>").fullText
+ );
+
+ // Shut down connections
+ MailServices.accounts.closeCachedConnections();
+ server.stop();
+});
diff --git a/comm/mailnews/news/test/unit/test_bug403242.js b/comm/mailnews/news/test/unit/test_bug403242.js
new file mode 100644
index 0000000000..54a385da78
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_bug403242.js
@@ -0,0 +1,55 @@
+// Bug 403242 stems from invalid message ids
+
+const { PromiseTestUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/PromiseTestUtils.jsm"
+);
+
+add_task(async function test403242() {
+ let daemon = setupNNTPDaemon();
+ daemon.addGroup("test1");
+ daemon.addArticle(make_article(do_get_file("postings/bug403242.eml")));
+ let server = makeServer(NNTP_RFC2980_handler, daemon);
+ server.start();
+ let localserver = setupLocalServer(server.port);
+ localserver.subscribeToNewsgroup("test1");
+
+ let folder = localserver.rootFolder.getChildNamed("test1");
+ folder.getNewMessages(null, {
+ OnStopRunningUrl() {
+ localserver.closeCachedConnections();
+ },
+ });
+ server.performTest();
+
+ // Fetch the message
+ let uri = folder.generateMessageURI(1);
+ let msgService = Cc[
+ "@mozilla.org/messenger/messageservice;1?type=news"
+ ].getService(Ci.nsIMsgMessageService);
+
+ // Does the URL lie to us?
+ let neckoUrl = msgService.getUrlForUri(uri).QueryInterface(Ci.nsINntpUrl);
+ Assert.equal(neckoUrl.newsAction, Ci.nsINntpUrl.ActionFetchArticle);
+
+ // Pretend to display the message
+ let listener = new PromiseTestUtils.PromiseStreamListener();
+ msgService.loadMessage(uri, listener, null, null, false);
+ let msgText = await listener.promise;
+ localserver.closeCachedConnections();
+ server.stop();
+
+ // Correct text? (original file uses LF only, so strip CR)
+ Assert.equal(
+ msgText.replaceAll("\r", ""),
+ daemon.getGroup("test1")[1].fullText
+ );
+
+ // No illegal commands?
+ test = "bug 403242";
+ let transaction = server.playTransaction();
+ do_check_transaction(transaction[transaction.length - 1], [
+ "MODE READER",
+ "GROUP test1",
+ "ARTICLE 1",
+ ]);
+});
diff --git a/comm/mailnews/news/test/unit/test_bug540288.js b/comm/mailnews/news/test/unit/test_bug540288.js
new file mode 100644
index 0000000000..9ffe8a7616
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_bug540288.js
@@ -0,0 +1,114 @@
+/* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* Tests that an empty cache entry doesn't return an empty message for news. */
+
+// The basic daemon to use for testing Nntpd.jsm implementations
+var daemon = setupNNTPDaemon();
+
+var server;
+var localserver;
+
+var streamListener = {
+ _data: "",
+
+ QueryInterface: ChromeUtils.generateQI([
+ "nsIStreamListener",
+ "nsIRequestObserver",
+ ]),
+
+ // nsIRequestObserver
+ onStartRequest(aRequest) {},
+ onStopRequest(aRequest, aStatusCode) {
+ Assert.equal(aStatusCode, 0);
+
+ // Reduce any \r\n to just \n so we can do a good comparison on any
+ // platform.
+ var reduced = this._data.replace(/\r\n/g, "\n");
+ Assert.equal(reduced, kSimpleNewsArticle);
+
+ // We must finish closing connections and tidying up after a timeout
+ // so that the thread has time to unwrap itself.
+ do_timeout(0, doTestFinished);
+ },
+
+ // nsIStreamListener
+ onDataAvailable(aRequest, aInputStream, aOffset, aCount) {
+ let scriptStream = Cc[
+ "@mozilla.org/scriptableinputstream;1"
+ ].createInstance(Ci.nsIScriptableInputStream);
+
+ scriptStream.init(aInputStream);
+
+ this._data += scriptStream.read(aCount);
+ },
+};
+
+function doTestFinished() {
+ localserver.closeCachedConnections();
+
+ server.stop();
+
+ var thread = gThreadManager.currentThread;
+ while (thread.hasPendingEvents()) {
+ thread.processNextEvent(true);
+ }
+
+ do_test_finished();
+}
+
+function run_test() {
+ server = makeServer(NNTP_RFC977_handler, daemon);
+ server.start();
+ localserver = setupLocalServer(server.port);
+ var uri = Services.io.newURI(
+ "news://localhost:" + server.port + "/TSS1%40nntp.test"
+ );
+
+ try {
+ // Add an empty message to the cache
+ MailServices.nntp.cacheStorage.asyncOpenURI(
+ uri,
+ "",
+ Ci.nsICacheStorage.OPEN_NORMALLY,
+ {
+ onCacheEntryAvailable(cacheEntry, isNew, status) {
+ Assert.equal(status, Cr.NS_OK);
+
+ cacheEntry.markValid();
+
+ // Get the folder and new mail
+ var folder = localserver.rootFolder.getChildNamed(
+ "test.subscribe.simple"
+ );
+ folder.clearFlag(Ci.nsMsgFolderFlags.Offline);
+ folder.getNewMessages(null, {
+ OnStopRunningUrl() {
+ localserver.closeCachedConnections();
+ },
+ });
+ server.performTest();
+
+ Assert.equal(folder.getTotalMessages(false), 1);
+ Assert.ok(folder.hasNewMessages);
+
+ server.resetTest();
+
+ var message = folder.firstNewMessage;
+
+ var messageUri = folder.getUriForMsg(message);
+
+ Cc["@mozilla.org/messenger/messageservice;1?type=news"]
+ .getService(Ci.nsIMsgMessageService)
+ .loadMessage(messageUri, streamListener, null, null, false);
+
+ // Get the server to run
+ server.performTest();
+ },
+ }
+ );
+
+ do_test_pending();
+ } catch (e) {
+ server.stop();
+ do_throw(e);
+ }
+}
diff --git a/comm/mailnews/news/test/unit/test_bug695309.js b/comm/mailnews/news/test/unit/test_bug695309.js
new file mode 100644
index 0000000000..d51587ba08
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_bug695309.js
@@ -0,0 +1,121 @@
+/* Tests the connection mayhem found by bug 695309 */
+
+// The full bug requires several things to fall into place:
+// 1. Cause the connections to timeout, while keeping them in the cache.
+// 2. Enqueue enough requests to cause things to be placed in the pending queue.
+// 3. Commands try to run but die instead.
+// 4. Enqueue more requests to open up new connections.
+// 5. When loading, the connection ends up pulling somebody from the queue and
+// ends up treating the response for the prior command as the current
+// response.
+// 6. This causes, in particular, GROUP to read the logon string as the response
+// (where sprintf clears everything to 0), and AUTHINFO to think credentials
+// are wrong. The bug's description is then caused by the next read seeing
+// a large number of (not really) new messages.
+// For the purposes of this test, we read enough to see if the group command is
+// being misread or not, as it is complicated enough.
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+const { PromiseTestUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/PromiseTestUtils.jsm"
+);
+
+const { NetworkTestUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/NetworkTestUtils.jsm"
+);
+
+var daemon, localserver, server;
+var highWater = 0;
+
+add_setup(async function () {
+ daemon = setupNNTPDaemon();
+ server = makeServer(NNTP_RFC2980_handler, daemon);
+ server.start();
+ localserver = setupLocalServer(server.port);
+
+ // Bug 1050840:
+ // Check if invalid value of the max_cached_connections pref
+ // is properly folded into a sane value.
+ localserver.maximumConnectionsNumber = -5;
+ Assert.equal(localserver.maximumConnectionsNumber, 1);
+
+ localserver.maximumConnectionsNumber = 0;
+ Assert.equal(localserver.maximumConnectionsNumber, 2);
+
+ localserver.maximumConnectionsNumber = 2;
+});
+
+add_task(async function test_newMsgs() {
+ // Start by initializing the folder, and mark some messages as read.
+ let folder = localserver.rootFolder.getChildNamed("test.filter");
+ Assert.equal(folder.getTotalMessages(false), 0);
+ let asyncUrlListener = new PromiseTestUtils.PromiseUrlListener();
+ folder.getNewMessages(null, asyncUrlListener);
+ await asyncUrlListener.promise;
+ // Do another folder to use up both connections
+ localserver.rootFolder
+ .getChildNamed("test.subscribe.simple")
+ .getNewMessages(null, asyncUrlListener);
+ await asyncUrlListener.promise;
+ folder.QueryInterface(Ci.nsIMsgNewsFolder).setReadSetFromStr("1-3");
+ Assert.equal(folder.getTotalMessages(false) - folder.getNumUnread(false), 3);
+ highWater = folder.getTotalMessages(false);
+ Assert.equal(folder.msgDatabase.dBFolderInfo.highWater, highWater);
+});
+
+add_task(async function trigger_bug() {
+ // Kill the connection and start it up again.
+ server.stop();
+ server.start();
+
+ // Get new messages for all folders. Once we've seen one folder, trigger a
+ // load of the folder in question. This second load should, if the bug is
+ // present, be overwritten with one from the load queue that causes the
+ // confusion. It then loads it again, and should (before the patch that fixes
+ // this) read the 200 logon instead of the 211 group.
+ let testFolder = localserver.rootFolder.getChildNamed("test.filter");
+ let asyncUrlListener = new PromiseTestUtils.PromiseUrlListener();
+ let promiseFolderEvent = function (folder, event) {
+ return new Promise((resolve, reject) => {
+ let folderListener = {
+ QueryInterface: ChromeUtils.generateQI(["nsIFolderListener"]),
+ onFolderEvent(aEventFolder, aEvent) {
+ if (
+ aEvent == "FolderLoaded" &&
+ aEventFolder.prettyName == "test.subscribe.simple"
+ ) {
+ aEventFolder.getNewMessages(null, asyncUrlListener);
+ return;
+ }
+
+ if (folder === aEventFolder && event == aEvent) {
+ MailServices.mailSession.RemoveFolderListener(folderListener);
+ resolve();
+ }
+ },
+ };
+ MailServices.mailSession.AddFolderListener(
+ folderListener,
+ Ci.nsIFolderListener.event
+ );
+ });
+ };
+ let folderLoadedPromise = promiseFolderEvent(testFolder, "FolderLoaded");
+
+ localserver.performExpand(null);
+
+ // Wait for test.subscribe.simple to load. That will trigger getNewMessages.
+ await folderLoadedPromise;
+ // Wait for the new messages to be loaded.
+ await asyncUrlListener.promise;
+
+ Assert.equal(testFolder.msgDatabase.dBFolderInfo.highWater, highWater);
+});
+
+add_task(async function cleanUp() {
+ NetworkTestUtils.shutdownServers();
+ localserver.closeCachedConnections();
+});
diff --git a/comm/mailnews/news/test/unit/test_cancelPasswordDialog.js b/comm/mailnews/news/test/unit/test_cancelPasswordDialog.js
new file mode 100644
index 0000000000..5212614b3a
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_cancelPasswordDialog.js
@@ -0,0 +1,59 @@
+/* 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 { PromiseTestUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/PromiseTestUtils.jsm"
+);
+
+/* import-globals-from ../../../test/resources/alertTestUtils.js */
+load("../../../resources/alertTestUtils.js");
+
+let daemon = setupNNTPDaemon();
+let server = makeServer(NNTP_RFC4643_extension, daemon);
+server.start();
+registerCleanupFunction(() => {
+ server.stop();
+});
+
+/**
+ * Test connection should be closed after canceling the password dialog.
+ */
+add_task(async function cancelPasswordDialog() {
+ // Mock the password prompt.
+ registerAlertTestUtils();
+
+ // Enforce server auth and trigger a list group request.
+ let incomingServer = setupLocalServer(server.port);
+ incomingServer.pushAuth = true;
+ let listener = new PromiseTestUtils.PromiseStreamListener();
+ incomingServer.loadNewsUrl(
+ Services.io.newURI(`news://localhost:${server.port}/*`),
+ null,
+ listener
+ );
+
+ // The request should be aborted.
+ try {
+ await listener.promise;
+ } catch (e) {
+ equal(e, Cr.NS_ERROR_ABORT);
+ }
+
+ // Should send nothing after canceling the password dialog.
+ let transaction = server.playTransaction();
+ do_check_transaction(transaction, ["MODE READER"]);
+});
+
+function promptUsernameAndPasswordPS(
+ aParent,
+ aDialogTitle,
+ aText,
+ aUsername,
+ aPassword,
+ aCheckMsg,
+ aCheckState
+) {
+ // Cancel the password dialog.
+ return false;
+}
diff --git a/comm/mailnews/news/test/unit/test_filter.js b/comm/mailnews/news/test/unit/test_filter.js
new file mode 100644
index 0000000000..9e450499e7
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_filter.js
@@ -0,0 +1,179 @@
+// Tests for the filtering code of NNTP. The same tests are run for each of the
+// different NNTP setups, to test code in a variety of cases.
+//
+// Different suites:
+// * Perfect 3977 compliance (not tested)
+// * Perfect 2980 compliance (XOVER and XHDR work)
+// * Giganews compliance (XHDR doesn't work for practical purposes)
+// * Only 977 compliance (no XOVER support)
+// Basic operations:
+// * Test that the following headers trigger:
+// - Subject
+// - From
+// - Date
+// - Size
+// - Message-ID (header retrievable by XOVER)
+// - User-Agent (header not retrievable by XHDR)
+// * Test all actions
+
+/* import-globals-from ../../../test/resources/filterTestUtils.js */
+load("../../../resources/filterTestUtils.js");
+
+// These are the expected results for testing filter triggers
+var attribResults = {
+ "1@regular.invalid": ["isRead", false],
+ "2@regular.invalid": ["isRead", true],
+ "3@regular.invalid": ["isRead", true],
+ "4@regular.invalid": ["isRead", true],
+ "5@regular.invalid": ["isRead", true],
+ "6.odd@regular.invalid": ["isRead", true],
+ "7@regular.invalid": ["isRead", true],
+ "8.unread@regular.invalid": ["isRead", true],
+};
+function testAttrib(handler, daemon, localserver) {
+ var server = makeServer(handler, daemon);
+ server.setDebugLevel(fsDebugAll);
+ server.start();
+ localserver.port = server.port;
+
+ // Get the folder and force filters to run
+ var folder = localserver.rootFolder.getChildNamed("test.filter");
+ folder.getNewMessages(null, {
+ OnStopRunningUrl() {
+ localserver.closeCachedConnections();
+ },
+ });
+ server.performTest();
+
+ var headers = [...folder.messages];
+
+ try {
+ Assert.equal(headers.length, 8);
+ for (var header of headers) {
+ var id = header.messageId;
+ dump("Testing message " + id + "\n");
+ Assert.equal(header[attribResults[id][0]], attribResults[id][1]);
+ }
+ } catch (e) {
+ print(server.playTransaction().them);
+ throw e;
+ } finally {
+ server.stop();
+ }
+
+ resetFolder(folder);
+}
+
+// These are the results for testing actual actions
+var actionResults = {
+ "1@regular.invalid": ["priority", 6],
+ // "2@regular.invalid" should not be in database
+ "3@regular.invalid": function (header, folder) {
+ var flags = folder.msgDatabase.getThreadContainingMsgHdr(header).flags;
+ var ignored = Ci.nsMsgMessageFlags.Ignored;
+ // This is checking the thread's kill flag
+ return (flags & ignored) == ignored;
+ },
+ "4@regular.invalid": function (header, folder) {
+ var flags = folder.msgDatabase.getThreadContainingMsgHdr(header).flags;
+ var watched = Ci.nsMsgMessageFlags.Watched;
+ // This is checking the thread's watch flag
+ return (flags & watched) == watched;
+ },
+ "5@regular.invalid": ["isFlagged", true],
+ "6.odd@regular.invalid": ["isRead", false],
+ "7@regular.invalid": function (header, folder) {
+ return header.getStringProperty("keywords") == "tag";
+ },
+ "8.unread@regular.invalid": ["isRead", false],
+};
+function testAction(handler, daemon, localserver) {
+ var server = makeServer(handler, daemon);
+ server.start();
+ localserver.port = server.port;
+
+ // Get the folder and force filters to run
+ var folder = localserver.rootFolder.getChildNamed("test.filter");
+ folder.getNewMessages(null, {
+ OnStopRunningUrl() {
+ localserver.closeCachedConnections();
+ },
+ });
+ server.performTest();
+
+ let headers = [...folder.messages];
+
+ try {
+ Assert.equal(headers.length, 7);
+ for (var header of headers) {
+ var id = header.messageId;
+ dump("Testing message " + id + "\n");
+ if (actionResults[id] instanceof Array) {
+ Assert.equal(header[actionResults[id][0]], actionResults[id][1]);
+ } else {
+ Assert.ok(actionResults[id](header, folder));
+ }
+ }
+ } catch (e) {
+ print(server.playTransaction().them);
+ throw e;
+ } finally {
+ server.stop();
+ }
+
+ resetFolder(folder);
+}
+
+// These are the various server handlers
+var handlers = [
+ NNTP_RFC977_handler,
+ NNTP_Giganews_handler,
+ NNTP_RFC2980_handler,
+];
+function run_test() {
+ // Set up the server and add in filters
+ var daemon = setupNNTPDaemon();
+ var localserver = setupLocalServer(NNTP_PORT);
+ var serverFilters = localserver.getFilterList(null);
+
+ createFilter(serverFilters, "subject", "Odd", "read");
+ createFilter(serverFilters, "from", "Odd Person", "read");
+ // A PRTime is the time in μs, but a JS date is time in ms.
+ createFilter(serverFilters, "date", new Date(2000, 0, 1) * 1000, "read");
+ createFilter(serverFilters, "size", 2, "read");
+ createFilter(serverFilters, "message-id", "odd", "read");
+ createFilter(serverFilters, "user-agent", "Odd/1.0", "read");
+ createFilter(serverFilters, "message-id", "8.unread", "read");
+ localserver.setFilterList(serverFilters);
+
+ handlers.forEach(function (handler) {
+ testAttrib(handler, daemon, localserver);
+ });
+
+ // Now we test folder-filters... and actions
+ // Clear out the server filters
+ while (serverFilters.filterCount > 0) {
+ serverFilters.removeFilterAt(0);
+ }
+ localserver.setFilterList(serverFilters);
+
+ var folder = localserver.rootFolder.getChildNamed("test.filter");
+ var folderFilters = folder.getFilterList(null);
+ createFilter(folderFilters, "subject", "First", "priority");
+ createFilter(folderFilters, "subject", "Odd", "delete");
+ createFilter(folderFilters, "from", "Odd Person", "kill");
+ createFilter(folderFilters, "date", new Date(2000, 0, 1) * 1000, "watch");
+ createFilter(folderFilters, "size", 2, "flag");
+ createFilter(folderFilters, "message-id", "odd", "stop");
+ // This shouldn't be hit, because of the previous filter
+ createFilter(folderFilters, "message-id", "6.odd", "read");
+ createFilter(folderFilters, "user-agent", "Odd/1.0", "tag");
+ createFilter(folderFilters, "message-id", "8.unread", "read");
+ createFilter(folderFilters, "message-id", "8.unread", "unread");
+ folderFilters.loggingEnabled = true;
+ folder.setFilterList(folderFilters);
+
+ handlers.forEach(function (handler) {
+ testAction(handler, daemon, localserver);
+ });
+}
diff --git a/comm/mailnews/news/test/unit/test_getNewsMessage.js b/comm/mailnews/news/test/unit/test_getNewsMessage.js
new file mode 100644
index 0000000000..94fa82aece
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_getNewsMessage.js
@@ -0,0 +1,101 @@
+/* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Tests:
+ * - getNewMessages for a newsgroup folder (single message).
+ * - loadMessage for a newsgroup message
+ * - Downloading a single message and checking content in stream is correct.
+ */
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+// The basic daemon to use for testing Nntpd.jsm implementations
+var daemon = setupNNTPDaemon();
+
+var server;
+var localserver;
+
+var streamListener = {
+ _data: "",
+
+ QueryInterface: ChromeUtils.generateQI([
+ "nsIStreamListener",
+ "nsIRequestObserver",
+ ]),
+
+ // nsIRequestObserver
+ onStartRequest(aRequest) {},
+ onStopRequest(aRequest, aStatusCode) {
+ Assert.equal(aStatusCode, 0);
+
+ // Reduce any \r\n to just \n so we can do a good comparison on any
+ // platform.
+ var reduced = this._data.replace(/\r\n/g, "\n");
+ Assert.equal(reduced, kSimpleNewsArticle);
+
+ // We must finish closing connections and tidying up after a timeout
+ // so that the thread has time to unwrap itself.
+ do_timeout(0, doTestFinished);
+ },
+
+ // nsIStreamListener
+ onDataAvailable(aRequest, aInputStream, aOffset, aCount) {
+ let scriptStream = Cc[
+ "@mozilla.org/scriptableinputstream;1"
+ ].createInstance(Ci.nsIScriptableInputStream);
+
+ scriptStream.init(aInputStream);
+
+ this._data += scriptStream.read(aCount);
+ },
+};
+
+function doTestFinished() {
+ localserver.closeCachedConnections();
+
+ server.stop();
+
+ var thread = gThreadManager.currentThread;
+ while (thread.hasPendingEvents()) {
+ thread.processNextEvent(true);
+ }
+
+ do_test_finished();
+}
+
+function run_test() {
+ server = makeServer(NNTP_RFC977_handler, daemon);
+ server.start();
+ localserver = setupLocalServer(server.port);
+
+ try {
+ // Get the folder and new mail
+ var folder = localserver.rootFolder.getChildNamed("test.subscribe.simple");
+ folder.clearFlag(Ci.nsMsgFolderFlags.Offline);
+ folder.getNewMessages(null, {
+ OnStopRunningUrl() {
+ localserver.closeCachedConnections();
+ },
+ });
+ server.performTest();
+
+ Assert.equal(folder.getTotalMessages(false), 1);
+ Assert.ok(folder.hasNewMessages);
+
+ server.resetTest();
+
+ var message = folder.firstNewMessage;
+
+ var messageUri = folder.getUriForMsg(message);
+
+ do_test_pending();
+
+ Cc["@mozilla.org/messenger/messageservice;1?type=news"]
+ .getService(Ci.nsIMsgMessageService)
+ .loadMessage(messageUri, streamListener, null, null, false);
+ } catch (e) {
+ server.stop();
+ do_throw(e);
+ }
+}
diff --git a/comm/mailnews/news/test/unit/test_internalUris.js b/comm/mailnews/news/test/unit/test_internalUris.js
new file mode 100644
index 0000000000..4be0402f0e
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_internalUris.js
@@ -0,0 +1,305 @@
+/* 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 internal URIs generated by various methods in the code base.
+ * If you manually generate a news URI somewhere, please add it to this test.
+ */
+
+Cu.importGlobalProperties(["crypto"]);
+
+/* import-globals-from ../../../test/resources/alertTestUtils.js */
+load("../../../resources/alertTestUtils.js");
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+var { PromiseTestUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/PromiseTestUtils.jsm"
+);
+var { PromiseUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/PromiseUtils.sys.mjs"
+);
+
+var daemon, localserver, server;
+
+var kCancelArticle =
+ "From: fake@acme.invalid\n" +
+ "Newsgroups: test.filter\n" +
+ "Subject: cancel <4@regular.invalid>\n" +
+ "References: <4@regular.invalid>\n" +
+ "Control: cancel <4@regular.invalid>\n" +
+ "MIME-Version: 1.0\n" +
+ "Content-Type: text/plain\n" +
+ "\n" +
+ "This message was cancelled from within ";
+
+var dummyMsgWindow;
+
+add_setup(function setupTest() {
+ registerAlertTestUtils();
+
+ daemon = setupNNTPDaemon();
+ server = makeServer(NNTP_RFC2980_handler, daemon);
+ server.start();
+ localserver = setupLocalServer(server.port);
+
+ // Set up an identity for posting.
+ let identity = MailServices.accounts.createIdentity();
+ identity.fullName = "Normal Person";
+ identity.email = "fake@acme.invalid";
+ MailServices.accounts.FindAccountForServer(localserver).addIdentity(identity);
+
+ dummyMsgWindow = new DummyMsgWindow();
+});
+
+add_task(async function test_newMsgs() {
+ // This tests nsMsgNewsFolder::GetNewsMessages via getNewMessages.
+ let folder = localserver.rootFolder.getChildNamed("test.filter");
+ Assert.equal(folder.getTotalMessages(false), 0);
+ let urlListener = new PromiseTestUtils.PromiseUrlListener();
+ folder.getNewMessages(null, urlListener);
+ await urlListener.promise;
+ Assert.equal(folder.getTotalMessages(false), 8);
+});
+
+add_task(async function test_cancel() {
+ // This tests nsMsgNewsFolder::CancelMessage.
+ let folder = localserver.rootFolder.getChildNamed("test.filter");
+ let db = folder.msgDatabase;
+ let hdr = db.getMsgHdrForKey(4);
+
+ folder.QueryInterface(Ci.nsIMsgNewsFolder).cancelMessage(hdr, dummyMsgWindow);
+ await dummyMsgWindow.promise;
+
+ // Reset promise state.
+ dummyMsgWindow.deferPromise();
+
+ Assert.equal(folder.getTotalMessages(false), 7);
+
+ // Check the content of the CancelMessage itself.
+ let article = daemon.getGroup("test.filter")[9];
+ // Since the cancel message includes the brand name (Daily, Thunderbird), we
+ // only check the beginning of the string.
+ Assert.ok(article.fullText.startsWith(kCancelArticle));
+});
+
+function generateLongArticle() {
+ // After converting to base64, the message body will be 65536 * 4 = 256KB.
+ let arr = new Uint8Array(65536);
+ crypto.getRandomValues(arr);
+ return `Date: Mon, 23 Jun 2008 19:58:07 +0400
+From: Normal Person <fake@acme.invalid>
+MIME-Version: 1.0
+Subject: Odd Subject
+Content-Type: text/plain; charset=ISO-8859-1; format=flowed
+Content-Transfer-Encoding: 7bit
+Message-ID: <2@regular.invalid>
+
+${btoa(arr)}
+${btoa(arr)}
+${btoa(arr)}
+`;
+}
+
+add_task(async function test_fetchMessage() {
+ // Replace the second article with a large message.
+ daemon.addArticleToGroup(
+ new NewsArticle(generateLongArticle()),
+ "test.filter",
+ 2
+ );
+
+ // Tests nsNntpService::CreateMessageIDURL via FetchMessage.
+ let streamListener = new PromiseTestUtils.PromiseStreamListener();
+ let urlListener = new PromiseTestUtils.PromiseUrlListener();
+ let folder = localserver.rootFolder.getChildNamed("test.filter");
+ MailServices.nntp.fetchMessage(folder, 2, null, streamListener, urlListener);
+ await urlListener.promise;
+ let data = await streamListener.promise;
+ // To point out that the streamListener Promise shouldn't reject.
+ Assert.ok(data);
+});
+
+add_task(async function test_fetchMessageNoStreamListener() {
+ // Tests nsNntpService::CreateMessageIDURL via FetchMessage.
+ let streamListener = null;
+ let urlListener = new PromiseTestUtils.PromiseUrlListener();
+ let folder = localserver.rootFolder.getChildNamed("test.filter");
+ MailServices.nntp.fetchMessage(folder, 2, null, streamListener, urlListener);
+ await urlListener.promise;
+});
+
+add_task(async function test_search() {
+ // This tests nsNntpService::Search.
+ let folder = localserver.rootFolder.getChildNamed("test.filter");
+ var searchSession = Cc[
+ "@mozilla.org/messenger/searchSession;1"
+ ].createInstance(Ci.nsIMsgSearchSession);
+ searchSession.addScopeTerm(Ci.nsMsgSearchScope.news, folder);
+
+ let searchTerm = searchSession.createTerm();
+ searchTerm.attrib = Ci.nsMsgSearchAttrib.Subject;
+ let value = searchTerm.value;
+ value.str = "First";
+ searchTerm.value = value;
+ searchTerm.op = Ci.nsMsgSearchOp.Contains;
+ searchTerm.booleanAnd = false;
+ searchSession.appendTerm(searchTerm);
+
+ let hitCount;
+ let searchListener = new PromiseTestUtils.PromiseSearchNotify(searchSession, {
+ onSearchHit() {
+ hitCount++;
+ },
+ onNewSearch() {
+ hitCount = 0;
+ },
+ });
+
+ searchSession.search(null);
+ await searchListener.promise;
+
+ Assert.equal(hitCount, 1);
+});
+
+add_task(async function test_grouplist() {
+ // This tests nsNntpService::GetListOfGroupsOnServer.
+ let subserver = localserver.QueryInterface(Ci.nsISubscribableServer);
+ let subscribablePromise = PromiseUtils.defer();
+ let subscribeListener = {
+ OnDonePopulating() {
+ subscribablePromise.resolve();
+ },
+ };
+ subserver.subscribeListener = subscribeListener;
+
+ function enumGroups(rootUri) {
+ let hierarchy = subserver.getChildURIs(rootUri);
+ let groups = [];
+ for (let name of hierarchy) {
+ if (subserver.isSubscribable(name)) {
+ groups.push(name);
+ }
+ if (subserver.hasChildren(name)) {
+ groups = groups.concat(enumGroups(name));
+ }
+ }
+ return groups;
+ }
+
+ MailServices.nntp.getListOfGroupsOnServer(localserver, null, false);
+ await subscribablePromise.promise;
+
+ let groups = enumGroups("");
+ Assert.equal(groups.length, Object.keys(daemon._groups).length);
+ for (let group in daemon._groups) {
+ Assert.ok(groups.includes(group));
+ }
+
+ // First node in the group list, even though it is not subscribable,
+ // parent of "test.empty" group.
+ Assert.equal(subserver.getFirstChildURI(""), "test");
+
+ // Release reference, somehow impedes GC of 'subserver'.
+ subserver.subscribeListener = null;
+});
+
+add_task(async function test_postMessage() {
+ // This tests nsNntpService::SetUpNntpUrlForPosting via PostMessage.
+ let urlListener = new PromiseTestUtils.PromiseUrlListener();
+ MailServices.nntp.postMessage(
+ do_get_file("postings/post2.eml"),
+ "misc.test",
+ localserver.key,
+ urlListener,
+ null
+ );
+ await urlListener.promise;
+ Assert.equal(daemon.getGroup("misc.test").keys.length, 1);
+});
+
+// Not tested because it requires UI, and this is insufficient, I think.
+// function test_forwardInline() {
+// // This tests mime_parse_stream_complete via forwarding inline
+// let folder = localserver.rootFolder.getChildNamed("test.filter");
+// let hdr = folder.msgDatabase.getMsgHdrForKey(1);
+// MailServices.compose.forwardMessage("a@b.invalid", hdr, null,
+// localserver, Ci.nsIMsgComposeService.kForwardInline);
+// }
+
+add_task(async function test_escapedName() {
+ // This does a few tests to make sure our internal URIs work for newsgroups
+ // with names that need escaping.
+ let evilName = "test.malformed&name";
+ daemon.addGroup(evilName);
+ daemon.addArticle(make_article(do_get_file("postings/bug670935.eml")));
+ localserver.subscribeToNewsgroup(evilName);
+
+ // Can we access it?
+ let folder = localserver.rootFolder.getChildNamed(evilName);
+ let newMessageUrlListener = new PromiseTestUtils.PromiseUrlListener();
+ folder.getNewMessages(null, newMessageUrlListener);
+ await newMessageUrlListener.promise;
+
+ // If we get here, we didn't crash--newsgroups unescape properly.
+ // Load a message, to test news-message: URI unescaping.
+ let streamlistener = new PromiseTestUtils.PromiseStreamListener();
+ let fetchMessageUrlListener = new PromiseTestUtils.PromiseUrlListener();
+ MailServices.nntp.fetchMessage(
+ folder,
+ 1,
+ null,
+ streamlistener,
+ fetchMessageUrlListener
+ );
+ await fetchMessageUrlListener.promise;
+ let data = await streamlistener.promise;
+ // To point out that the streamListener Promise shouldn't reject.
+ Assert.ok(data);
+});
+
+add_task(function cleanUp() {
+ localserver.closeCachedConnections();
+});
+
+class DummyMsgWindow {
+ QueryInterface = ChromeUtils.generateQI([
+ "nsIMsgWindow",
+ "nsISupportsWeakReference",
+ ]);
+
+ constructor() {
+ this._deferredPromise = PromiseUtils.defer();
+ }
+
+ get statusFeedback() {
+ let scopedThis = this;
+ return {
+ startMeteors() {},
+ stopMeteors() {
+ scopedThis._deferredPromise.resolve(true);
+ },
+ showProgress() {},
+ };
+ }
+
+ get promptDialog() {
+ return alertUtilsPrompts;
+ }
+
+ deferPromise() {
+ this._deferredPromise = PromiseUtils.defer();
+ }
+
+ get promise() {
+ return this._deferredPromise.promise;
+ }
+}
+
+/* exported alert, confirmEx */
+// Prompts for cancel.
+function alertPS(parent, title, text) {}
+function confirmExPS(parent, title, text, flags) {
+ return 0;
+}
diff --git a/comm/mailnews/news/test/unit/test_newsAutocomplete.js b/comm/mailnews/news/test/unit/test_newsAutocomplete.js
new file mode 100644
index 0000000000..29fecb3d9d
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_newsAutocomplete.js
@@ -0,0 +1,107 @@
+/* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ *
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+function acObserver() {}
+
+acObserver.prototype = {
+ _search: null,
+ _result: null,
+
+ onSearchResult(aSearch, aResult) {
+ this._search = aSearch;
+ this._result = aResult;
+ },
+};
+
+function run_test() {
+ setupLocalServer(119);
+
+ // create identity
+ let identity = MailServices.accounts.createIdentity();
+ _account.addIdentity(identity);
+
+ let acs = Cc["@mozilla.org/autocomplete/search;1?name=news"].getService(
+ Ci.nsIAutoCompleteSearch
+ );
+ let obs;
+
+ let paramsN = JSON.stringify({
+ idKey: identity.key,
+ accountKey: _account.key,
+ type: "addr_newsgroups",
+ });
+ let paramsF = JSON.stringify({
+ idKey: identity.key,
+ accountKey: _account.key,
+ type: "addr_followup",
+ });
+ let paramsMail = JSON.stringify({
+ idKey: identity.key,
+ accountKey: _account.key,
+ type: "addr_to",
+ });
+
+ // misc.test is not subscribed
+ obs = new acObserver();
+ acs.startSearch("misc", paramsN, null, obs);
+ Assert.ok(obs._result == null || obs._result.matchCount == 0);
+
+ obs = new acObserver();
+ acs.startSearch("misc", paramsF, null, obs);
+ Assert.ok(obs._result == null || obs._result.matchCount == 0);
+
+ obs = new acObserver();
+ acs.startSearch("misc", paramsMail, null, obs);
+ Assert.ok(obs._result == null || obs._result.matchCount == 0);
+
+ // test.filter is subscribed
+ obs = new acObserver();
+ acs.startSearch("filter", paramsN, null, obs);
+ Assert.equal(obs._result.matchCount, 1);
+
+ obs = new acObserver();
+ acs.startSearch("filter", paramsF, null, obs);
+ Assert.equal(obs._result.matchCount, 1);
+
+ // ... but no auto-complete should occur for addr_to
+ obs = new acObserver();
+ acs.startSearch("filter", paramsMail, null, obs);
+ Assert.ok(obs._result == null || obs._result.matchCount == 0);
+
+ // test.subscribe.empty and test.subscribe.simple are subscribed
+ obs = new acObserver();
+ acs.startSearch("subscribe", paramsN, null, obs);
+ Assert.equal(obs._result.matchCount, 2);
+
+ obs = new acObserver();
+ acs.startSearch("subscribe", paramsF, null, obs);
+ Assert.equal(obs._result.matchCount, 2);
+
+ // ... but no auto-complete should occur for addr_to
+ obs = new acObserver();
+ acs.startSearch("subscribe", paramsMail, null, obs);
+ Assert.ok(obs._result == null || obs._result.matchCount == 0);
+
+ // test.subscribe.empty is subscribed, test.empty is not
+ obs = new acObserver();
+ acs.startSearch("empty", paramsN, null, obs);
+ Assert.equal(obs._result.matchCount, 1);
+
+ obs = new acObserver();
+ acs.startSearch("empty", paramsF, null, obs);
+ Assert.equal(obs._result.matchCount, 1);
+
+ let thread = gThreadManager.currentThread;
+ while (thread.hasPendingEvents()) {
+ thread.processNextEvent(true);
+ }
+}
diff --git a/comm/mailnews/news/test/unit/test_nntpContentLength.js b/comm/mailnews/news/test/unit/test_nntpContentLength.js
new file mode 100644
index 0000000000..f9f780011d
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_nntpContentLength.js
@@ -0,0 +1,80 @@
+/* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ *
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Test content length for the news protocol. This focuses on necko URLs
+ * that are run externally.
+ */
+
+// The basic daemon to use for testing Nntpd.jsm implementations
+var daemon = setupNNTPDaemon();
+
+var server;
+var localserver;
+
+function run_test() {
+ server = makeServer(NNTP_RFC977_handler, daemon);
+ server.start();
+ localserver = setupLocalServer(server.port);
+
+ try {
+ // Get the folder and new mail
+ let folder = localserver.rootFolder.getChildNamed("test.subscribe.simple");
+ folder.clearFlag(Ci.nsMsgFolderFlags.Offline);
+ folder.getNewMessages(null, {
+ OnStopRunningUrl() {
+ localserver.closeCachedConnections();
+ },
+ });
+ server.performTest();
+
+ Assert.equal(folder.getTotalMessages(false), 1);
+ Assert.ok(folder.hasNewMessages);
+
+ server.resetTest();
+
+ // Get the message URI
+ let msgHdr = folder.firstNewMessage;
+ let messageUri = folder.getUriForMsg(msgHdr);
+ // Convert this to a URI that necko can run
+ let messageService = MailServices.messageServiceFromURI(messageUri);
+ let neckoURL = messageService.getUrlForUri(messageUri);
+ // Don't use the necko URL directly. Instead, get the spec and create a new
+ // URL using the IO service
+ let urlToRun = Services.io.newURI(neckoURL.spec);
+
+ // Get a channel from this URI, and check its content length
+ let channel = Services.io.newChannelFromURI(
+ urlToRun,
+ null,
+ Services.scriptSecurityManager.getSystemPrincipal(),
+ null,
+ Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
+ Ci.nsIContentPolicy.TYPE_OTHER
+ );
+ Assert.equal(channel.contentLength, kSimpleNewsArticle.length);
+
+ // Now try an attachment. &part=1.2
+ // XXX the message doesn't really have an attachment
+ let attachmentURL = Services.io.newURI(neckoURL.spec + "&part=1.2");
+ Services.io.newChannelFromURI(
+ attachmentURL,
+ null,
+ Services.scriptSecurityManager.getSystemPrincipal(),
+ null,
+ Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
+ Ci.nsIContentPolicy.TYPE_OTHER
+ );
+ // Currently attachments have their content length set to the length of the
+ // entire message
+ Assert.equal(channel.contentLength, kSimpleNewsArticle.length);
+ } catch (e) {
+ server.stop();
+ do_throw(e);
+ }
+}
diff --git a/comm/mailnews/news/test/unit/test_nntpGroupPassword.js b/comm/mailnews/news/test/unit/test_nntpGroupPassword.js
new file mode 100644
index 0000000000..6bf9be53cc
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_nntpGroupPassword.js
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/**
+ * Authentication tests for NNTP (based on RFC4643).
+ */
+
+// The basic daemon to use for testing Nntpd.jsm implementations
+var daemon = setupNNTPDaemon();
+
+add_task(async function () {
+ await Services.logins.initializationPromise;
+
+ daemon.groupCredentials = {
+ "test.subscribe.empty": ["group1", "pass1"],
+ "test.filter": ["group2", "pass2"],
+ };
+
+ var server = makeServer(NNTP_RFC4643_extension, daemon);
+ server.start();
+ var localserver = setupLocalServer(server.port);
+ localserver.singleSignon = false;
+
+ // Add passwords to the manager
+ var serverURI = "news://localhost/";
+ var loginInfo1 = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(
+ Ci.nsILoginInfo
+ );
+ loginInfo1.init(
+ serverURI + "test.subscribe.empty",
+ null,
+ serverURI + "test.subscribe.empty",
+ "group1",
+ "pass1",
+ "",
+ ""
+ );
+ Services.logins.addLogin(loginInfo1);
+ var loginInfo2 = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(
+ Ci.nsILoginInfo
+ );
+ loginInfo2.init(
+ serverURI + "test.filter",
+ null,
+ serverURI + "test.filter",
+ "group2",
+ "pass2",
+ "",
+ ""
+ );
+ Services.logins.addLogin(loginInfo2);
+ try {
+ var prefix = "news://localhost:" + server.port + "/";
+ var transaction;
+
+ test = "per-group password part 1";
+ setupProtocolTest(
+ server.port,
+ prefix + "test.subscribe.empty",
+ localserver
+ );
+ server.performTest();
+ transaction = server.playTransaction();
+ do_check_transaction(transaction, [
+ "MODE READER",
+ "GROUP test.subscribe.empty",
+ "AUTHINFO user group1",
+ "AUTHINFO pass pass1",
+ "GROUP test.subscribe.empty",
+ ]);
+
+ test = "per-group password part 2";
+ server.resetTest();
+ setupProtocolTest(server.port, prefix + "test.filter", localserver);
+ server.performTest();
+ transaction = server.playTransaction();
+ do_check_transaction(transaction, [
+ "MODE READER",
+ "GROUP test.filter",
+ "AUTHINFO user group2",
+ "AUTHINFO pass pass2",
+ "GROUP test.filter",
+ "XOVER 1-8",
+ ]);
+ } catch (e) {
+ dump("NNTP Protocol test " + test + " failed for type RFC 977:\n");
+ try {
+ var trans = server.playTransaction();
+ if (trans) {
+ dump("Commands called: " + uneval(trans) + "\n");
+ }
+ } catch (exp) {}
+ do_throw(e);
+ }
+ server.stop();
+
+ var thread = gThreadManager.currentThread;
+ while (thread.hasPendingEvents()) {
+ thread.processNextEvent(true);
+ }
+});
diff --git a/comm/mailnews/news/test/unit/test_nntpPassword.js b/comm/mailnews/news/test/unit/test_nntpPassword.js
new file mode 100644
index 0000000000..dbccf01f74
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_nntpPassword.js
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/**
+ * Authentication tests for NNTP (based on RFC4643).
+ *
+ * Note: Logins for newsgroup servers for 1.8 were stored with either the
+ * default port or the SSL default port. Nothing else!
+ */
+
+/* import-globals-from ../../../test/resources/passwordStorage.js */
+load("../../../resources/passwordStorage.js");
+
+// The basic daemon to use for testing Nntpd.jsm implementations
+var daemon = setupNNTPDaemon();
+
+add_task(async function () {
+ // Prepare files for passwords (generated by a script in bug 1018624).
+ await setupForPassword("signons-mailnews1.8.json");
+
+ var server = makeServer(NNTP_RFC4643_extension, daemon);
+ server.start();
+
+ try {
+ var prefix = "news://localhost:" + server.port + "/";
+ var transaction;
+
+ // Test - group subscribe listing
+ test = "news:*";
+ setupProtocolTest(server.port, prefix + "*");
+ server.performTest();
+ transaction = server.playTransaction();
+ do_check_transaction(transaction, [
+ "MODE READER",
+ "LIST",
+ "AUTHINFO user testnews",
+ "AUTHINFO pass newstest",
+ "LIST",
+ ]);
+ } catch (e) {
+ dump("NNTP Protocol test " + test + " failed for type RFC 977:\n");
+ try {
+ var trans = server.playTransaction();
+ if (trans) {
+ dump("Commands called: " + trans.them + "\n");
+ }
+ } catch (exp) {}
+ do_throw(e);
+ }
+ server.stop();
+
+ var thread = gThreadManager.currentThread;
+ while (thread.hasPendingEvents()) {
+ thread.processNextEvent(true);
+ }
+});
diff --git a/comm/mailnews/news/test/unit/test_nntpPassword2.js b/comm/mailnews/news/test/unit/test_nntpPassword2.js
new file mode 100644
index 0000000000..8fcf7d7e0b
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_nntpPassword2.js
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/**
+ * Authentication tests for NNTP (based on RFC4643) - checks for servers whose
+ * details have changed (e.g. realhostname is different from hostname).
+ *
+ * Note: Logins for newsgroup servers for 1.8 were stored with either the
+ * default port or the SSL default port. Nothing else!
+ */
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+/* import-globals-from ../../../test/resources/passwordStorage.js */
+load("../../../resources/passwordStorage.js");
+
+// The basic daemon to use for testing Nntpd.jsm implementations
+var daemon = setupNNTPDaemon();
+
+add_task(async function () {
+ let server = makeServer(NNTP_RFC4643_extension, daemon);
+ server.start();
+
+ // These preferences set up a local news server that has had its hostname
+ // and username changed from the original settings. We can't do this by
+ // function calls for this test as they would cause the password to be
+ // forgotten when changing the hostname/username and this breaks the test.
+ Services.prefs.setCharPref("mail.account.account1.server", "server1");
+ Services.prefs.setCharPref("mail.account.account2.server", "server2");
+ Services.prefs.setCharPref("mail.account.account2.identities", "id1");
+ Services.prefs.setCharPref(
+ "mail.accountmanager.accounts",
+ "account1,account2"
+ );
+ Services.prefs.setCharPref(
+ "mail.accountmanager.localfoldersserver",
+ "server1"
+ );
+ Services.prefs.setCharPref("mail.accountmanager.defaultaccount", "account2");
+ Services.prefs.setCharPref("mail.identity.id1.fullName", "testnntp");
+ Services.prefs.setCharPref(
+ "mail.identity.id1.useremail",
+ "testnntp@localhost"
+ );
+ Services.prefs.setBoolPref("mail.identity.id1.valid", true);
+ Services.prefs.setCharPref("mail.server.server1.hostname", "Local Folders");
+ Services.prefs.setCharPref("mail.server.server1.name", "Local Folders");
+ Services.prefs.setCharPref("mail.server.server1.type", "none");
+ Services.prefs.setCharPref("mail.server.server1.userName", "nobody");
+ Services.prefs.setCharPref("mail.server.server2.hostname", "invalid");
+ Services.prefs.setCharPref(
+ "mail.server.server2.name",
+ "testnntp on localhost"
+ );
+ Services.prefs.setIntPref("mail.server.server2.port", server.port);
+ Services.prefs.setCharPref("mail.server.server2.realhostname", "localhost");
+ Services.prefs.setCharPref("mail.server.server2.type", "nntp");
+
+ // Prepare files for passwords (generated by a script in bug 1018624).
+ await setupForPassword("signons-mailnews1.8-alt.json");
+
+ try {
+ // Note, the uri is for hostname "invalid" which is the original uri. See
+ // setupProtocolTest parameters.
+ var prefix = "news://invalid:" + server.port + "/";
+
+ // Test - group subscribe listing
+ test = "news:*";
+
+ // Get the existing incoming server
+ MailServices.accounts.loadAccounts();
+
+ // Create the incoming server with "original" details.
+ var incomingServer = MailServices.accounts.getIncomingServer("server2");
+
+ subscribeServer(incomingServer);
+
+ // Now set up and run the tests
+ setupProtocolTest(server.port, prefix + "*", incomingServer);
+ server.performTest();
+ var transaction = server.playTransaction();
+ do_check_transaction(transaction, [
+ "MODE READER",
+ "LIST",
+ "AUTHINFO user testnews",
+ "AUTHINFO pass newstest",
+ "LIST",
+ ]);
+ incomingServer.QueryInterface(Ci.nsISubscribableServer).subscribeCleanup();
+ } catch (e) {
+ dump("NNTP Protocol test " + test + " failed for type RFC 977:\n");
+ try {
+ var trans = server.playTransaction();
+ if (trans) {
+ dump("Commands called: " + trans.them + "\n");
+ }
+ } catch (exp) {}
+ do_throw(e);
+ }
+ server.stop();
+
+ var thread = gThreadManager.currentThread;
+ while (thread.hasPendingEvents()) {
+ thread.processNextEvent(true);
+ }
+});
diff --git a/comm/mailnews/news/test/unit/test_nntpPassword3.js b/comm/mailnews/news/test/unit/test_nntpPassword3.js
new file mode 100644
index 0000000000..a4c5e0ac76
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_nntpPassword3.js
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/**
+ * Extra tests for forgetting newsgroup usernames and passwords.
+ */
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+/* import-globals-from ../../../test/resources/passwordStorage.js */
+load("../../../resources/passwordStorage.js");
+
+var kUsername = "testnews";
+var kPassword = "newstest";
+var kProtocol = "nntp";
+var kHostname = "localhost";
+var kServerUrl = "news://" + kHostname;
+
+add_task(async function () {
+ // Prepare files for passwords (generated by a script in bug 1018624).
+ await setupForPassword("signons-mailnews1.8.json");
+
+ // Set up the basic accounts and folders.
+ localAccountUtils.loadLocalMailAccount();
+
+ var incomingServer = MailServices.accounts.createIncomingServer(
+ null,
+ kHostname,
+ kProtocol
+ );
+
+ // Test - Check there is a password to begin with...
+ var logins = Services.logins.findLogins(kServerUrl, null, kServerUrl);
+
+ Assert.equal(logins.length, 1);
+ Assert.equal(logins[0].username, kUsername);
+ Assert.equal(logins[0].password, kPassword);
+
+ // Test - Remove the news password login via the incoming server
+ incomingServer.forgetPassword();
+
+ logins = Services.logins.findLogins(kServerUrl, null, kServerUrl);
+
+ // should be no passwords left...
+ Assert.equal(logins.length, 0);
+});
diff --git a/comm/mailnews/news/test/unit/test_nntpPasswordFailure.js b/comm/mailnews/news/test/unit/test_nntpPasswordFailure.js
new file mode 100644
index 0000000000..994a701c8e
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_nntpPasswordFailure.js
@@ -0,0 +1,196 @@
+/* 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/. */
+
+/**
+ * This test checks to see if the nntp password failure is handled correctly.
+ * The steps are:
+ * - Have an invalid password in the password database.
+ * - Check we get a prompt asking what to do.
+ * - Check retry does what it should do.
+ * - Check cancel does what it should do.
+ * - Re-initiate connection, this time select enter new password, check that
+ * we get a new password prompt and can enter the password.
+ */
+
+var { mailTestUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/MailTestUtils.jsm"
+);
+var { PromiseTestUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/PromiseTestUtils.jsm"
+);
+
+/* import-globals-from ../../../test/resources/alertTestUtils.js */
+/* import-globals-from ../../../test/resources/passwordStorage.js */
+load("../../../resources/alertTestUtils.js");
+load("../../../resources/passwordStorage.js");
+
+var server;
+var daemon;
+var incomingServer;
+var folder;
+var attempt = 0;
+var logins;
+
+var kUserName = "testnews";
+var kInvalidPassword = "newstest";
+var kValidPassword = "notallama";
+
+add_setup(function () {
+ // Disable new mail notifications
+ Services.prefs.setBoolPref("mail.biff.play_sound", false);
+ Services.prefs.setBoolPref("mail.biff.show_alert", false);
+ Services.prefs.setBoolPref("mail.biff.show_tray_icon", false);
+ Services.prefs.setBoolPref("mail.biff.animate_dock_icon", false);
+ Services.prefs.setBoolPref("signon.debug", true);
+
+ // Prepare files for passwords (generated by a script in bug 1018624).
+ setupForPassword("signons-mailnews1.8.json");
+
+ registerAlertTestUtils();
+
+ // Set up the server
+ daemon = setupNNTPDaemon();
+ function createHandler(d) {
+ var handler = new NNTP_RFC4643_extension(d);
+ handler.expectedPassword = kValidPassword;
+ return handler;
+ }
+ server = new nsMailServer(createHandler, daemon);
+ server.start();
+ incomingServer = setupLocalServer(server.port);
+ folder = incomingServer.rootFolder.getChildNamed("test.subscribe.simple");
+
+ // Check that we haven't got any messages in the folder, if we have its a test
+ // setup issue.
+ Assert.equal(folder.getTotalMessages(false), 0);
+});
+
+add_task(async function getMail1() {
+ // Now get mail.
+ let urlListener = new PromiseTestUtils.PromiseUrlListener({
+ OnStopRunningUrl(url, result) {
+ // On the last attempt, we should have successfully got one mail.
+ Assert.equal(folder.getTotalMessages(false), attempt == 4 ? 1 : 0);
+
+ // If we've just cancelled, expect failure rather than success
+ // because the server dropped the connection.
+ dump("in onStopRunning, result = " + result + "\n");
+ // do_check_eq(result, attempt == 2 ? Cr.NS_ERROR_FAILURE : 0);
+ },
+ });
+ folder.getNewMessages(gDummyMsgWindow, urlListener);
+ await urlListener.promise;
+
+ Assert.equal(attempt, 2);
+
+ // Check that we haven't forgotten the login even though we've retried and cancelled.
+ logins = Services.logins.findLogins(
+ "news://localhost",
+ null,
+ "news://localhost"
+ );
+
+ Assert.equal(logins.length, 1);
+ Assert.equal(logins[0].username, kUserName);
+ Assert.equal(logins[0].password, kInvalidPassword);
+
+ server.resetTest();
+});
+
+add_task(async function getMail2() {
+ let urlListener = new PromiseTestUtils.PromiseUrlListener({
+ OnStopRunningUrl(url, result) {
+ // On the last attempt, we should have successfully got one mail.
+ Assert.equal(folder.getTotalMessages(false), attempt == 4 ? 1 : 0);
+
+ // If we've just cancelled, expect failure rather than success
+ // because the server dropped the connection.
+ dump("in onStopRunning, result = " + result + "\n");
+ // do_check_eq(result, attempt == 2 ? Cr.NS_ERROR_FAILURE : 0);
+ },
+ });
+ folder.getNewMessages(gDummyMsgWindow, urlListener);
+ await urlListener.promise;
+ // Now check the new one has been saved.
+ logins = Services.logins.findLogins(
+ "news://localhost",
+ null,
+ "news://localhost"
+ );
+
+ Assert.equal(logins.length, 1);
+ Assert.equal(logins[0].username, kUserName);
+ Assert.equal(logins[0].password, kValidPassword);
+});
+
+add_task(function endTest() {
+ // Clean up nicely the test.
+ server.stop();
+
+ var thread = gThreadManager.currentThread;
+ while (thread.hasPendingEvents()) {
+ thread.processNextEvent(true);
+ }
+});
+
+/* exported alert, confirmEx, promptUsernameAndPasswordPS */
+function alertPS(parent, aDialogText, aText) {
+ // The first few attempts may prompt about the password problem, the last
+ // attempt shouldn't.
+ Assert.ok(attempt < 4);
+
+ // Log the fact we've got an alert, but we don't need to test anything here.
+ dump("Alert Title: " + aDialogText + "\nAlert Text: " + aText + "\n");
+}
+
+function confirmExPS(
+ parent,
+ aDialogTitle,
+ aText,
+ aButtonFlags,
+ aButton0Title,
+ aButton1Title,
+ aButton2Title,
+ aCheckMsg,
+ aCheckState
+) {
+ switch (++attempt) {
+ // First attempt, retry.
+ case 1:
+ dump("\nAttempting retry\n");
+ return 0;
+ // Second attempt, cancel.
+ case 2:
+ dump("\nCancelling login attempt\n");
+ return 1;
+ // Third attempt, retry.
+ case 3:
+ dump("\nAttempting Retry\n");
+ return 0;
+ // Fourth attempt, enter a new password.
+ case 4:
+ dump("\nEnter new password\n");
+ return 2;
+ default:
+ throw new Error("unexpected attempt number " + attempt);
+ }
+}
+
+function promptUsernameAndPasswordPS(
+ aParent,
+ aDialogTitle,
+ aText,
+ aUsername,
+ aPassword,
+ aCheckMsg,
+ aCheckState
+) {
+ if (attempt == 4) {
+ aUsername.value = kUserName;
+ aPassword.value = kValidPassword;
+ aCheckState.value = true;
+ return true;
+ }
+ return false;
+}
diff --git a/comm/mailnews/news/test/unit/test_nntpPost.js b/comm/mailnews/news/test/unit/test_nntpPost.js
new file mode 100644
index 0000000000..e49aa81d92
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_nntpPost.js
@@ -0,0 +1,37 @@
+// Tests that the news can correctly post messages
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+var { PromiseTestUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/PromiseTestUtils.jsm"
+);
+
+/**
+ * Test dot is stuffed correctly when posting an article.
+ */
+add_task(async function test_nntpPost() {
+ // Setup test server.
+ let daemon = setupNNTPDaemon();
+ let handler = new NNTP_RFC977_handler(daemon);
+ let server = new nsMailServer(() => handler, daemon);
+ server.start();
+ registerCleanupFunction(() => server.stop());
+
+ // Send post3.eml to the server.
+ let localServer = setupLocalServer(server.port);
+ let testFile = do_get_file("postings/post3.eml");
+ let urlListener = new PromiseTestUtils.PromiseUrlListener();
+ MailServices.nntp.postMessage(
+ testFile,
+ "test.empty",
+ localServer.key,
+ urlListener,
+ null
+ );
+ await urlListener.promise;
+
+ // Because Nntpd.jsm undone the dot-stuffing, handler.post should be the same
+ // as the original post.
+ equal(handler.post, await IOUtils.readUTF8(testFile.path));
+});
diff --git a/comm/mailnews/news/test/unit/test_nntpProtocols.js b/comm/mailnews/news/test/unit/test_nntpProtocols.js
new file mode 100644
index 0000000000..48f13095fd
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_nntpProtocols.js
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Test suite for getting news urls via the protocol handler.
+ */
+
+var defaultProtocolFlags =
+ Ci.nsIProtocolHandler.URI_NORELATIVE |
+ Ci.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE |
+ Ci.nsIProtocolHandler.ALLOWS_PROXY |
+ Ci.nsIProtocolHandler.URI_FORBIDS_AUTOMATIC_DOCUMENT_REPLACEMENT |
+ Ci.nsIProtocolHandler.URI_FORBIDS_COOKIE_ACCESS |
+ Ci.nsIProtocolHandler.ORIGIN_IS_FULL_SPEC;
+
+var protocols = [
+ {
+ protocol: "news",
+ urlSpec: "news://user@localhost/",
+ defaultPort: Ci.nsINntpUrl.DEFAULT_NNTP_PORT,
+ },
+ // XXX News secure protocol not working yet.
+ /* { protocol: "snews",
+ urlSpec: "snews://user@localhost/",
+ defaultPort: Ci.nsINntpUrl.DEFAULT_NNTPS_PORT
+} */
+];
+
+function run_test() {
+ for (var part = 0; part < protocols.length; ++part) {
+ print("protocol: " + protocols[part].protocol);
+
+ var pH = Cc[
+ "@mozilla.org/network/protocol;1?name=" + protocols[part].protocol
+ ].createInstance(Ci.nsIProtocolHandler);
+
+ Assert.equal(pH.scheme, protocols[part].protocol);
+ Assert.equal(
+ Services.io.getDefaultPort(pH.scheme),
+ protocols[part].defaultPort
+ );
+ Assert.equal(Services.io.getProtocolFlags(pH.scheme), defaultProtocolFlags);
+
+ // Whip through some of the ports to check we get the right results.
+ // NEWS allows connecting to any port.
+ for (let i = 0; i < 1024; ++i) {
+ Assert.ok(pH.allowPort(i, ""));
+ }
+
+ // Check we get a URI when we ask for one
+ var uri = Services.io.newURI(protocols[part].urlSpec);
+
+ uri.QueryInterface(Ci.nsINntpUrl);
+
+ Assert.equal(uri.spec, protocols[part].urlSpec);
+ }
+}
diff --git a/comm/mailnews/news/test/unit/test_nntpProxy.js b/comm/mailnews/news/test/unit/test_nntpProxy.js
new file mode 100644
index 0000000000..826a057c9d
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_nntpProxy.js
@@ -0,0 +1,38 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+// Tests that NNTP over a SOCKS proxy works.
+
+const { NetworkTestUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/NetworkTestUtils.jsm"
+);
+const { PromiseTestUtils } = ChromeUtils.import(
+ "resource://testing-common/mailnews/PromiseTestUtils.jsm"
+);
+
+const PORT = 119;
+
+var daemon, localserver, server;
+
+add_setup(async function () {
+ daemon = setupNNTPDaemon();
+ server = makeServer(NNTP_RFC2980_handler, daemon);
+ server.start();
+ NetworkTestUtils.configureProxy("news.tinderbox.invalid", PORT, server.port);
+ localserver = setupLocalServer(PORT, "news.tinderbox.invalid");
+});
+
+add_task(async function findMessages() {
+ // This is a trivial check that makes sure that we actually do some network
+ // traffic without caring about the exact network traffic.
+ let folder = localserver.rootFolder.getChildNamed("test.filter");
+ equal(folder.getTotalMessages(false), 0);
+ let asyncUrlListener = new PromiseTestUtils.PromiseUrlListener();
+ folder.getNewMessages(null, asyncUrlListener);
+ await asyncUrlListener.promise;
+ equal(folder.getTotalMessages(false), 8);
+});
+
+add_task(async function cleanUp() {
+ NetworkTestUtils.shutdownServers();
+ localserver.closeCachedConnections();
+});
diff --git a/comm/mailnews/news/test/unit/test_nntpUrl.js b/comm/mailnews/news/test/unit/test_nntpUrl.js
new file mode 100644
index 0000000000..93c51334bd
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_nntpUrl.js
@@ -0,0 +1,30 @@
+/* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ *
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+function getMessageHeaderFromUrl(aUrl) {
+ let msgUrl = Services.io.newURI(aUrl).QueryInterface(Ci.nsIMsgMessageUrl);
+ return msgUrl.messageHeader;
+}
+
+function run_test() {
+ // This is crash test for Bug 392729
+ try {
+ // msgkey is invalid for news:// protocol
+ getMessageHeaderFromUrl(
+ "news://localhost:119" +
+ "/123@example.invalid?group=test.subscribe.simple&key=abcdefghijk"
+ );
+ Assert.ok(false);
+ } catch (e) {
+ Assert.equal(e.result, Cr.NS_ERROR_MALFORMED_URI);
+ }
+}
diff --git a/comm/mailnews/news/test/unit/test_server.js b/comm/mailnews/news/test/unit/test_server.js
new file mode 100644
index 0000000000..f0954add1c
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_server.js
@@ -0,0 +1,179 @@
+// Protocol tests for NNTP. These actually aren't too important, but their main
+// purpose is to make sure that maild is working properly and to provide
+// examples for how using maild. They also help make sure that I coded Nntpd.jsm
+// right, both logically and for RFC compliance.
+// TODO:
+// * We need to hook up mochitest,
+// * TLS negotiation.
+
+// The basic daemon to use for testing Nntpd.jsm implementations
+var daemon = setupNNTPDaemon();
+
+// NNTP SERVER TESTS
+// -----------------
+// Functions in order as defined in Nntpd.jsm. Each function tests the URLs
+// that are located over the implementation of nsNNTPProtocol::LoadURL and
+// added in bug 400331. Furthermore, they are tested in rough order as they
+// would be expected to be used in a session. If more URL types are modified,
+// please add a corresponding type to the following tests.
+// When adding new servers, only test the commands that become different for
+// each specified server, to keep down redudant tests.
+
+function testRFC977() {
+ var server = makeServer(NNTP_RFC977_handler, daemon);
+ server.start(NNTP_PORT);
+
+ try {
+ var prefix = "news://localhost:" + NNTP_PORT + "/";
+ var transaction;
+
+ // Test - group subscribe listing
+ test = "news:*";
+ setupProtocolTest(NNTP_PORT, prefix + "*");
+ server.performTest();
+ transaction = server.playTransaction();
+ do_check_transaction(transaction, ["MODE READER", "LIST"]);
+
+ // Test - getting group headers
+ test = "news:test.subscribe.empty";
+ server.resetTest();
+ setupProtocolTest(NNTP_PORT, prefix + "test.subscribe.empty");
+ server.performTest();
+ transaction = server.playTransaction();
+ do_check_transaction(transaction, [
+ "MODE READER",
+ "GROUP test.subscribe.empty",
+ ]);
+
+ // Test - getting an article
+ test = "news:MESSAGE_ID";
+ server.resetTest();
+ setupProtocolTest(NNTP_PORT, prefix + "TSS1@nntp.invalid");
+ server.performTest();
+ transaction = server.playTransaction();
+ do_check_transaction(transaction, [
+ "MODE READER",
+ "ARTICLE <TSS1@nntp.invalid>",
+ ]);
+ } catch (e) {
+ dump("NNTP Protocol test " + test + " failed for type RFC 977:\n");
+ try {
+ var trans = server.playTransaction();
+ if (trans) {
+ dump("Commands called: " + trans.them + "\n");
+ }
+ } catch (exp) {}
+ do_throw(e);
+ }
+ server.stop();
+
+ var thread = gThreadManager.currentThread;
+ while (thread.hasPendingEvents()) {
+ thread.processNextEvent(true);
+ }
+}
+
+function testConnectionLimit() {
+ var server = makeServer(NNTP_RFC977_handler, daemon);
+ server.start(NNTP_PORT);
+ // 1 is the default, but other tests do change it, so let's be explicit.
+ _server.maximumConnectionsNumber = 1;
+
+ var prefix = "news://localhost:" + NNTP_PORT + "/";
+
+ // To test make connections limit, we run two URIs simultaneously.
+ var url = Services.io.newURI(prefix + "*");
+ _server.loadNewsUrl(url, null, null);
+ setupProtocolTest(NNTP_PORT, prefix + "TSS1@nntp.invalid");
+ server.performTest();
+ // We should have length one... which means this must be a transaction object,
+ // containing only us and them
+ // (playTransactions() returns an array of transaction objects if there is
+ // more than one of them, so this assert will fail in that case).
+ Assert.ok("us" in server.playTransaction());
+ server.stop();
+
+ var thread = gThreadManager.currentThread;
+ while (thread.hasPendingEvents()) {
+ thread.processNextEvent(true);
+ }
+}
+
+function testReentrantClose() {
+ // What we are testing is that a CloseConnection that spins the event loop
+ // does not cause a crash.
+ var server = makeServer(NNTP_RFC977_handler, daemon);
+ server.start(NNTP_PORT);
+
+ var listener = {
+ OnStartRunningUrl(url) {},
+ OnStopRunningUrl(url, rv) {
+ // Spin the event loop (entering nsNNTPProtocol::ProcessProtocolState)
+ let thread = gThreadManager.currentThread;
+ while (thread.hasPendingEvents()) {
+ thread.processNextEvent(true);
+ }
+ },
+ };
+ // Nice multi-step command--we can close while executing this URL if we are
+ // careful.
+ var url = Services.io.newURI(
+ "news://localhost:" + NNTP_PORT + "/test.filter"
+ );
+ url.QueryInterface(Ci.nsIMsgMailNewsUrl);
+ url.RegisterListener(listener);
+
+ _server.loadNewsUrl(url, null, {
+ QueryInterface: ChromeUtils.generateQI(["nsIStreamListener"]),
+ onStartRequest() {},
+ onStopRequest() {},
+ });
+ server.performTest("GROUP");
+ dump("Stopping server\n");
+ gThreadManager.currentThread.dispatch(
+ {
+ run() {
+ _server.closeCachedConnections();
+ },
+ },
+ Ci.nsIEventTarget.DISPATCH_NORMAL
+ );
+ server.performTest();
+ server.stop();
+
+ // Break refcnt loops
+ listener = url = null;
+}
+
+function testManyConnections() {
+ // Start up 2 connections at once and make sure that they don't conflict
+ var server = makeServer(NNTP_RFC2980_handler, daemon);
+ setupLocalServer(NNTP_PORT);
+ server.start(NNTP_PORT);
+ _server.maximumConnectionsNumber = 3;
+ var listener = {
+ ran: 0,
+ OnStartRunningUrl(url) {},
+ OnStopRunningUrl(url, rv) {
+ if (--this.ran == 0) {
+ _server.closeCachedConnections();
+ }
+ },
+ };
+ for (let group of _server.rootFolder.subFolders) {
+ group.getNewMessages(null, listener);
+ listener.ran++;
+ }
+ server.performTest();
+ // The last one that is processed is test.filter, so make sure that
+ // test.subscribed.simple is not retrieving the data meant for test.filter
+ let folder = _server.rootFolder.getChildNamed("test.subscribe.simple");
+ Assert.equal(folder.getTotalMessages(false), 1);
+}
+
+function run_test() {
+ testRFC977();
+ testConnectionLimit();
+ testReentrantClose();
+ testManyConnections();
+}
diff --git a/comm/mailnews/news/test/unit/test_uriParser.js b/comm/mailnews/news/test/unit/test_uriParser.js
new file mode 100644
index 0000000000..a152076333
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_uriParser.js
@@ -0,0 +1,221 @@
+// Tests nsINntpUrl parsing.
+
+var { MailServices } = ChromeUtils.import(
+ "resource:///modules/MailServices.jsm"
+);
+
+var localserver;
+var tests = [
+ // news://host/-based URIs
+ {
+ uri: "news://localhost/?newgroups",
+ get server() {
+ return localserver;
+ },
+ folder: null,
+ newsAction: Ci.nsINntpUrl.ActionListNewGroups,
+ },
+ // news://host/group-based
+ {
+ uri: "news://news.server.example/example.group.this",
+ server: null,
+ folder: null,
+ newsAction: Ci.nsINntpUrl.ActionGetNewNews,
+ group: "example.group.this",
+ },
+ {
+ uri: "news://news.server.example/*",
+ server: null,
+ folder: null,
+ newsAction: Ci.nsINntpUrl.ActionListGroups,
+ },
+ {
+ uri: "news://news.server.example/news.*",
+ server: null,
+ folder: null,
+ newsAction: Ci.nsINntpUrl.ActionListGroups,
+ },
+ {
+ uri: "news://localhost/test.filter?list-ids",
+ get server() {
+ return localserver;
+ },
+ get folder() {
+ return localserver.rootFolder.getChildNamed("test.filter");
+ },
+ newsAction: Ci.nsINntpUrl.ActionListIds,
+ group: "test.filter",
+ },
+ {
+ uri: "news://localhost/some.group?search/XPAT From 1-5 [Ww][Hh][Oo]",
+ get server() {
+ return localserver;
+ },
+ newsAction: Ci.nsINntpUrl.ActionSearch,
+ group: "some.group",
+ },
+
+ // news://host/message-based URIs
+ {
+ uri: "news://localhost/message-id@some-host.invalid",
+ get server() {
+ return localserver;
+ },
+ folder: null,
+ newsAction: Ci.nsINntpUrl.ActionFetchArticle,
+ messageID: "message-id@some-host.invalid",
+ group: "",
+ key: 0xffffffff,
+ },
+ {
+ uri: "news://localhost/message-id@some-host.invalid?part=1.4",
+ get server() {
+ return localserver;
+ },
+ folder: null,
+ newsAction: Ci.nsINntpUrl.ActionFetchPart,
+ messageID: "message-id@some-host.invalid",
+ },
+ {
+ uri: "news://localhost/message-id@some-host.invalid?cancel",
+ get server() {
+ return localserver;
+ },
+ folder: null,
+ newsAction: Ci.nsINntpUrl.ActionCancelArticle,
+ messageID: "message-id@some-host.invalid",
+ },
+ {
+ uri: "news://localhost/message-id@some-host.invalid?group=foo&key=123",
+ get server() {
+ return localserver;
+ },
+ folder: null,
+ newsAction: Ci.nsINntpUrl.ActionFetchArticle,
+ messageID: "message-id@some-host.invalid",
+ group: "foo",
+ key: 123,
+ },
+
+ // No-authority uris
+ {
+ uri: "news:rec.games.pinball",
+ server: null,
+ folder: null,
+ newsAction: Ci.nsINntpUrl.ActionGetNewNews,
+ group: "rec.games.pinball",
+ host: "",
+ },
+ {
+ uri: "news:message-id@some-host.invalid",
+ server: null,
+ folder: null,
+ newsAction: Ci.nsINntpUrl.ActionFetchArticle,
+ messageID: "message-id@some-host.invalid",
+ group: "",
+ key: 0xffffffff,
+ },
+
+ // news-message://host/group#key
+ {
+ uri: "news-message://localhost/test.simple.subscribe#1",
+ newsAction: Ci.nsINntpUrl.ActionFetchArticle,
+ group: "test.simple.subscribe",
+ key: 1,
+ },
+
+ // nntp://host/group
+ {
+ uri: "nntp://localhost/test.filter",
+ get server() {
+ return localserver;
+ },
+ get folder() {
+ return localserver.rootFolder.getChildNamed("test.filter");
+ },
+ newsAction: Ci.nsINntpUrl.ActionGetNewNews,
+ group: "test.filter",
+ },
+ {
+ uri: "nntp://localhost/i.dont.exist",
+ get server() {
+ return localserver;
+ },
+ folder: null,
+ newsAction: Ci.nsINntpUrl.ActionGetNewNews,
+ group: "i.dont.exist",
+ },
+ {
+ uri: "nntp://news.example.invalid/i.dont.exist",
+ server: null,
+ folder: null,
+ newsAction: Ci.nsINntpUrl.ActionGetNewNews,
+ group: "i.dont.exist",
+ },
+
+ // nntp://host/group/key
+ {
+ uri: "nntp://localhost/test.filter/123",
+ get server() {
+ return localserver;
+ },
+ get folder() {
+ return localserver.rootFolder.getChildNamed("test.filter");
+ },
+ newsAction: Ci.nsINntpUrl.ActionFetchArticle,
+ group: "test.filter",
+ key: 123,
+ },
+ {
+ uri: "nntp://localhost/i.dont.exist/123",
+ get server() {
+ return localserver;
+ },
+ folder: null,
+ newsAction: Ci.nsINntpUrl.ActionFetchArticle,
+ group: "i.dont.exist",
+ key: 123,
+ },
+];
+
+var invalid_uris = [
+ "news-message://localhost/test.simple.subscribe#hello",
+ "nntp://localhost/",
+ "nntp://localhost/a.group/hello",
+ "nntp://localhost/a.group/0",
+ "nntp:a.group",
+];
+
+function run_test() {
+ // We're not running the server, just setting it up
+ localserver = setupLocalServer(119);
+ for (let test of tests) {
+ dump("Checking URL " + test.uri + "\n");
+ let url = Services.io.newURI(test.uri);
+ url.QueryInterface(Ci.nsIMsgMailNewsUrl);
+ url.QueryInterface(Ci.nsINntpUrl);
+ for (let prop in test) {
+ if (prop == "uri") {
+ continue;
+ }
+ Assert.equal(url[prop], test[prop]);
+ }
+ }
+
+ for (let fail of invalid_uris) {
+ try {
+ dump("Checking URL " + fail + " for failure\n");
+ Services.io.newURI(fail);
+ Assert.ok(false);
+ } catch (e) {
+ Assert.equal(e.result, Cr.NS_ERROR_MALFORMED_URI);
+ }
+ }
+
+ // The password migration is async, so trigger an event to prevent the logon
+ // manager from trying to migrate after shutdown has started.
+ let thread = Services.tm.currentThread;
+ while (thread.hasPendingEvents()) {
+ thread.processNextEvent(true);
+ }
+}
diff --git a/comm/mailnews/news/test/unit/test_xover.js b/comm/mailnews/news/test/unit/test_xover.js
new file mode 100644
index 0000000000..48cc6f3e50
--- /dev/null
+++ b/comm/mailnews/news/test/unit/test_xover.js
@@ -0,0 +1,42 @@
+/* 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/. */
+
+let daemon = setupNNTPDaemon();
+let server = makeServer(NNTP_RFC2980_handler, daemon);
+server.start();
+registerCleanupFunction(() => {
+ server.stop();
+});
+
+let incomingServer = setupLocalServer(server.port);
+
+/**
+ * Test nsIDBFolderInfo.knownArtsSet is correctly updated after XOVER response.
+ * knownArtsSet depends on the XOVER range requested, it doesn't matter if
+ * articles in that range don't exist on the server.
+ */
+add_task(function test_updateKnownKeySetAfterXOver() {
+ // setupNNTPDaemon inited test.filter with 8 messages, delete the 5th, 6th here.
+ daemon.removeArticleFromGroup("test.filter", 5);
+ daemon.removeArticleFromGroup("test.filter", 6);
+
+ // Trigger a get new messages request.
+ let prefix = "news://localhost:" + server.port + "/";
+ setupProtocolTest(server.port, prefix + "test.filter", incomingServer);
+ server.performTest();
+ let transaction = server.playTransaction();
+
+ // Test XOVER was sent correctly.
+ do_check_transaction(transaction, [
+ "MODE READER",
+ "GROUP test.filter",
+ "XOVER 1-8",
+ ]);
+
+ // Test knownArtsSet was updated correctly.
+ let folder = incomingServer.rootFolder.getChildNamed("test.filter");
+ let groupInfo = folder.msgDatabase.dBFolderInfo;
+ // knownArtsSet should be "1-8", not "1-4,7-8".
+ equal(groupInfo.knownArtsSet, "1-8");
+});
diff --git a/comm/mailnews/news/test/unit/xpcshell.ini b/comm/mailnews/news/test/unit/xpcshell.ini
new file mode 100644
index 0000000000..e997e00987
--- /dev/null
+++ b/comm/mailnews/news/test/unit/xpcshell.ini
@@ -0,0 +1,35 @@
+[DEFAULT]
+head = head_server_setup.js
+tail =
+support-files = postings/*
+
+[test_biff.js]
+[test_bug37465.js]
+[test_bug170727.js]
+run-sequentially = Restarts server twice--may work but dangerous
+[test_bug403242.js]
+[test_bug540288.js]
+[test_bug695309.js]
+[test_cancelPasswordDialog.js]
+[test_filter.js]
+[test_getNewsMessage.js]
+[test_internalUris.js]
+[test_newsAutocomplete.js]
+[test_NntpChannel.js]
+[test_nntpContentLength.js]
+# The server doesn't support returning sizes! (bug 782629)
+skip-if = true
+[test_nntpGroupPassword.js]
+[test_nntpPassword.js]
+[test_nntpPassword2.js]
+skip-if = true # realhostname and realuserName don't exist anymore
+[test_nntpPassword3.js]
+[test_nntpPasswordFailure.js]
+[test_nntpPost.js]
+[test_nntpProtocols.js]
+[test_nntpProxy.js]
+[test_nntpUrl.js]
+[test_server.js]
+run-sequentially = Uses fixed NNTP_PORT
+[test_uriParser.js]
+[test_xover.js]