Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

Commit

Permalink
Bug 1158447 - merge pull request #380 from asutherland:dot-stuffing t…
Browse files Browse the repository at this point in the history
…o mozilla-b2g:master
  • Loading branch information
mozilla-autolander-deprecated committed May 1, 2015
2 parents 2373293 + 00fce29 commit 817ed6b
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 5 deletions.
13 changes: 11 additions & 2 deletions js/drafts/composer.js
Expand Up @@ -192,8 +192,12 @@ Composer.prototype = {
* Request that a body be produced as a single Blob with the given options.
* Multiple calls to this method may overlap concurrently.
*
* @param {object} opts
* { includeBcc: true } if the BCC header should be included.
* @param {Object} opts
* @param {Boolean} [opts.includeBcc=true]
* @param {Boolean} [opts.smtp=false]
* Is this for an SMTP server? Matters for dot-stuffing. Our use of
* Blobs currently has the side-effect of making it impossible for
* smtpclient's dot-stuffing to work, which is somewhat of a problem.
* @param {function(blob)} callback
*/
withMessageBlob: function(opts, callback) {
Expand All @@ -216,6 +220,11 @@ Composer.prototype = {
}

var str = this._rootNode.build();
// smtpclient knows how to do dot-stuffing, but we bypass its dot-stuffing
// logic because smtpclient doesn't understand Blobs.
if (opts.smtp) {
str = str.replace(/\n\./g, '\n..');
}

if (hasBcc) {
str = str.replace(TEMP_BCC_REGEX, 'Bcc: ');
Expand Down
3 changes: 2 additions & 1 deletion js/smtp/account.js
Expand Up @@ -118,7 +118,8 @@ SmtpAccount.prototype = {
sendMessage: function(conn) {
// Then send the actual message if everything was cool
logic(scope, 'building-blob');
composer.withMessageBlob({ includeBcc: false }, function(blob) {
composer.withMessageBlob({ includeBcc: false, smtp: true },
function(blob) {
logic(scope, 'sending-blob', { size: blob.size });
// simplesmtp's SMTPClient does not understand Blobs, so we
// issue the write directly. All that it cares about is
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -25,7 +25,7 @@
"devDependencies": {
"argparse": "~0.1.15",
"js-yaml": "~3.2.2",
"mail-fakeservers": "0.0.39",
"mail-fakeservers": "0.0.40",
"mozilla-download": "~1.0.5",
"ms": "~0.6.2",
"mustache": "~0.8.2",
Expand Down
4 changes: 4 additions & 0 deletions test/test-files.json
Expand Up @@ -220,6 +220,10 @@
"variants": ["imap:fake", "activesync:fake"]
},

"test_compose_roundtripping.js": {
"variants": ["imap:fake", "activesync:fake", "pop3:fake"]
},

"test_storage_upgrade.js": {
"variants": ["imap:fake", "activesync:fake", "pop3:fake"]
},
Expand Down
72 changes: 71 additions & 1 deletion test/unit/resources/account_helpers.js
Expand Up @@ -172,8 +172,78 @@ AccountHelpers.prototype = {
resolve(slice);
};
});
}
},

/**
* Create a nondeterministic subject (in contrast to what TB's messageGenerator
* does because unit tests usually like determinism.) This is required because
* we potentially use a real Inbox which may have test detritus from previous
* runs. In that case, we don't want to be tricked by a previous test run's
* values.
*/
makeRandomSubject() {
return 'Composition: ' + Date.now() + ' ' +
Math.floor(Math.random() * 100000);
},

/**
* Wait for a message with the given subject to show up in the folder. This
* clobbers the onadd/oncomplete listeners as part of its operation.
*/
waitForMessage(slice, expectSubject) {
var activeTimeout;
return new Promise((resolve, reject) => {
var checkHeader = function(header) {
if (header.subject !== expectSubject) {
return false;
}
satisfied = true;
resolve(header);
return true;
}

// Check if the message is already in the slice:
if (!slice.items.some(checkHeader)) {
slice.onadd = checkHeader;

// Nope, we have to listen for changes and continually trigger
// refreshes until we achieve happiness.
var completeFunc = () => {
// trigger a refresh after giving the fake-servers a chance to catch up
activeTimeout = window.setTimeout(
() => {
// the slice clears oncomplete each time it fires, so we need to
// re-bind ourselves
slice.oncomplete = completeFunc;
slice.refresh();
},
20);
};
slice.oncomplete = completeFunc;
// Trigger a refresh if something isn't still ongoing. (When the ongoing
// thing completes, it will trigger our completeFunc.)
if (slice.status !== 'new' && slice.status !== 'synchronizing') {
slice.refresh();
}
}
}).then((header) => {
window.clearTimeout(activeTimeout);
slice.onadd = null;
slice.oncomplete = null;
return header;
});
},

/**
* Transition helper, this just wraps MailHeader.getBody in a Promise. (I'm
* creating this to minimize uplift contamination right now and since the
* Promises refactoring stuff is largely in the conversations branch.)
*/
getBody(header, opts) {
return new Promise((resolve) => {
header.getBody(opts, resolve);
});
}
};


Expand Down
72 changes: 72 additions & 0 deletions test/unit/test_compose_roundtripping.js
@@ -0,0 +1,72 @@
define(function(require) {

var GelamTest = require('./resources/gelamtest');
var AccountHelpers = require('./resources/account_helpers');
var assert = require('./resources/assert');
var help;

/**
* Verify that we properly address a reply to a message containing a Reply-To
* header.
*/
return new GelamTest('compose round-trips correctly', function*(MailAPI) {
this.group('setup');

// Alternately, we could perhaps just slurp up a bunch of JSON definitions?
var messagesToCompose = [
{
name: 'dot stuffing test',
why: 'end-to-end SMTP dot stuffing verification',
textBody: `..apple
..banana
...cherry
..crouton
.deli meats
..energy`
},
];

// -- create the account, get the inbox
help = new AccountHelpers(MailAPI);
var account = yield help.createAccount(this.options);
var inboxFolder = help.folders.getFirstFolderWithType('inbox');
var inboxView = yield help.viewFolder(inboxFolder);

for (var iMessage = 0; iMessage < messagesToCompose.length; iMessage++) {
var messageDef = messagesToCompose[iMessage];

this.group(messageDef.name);

// - Create the composer
var composer = yield new Promise((resolve) => {
MailAPI.beginMessageComposition(null, inboxFolder, {}, resolve);
});

// - Update the composer with the desired state
// Loopback to this account's identity
composer.to.push({ address: composer.senderIdentity.address });

var uniqueSubject = composer.subject = help.makeRandomSubject();

// We're intentionally not using or working with signatures here; at least
// for dot-stuffing we don't want the signature stealing the last line case
// from us.
composer.body.text = messageDef.textBody;

// - Send the message
composer.finishCompositionSendMessage();

// - Wait for the message to be show up in the folder view
var header = yield help.waitForMessage(inboxView, uniqueSubject);

// - Get the body
var body = yield help.getBody(header, { withBodyReps: true });

// - Verify the body matches
assert.equal(
body.bodyReps[0].content[1],
messageDef.textBody);
}
});

});

0 comments on commit 817ed6b

Please sign in to comment.