diff options
Diffstat (limited to '')
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] |