From d6c3c4b1a3f6235b58bbcba73172913b095731b3 Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Mon, 1 Nov 2021 16:46:48 -0400 Subject: [PATCH] test: migration from Python to JavaScript --- Tests/lib/WebDAV.js | 41 +++ Tests/spec/CardDAVSpec.js | 2 +- Tests/spec/ConfigSpec.js | 2 +- Tests/spec/MailDAVSpec.js | 532 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 575 insertions(+), 2 deletions(-) create mode 100644 Tests/spec/MailDAVSpec.js diff --git a/Tests/lib/WebDAV.js b/Tests/lib/WebDAV.js index 6ca7ad2de..4c77be5c8 100644 --- a/Tests/lib/WebDAV.js +++ b/Tests/lib/WebDAV.js @@ -427,6 +427,47 @@ class WebDAV { }) } + mailQueryMaildav(resource, properties, filters = {}) { + let formattedFilters = {} + if (filters.constructor.toString().includes('Array')) { + filters.map(f => { + Object.keys(f).map(p => { + const pName = `${DAVInverseShort}:${p}` + if (!formattedFilters[pName]) + formattedFilters[pName] = [] + formattedFilters[pName].push({ _attributes: f[p] }) + }) + }) + } + else { + Object.keys(filters).map(p => { + const pName = `${DAVInverseShort}:${p}` + if (!formattedFilters[pName]) + formattedFilters[pName] = [] + formattedFilters[pName].push({ _attributes: filters[p] }) + }) + } + + return davRequest({ + url: this.serverUrl + resource, + init: { + method: 'REPORT', + namespace: DAVNamespaceShorthandMap[DAVNamespace.DAV], + headers: this.headers, + body: { + [`${DAVInverseShort}:mail-query`]: { + _attributes: { + ...getDAVAttribute([DAVNamespace.DAV]), + [`xmlns:${DAVInverseShort}`]: DAVInverse + }, + prop: formatProps(properties.map(p => { return { name: p } })), + [`${DAVInverseShort}:mail-filters`]: formattedFilters + } + } + } + }) + } + } export default WebDAV \ No newline at end of file diff --git a/Tests/spec/CardDAVSpec.js b/Tests/spec/CardDAVSpec.js index 32fe5a600..01d37a2d0 100644 --- a/Tests/spec/CardDAVSpec.js +++ b/Tests/spec/CardDAVSpec.js @@ -96,7 +96,7 @@ describe('CardDAV extensions', function() { }) // https://datatracker.ietf.org/doc/html/rfc6352#section-8.7 - fit("supports for addressbook-multiget", async function() { + it("supports for addressbook-multiget", async function() { const hrefs = Object.keys(cards).map(c => `${resource}${c}`) const response = await davRequest({ url: webdav.serverUrl + resource, diff --git a/Tests/spec/ConfigSpec.js b/Tests/spec/ConfigSpec.js index 1cad8626a..419da043d 100644 --- a/Tests/spec/ConfigSpec.js +++ b/Tests/spec/ConfigSpec.js @@ -2,7 +2,7 @@ import config from '../lib/config' describe('config tests', function() { - fit('required configuration parameters', async function() { + it('required configuration parameters', async function() { expect(config.hostname) .withContext(`Config 'hostname'`) .toBeDefined() diff --git a/Tests/spec/MailDAVSpec.js b/Tests/spec/MailDAVSpec.js new file mode 100644 index 000000000..d5f80c267 --- /dev/null +++ b/Tests/spec/MailDAVSpec.js @@ -0,0 +1,532 @@ +import config from '../lib/config' +import WebDAV from '../lib/WebDAV' +import TestUtility from '../lib/utilities' +import { fetch } from 'cross-fetch' + +const message1 = `Return-Path: +Received: from cyril.dev (localhost [127.0.0.1]) + by cyril.dev (Cyrus v2.3.8-Debian-2.3.8-1) with LMTPA; + Tue, 17 Dec 2009 07:42:16 -0400 +Received: from aloha.dev (localhost [127.0.0.1]) + by aloha.dev (Cyrus v2.3.8-Debian-2.3.8-1) with LMTPA; + Tue, 29 Sep 2009 07:42:16 -0400 +Message-ID: <4AC1F29sept6.5060801@cyril.dev> +Date: Mon, 28 Sep 2009 07:42:14 -0400 +From: Cyril +User-Agent: Thunderbird 2.0.0.22 (Macintosh/20090605) +References: <4AC3BF1B.3010806@inverse.ca> +MIME-Version: 1.0 +To: message1to@cyril.dev +CC: 2message1cc@cyril.dev, user10@cyril.dev +Subject: message1subject +Content-Type: text/plain; charset=us-ascii; format=flowed +Content-Transfer-Encoding: 7bit +Reply-To: support@inverse.ca + +Hello Jacques, + +Can you read me? + +-- +Cyril +` +const msg1Size = 874 +const message2 = `Return-Path: +Received: from cyril.dev (localhost [127.0.0.1]) + by cyril.dev (Cyrus v2.3.8-Debian-2.3.8-1) with LMTPA; + Tue, 09 Dec 2009 07:42:16 -0400 +Message-ID: <410sepAC1F296.5060801a@cyril.dev> +Date: Tue, 10 Sep 2009 07:42:14 -0400 +User-Agent: Thunderbird 2.0.0.22 (Macintosh/20090605) +MIME-Version: 1.0 +From: Cyril +To: message2to@cyril.dev +CC: 3message2cc@cyril.dev +Subject: message2subject +Content-Type: text/plain; charset=us-ascii; format=flowed +Content-Transfer-Encoding: 7bit +Reply-To: support@inverse.ca + +Hello Jacques, + +Can you read me? + +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +Stuff StuffStuffStuffStuff StuffStuffStuff StuffStuff +-- +Cyril +` +const msg2Size = 4398 +const message3 = `Return-Path: +Received: from cyril.dev (localhost [127.0.0.1]) + by cyril.dev (Cyrus v2.3.8-Debian-2.3.8-1) with LMTPA; + Tue, 15 Dec 2009 07:42:16 -0400 +Message-ID: <4AC1aF2dec96.5060801a@cyril.dev> +Date: Tue, 10 Dec 2009 07:42:14 -0400 +User-Agent: Thunderbird 2.0.0.22 (Macintosh/20090605) +MIME-Version: 1.0 +From: Cyril +To: message3to@cyril.dev +CC: 1message3cc@cyril.dev +Subject: Hallo +Content-Type: text/plain; charset=us-ascii; format=flowed +Content-Transfer-Encoding: 7bit +Reply-To: support@inverse.ca + +Hello Jacques, + +Can you read me? + +This message is just a bit larger than message1 but smaller than message2 +-- +Cyril ` +const msg3Size = 720 + +let webdav, utility +let user, resource, mailboxesList + +// DAVMailCollectionTest + +describe('MailDAV', function() { + + const _deleteMailbox = async function (path, expectedCode = 204) { + const folderPath = path.split('/').map(p => `folder${p}`).join('/') + const response = await webdav.deleteObject(resource + folderPath) + if (expectedCode) { + expect(response.status) + .withContext(`HTTP status code when deleting the mailbox ${path}`) + .toBe(expectedCode) + } + } + + const _makeMailbox = async function (path, expectedCode = 201) { + const [lastFolder, ...parents] = path.split('/').reverse() + let mailPath = lastFolder + if (parents.lenght) { + mailPath = parents.reverse().map(p => `folder${p}`).join('/') + '/' + lastFolder + } + const [response] = await webdav.makeCollection(resource + mailPath) + if (mailboxesList.indexOf(path) < 0) + mailboxesList.push(path) + expect(response.status) + .withContext(`HTTP status code when creating the mailbox ${path}`) + .toBe(expectedCode) + } + + const _putMessage = async function (path, message, expectedCode = 201) { + const url = resource + `folder${path}` + const localHeaders = {'Content-Type': 'message/rfc822'} + const response = await fetch(webdav.serverUrl + url, { + method: 'PUT', + headers: { ...webdav.headers, ...localHeaders }, + body: message + }) + if (expectedCode != null) + expect(response.status) + .withContext(`HTTP status code when putting a message`) + .toBe(expectedCode) + if (response.status >= 200) + return response.headers.get('location'); + } + + const _testFilter = async function (filter) { + const [filters, hrefs] = filter + const url = `${resource}foldertest-dav-mail` + const results = await webdav.mailQueryMaildav(url, ['displayname'], filters) + + let received_count = 0 + for (let response of results) { + expect(response.status) + .withContext(`HTTP status code when performing a mail query`) + .toBe(207) + if (response.href) { + expect(hrefs.includes(response.href)) + .withContext(`${response.href} is returned (filter: ${JSON.stringify(filters)}, expected results: ${hrefs.join(', ')})`) + .toBeTrue() + received_count++ + } + } + expect(received_count) + .withContext(`Expected number of results from mail query ${JSON.stringify(filters)}`) + .toEqual(hrefs.length) + } + + beforeAll(async function() { + webdav = new WebDAV(config.username, config.password) + utility = new TestUtility(webdav) + user = await utility.fetchUserInfo(config.username) + mailboxesList = [] + resource = `/SOGo/dav/${config.username}/Mail/0/` + }) + + afterEach(async function() { + for (let path of mailboxesList.reverse()) { + await _deleteMailbox(path) + } + }) + + it(`Folder creation`, async function() { + await _makeMailbox('test-dav-mail-%40-abc') + await _makeMailbox('test-dav-mail-@-def') + await _makeMailbox('test-dav-mail-%20-ghi') + await _makeMailbox('test-dav-mail-%20-ghi', 500) + await _makeMailbox('test-dav-mail') + await _makeMailbox('test-dav-mail/test-dav-mail') + }) + + it(`Message creation`, async function() { + const mailbox = 'test-dav-mail' + let itemLocation, url, response + + await _makeMailbox(mailbox) + + // message creation on collection url + itemLocation = await _putMessage(mailbox, message1); + [response] = await webdav.getObject(itemLocation) + expect(response.status) + .withContext(`HTTP status code when fetching a message`) + .toBe(200) + + // message creation with explicit filename + itemLocation = await _putMessage(`${mailbox}/blabla.eml`, message1); + [response] = await webdav.getObject(itemLocation) + expect(response.status) + .withContext(`HTTP status code when fetching a message`) + .toBe(200) + }) + + fit(`mail-query filters`, async function() { + const mailbox = 'test-dav-mail' + const url = `${resource}folder${mailbox}` + let msg1Loc, msg2Loc, msg3Loc + let filter, filters + + await _makeMailbox(mailbox) + msg1Loc = await _putMessage(mailbox, message1); + msg2Loc = await _putMessage(mailbox, message2); + msg3Loc = await _putMessage(mailbox, message3); + + // 1. test filter: sent-date + // SENTSINCE, SENTBEFORE, SENTON + filters = [ + [ + { + 'sent-date': { + from: '20091201T000000Z', + to: '20091208T000000Z' + } + }, + [] + ], + [ + { + 'sent-date': { + from: '20090908T000000Z', + to: '20090913T134300Z' + } + }, + [ msg2Loc ] + ], + [ + { + 'sent-date': { + from: '20090908T000000Z', + to: '20091016T134300Z' + } + }, + [ msg1Loc, msg2Loc ] + ], + [ + { + 'sent-date': { + from: '20091210T000000Z', + to: '20091220T134300Z' + } + }, + [ msg3Loc ] + ], + [ + { + 'sent-date': { + from: '20091220T000000', + to: '20091229T134300Z' + } + }, + [] + ] + ] + + for (filter of filters) { + await _testFilter(filter) + } + + // 2. test filter: uid + filters = [ + [ + { uid: { from: '1' }}, + [ msg1Loc, msg2Loc, msg3Loc ] + ], + [ + { uid: { to: '5' }}, + [ msg1Loc, msg2Loc, msg3Loc ] + ], + [ + { uid: { from: '1', to: '2' }}, + [ msg1Loc, msg2Loc ] + ] + ] + + for (filter of filters) { + await _testFilter(filter) + } + + // 3. test filter: from + // FROM + filters = [ + [ + { from: { match: 'message' } }, + [ msg1Loc, msg2Loc, msg3Loc ] + ], + [ + { from: { match: 'Cyril' } }, + [ msg1Loc, msg2Loc, msg3Loc ] + ], + [ + { from: { match: 'cyril.dev' } }, + [ msg1Loc, msg2Loc, msg3Loc ] + ], + [ + { from: { match: 'message1from' } }, + [ msg1Loc ] + ], + [ + { from: { match: 'message2from' } }, + [ msg2Loc ] + ], + [ + { from: { match: 'message3from' } }, + [ msg3Loc ] + ] + ] + + for (filter of filters) { + await _testFilter(filter) + } + + // 4. test filter: to + // TO + filters = [ + [ + { to: { match: 'message' }}, + [ msg1Loc, msg2Loc, msg3Loc ] + ], + [ + { to: { match: 'Cyril' }}, + [ msg1Loc, msg2Loc, msg3Loc ] + ], + [ + { to: { match: 'message1to' }}, + [ msg1Loc ] + ], + [ + { to: { match: 'message2to' }}, + [ msg2Loc ] + ], + [ + { to: { match: 'message3to' }}, + [ msg3Loc ] + ] + ] + + for (filter of filters) { + await _testFilter(filter) + } + + // 5. test filter: cc + // CC + filters = [ + [ + { cc: { match: 'message' }}, + [ msg1Loc, msg2Loc, msg3Loc ] + ], + [ + { cc: { match: 'Cyril' }}, + [ msg1Loc, msg2Loc, msg3Loc ] + ], + [ + { cc: { match: 'cyril.dev' }}, + [ msg1Loc, msg2Loc, msg3Loc ] + ], + [ + { cc: { match: 'message1cc' }}, + [ msg1Loc ] + ], + [ + { cc: { match: 'message2cc' }}, + [ msg2Loc ] + ], + [ + { cc: { match: 'message3cc' }}, + [ msg3Loc ] + ] + ] + + for (filter of filters) { + await _testFilter(filter) + } + + // 6. test filter: body + // BODY + filters = [ + [ + { body: { match: 'Hello' }}, + [ msg1Loc, msg2Loc, msg3Loc ] + ], + [ + { body: { match: 'Stuff' }}, + [ msg2Loc ] + ], + [ + { body: { match: 'DOESNOT MATCH' }}, + [] + ] + ] + + for (filter of filters) { + await _testFilter(filter) + } + + // 7. test filter: size + // LARGER, SMALLER + filters = [ + [ + { size: { min: msg1Size, max: msg1Size }}, + [] + ], + [ + { size: { min: msg1Size -1, max: msg1Size +1 }}, + [ msg1Loc ] + ], + [ + { size: { min: msg3Size -1, max: msg2Size +1 }}, + [ msg1Loc, msg2Loc, msg3Loc ] + ], + [ + { size: { min: msg1Size -1, max: msg2Size +1 }}, + [ msg1Loc, msg2Loc ] + ], + [ + { size: { min: msg3Size -1, max: msg1Size +1 }}, + [ msg1Loc, msg3Loc ] + ], + [ + [ + { size: { min: msg3Size -1, max: msg2Size +1 } }, + { size: { max: msg1Size +1, not: "true" } } + ], + [ msg2Loc ] + ] + ] + + for (filter of filters) { + await _testFilter(filter) + } + + // 8. test filter: multiple combinations + filters = [ + [ + { + body: { match: "Hello" }, + cc: { match: "message1cc" } + }, + [ msg1Loc ] + ], + [ + { + to: { match: "message" }, + uid: { from: "1", to: "2" } + }, + [ msg1Loc, msg2Loc ] + ], + [ + { + to: { match: "message" }, + uid: { from: "1", to: "2" }, + cc: { match: "message3cc" } + }, + [] + ] + ] + + for (filter of filters) { + await _testFilter(filter) + } + + }, 30000) // increase timeout for this long test +}) \ No newline at end of file