fix(project): move mailer files into proper directories (#1676) r=vladikoff

This commit is contained in:
Phil Booth 2017-02-24 15:31:07 +00:00 коммит произвёл Vlad Filippov
Родитель 0c52a7cf06
Коммит d09759cee8
97 изменённых файлов: 4821 добавлений и 10788 удалений

4
.gitignore поставляемый
Просмотреть файл

@ -17,5 +17,5 @@ secret*
/.vagrant
.nyc_output
npm-debug.log
mailer/server.pot
mailer/.mail_output
server.pot
.mail_output

3
.nsprc
Просмотреть файл

@ -1,4 +1,7 @@
{
"exceptions": [
// i18n-abide@0.0.25
"https://nodesecurity.io/advisories/39",
"https://nodesecurity.io/advisories/48"
]
}

Просмотреть файл

@ -46,10 +46,7 @@ script:
- COVERALLS_REPO_TOKEN=vKN3jjhAOwxkv9HG0VBX4EYIlWLPwiJ9d npm test
- npm run test-e2e
# Test fxa-auth-mailer
- cd mailer
- grunt templates
- npm test
- grunt l10n-extract
- cd ..
# NSP check
- grunt nsp

Просмотреть файл

@ -5,7 +5,12 @@
module.exports = function (grunt) {
require('load-grunt-tasks')(grunt)
grunt.initConfig({
pkg: grunt.file.readJSON('package.json')
})
grunt.loadTasks('grunttasks')
grunt.registerTask('default', ['eslint', 'copyright'])
grunt.registerTask('mailer', ['templates', 'copy:strings', 'l10n-extract'])
}

Просмотреть файл

@ -3,9 +3,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var restify = require('restify')
var config = require('../config')
var config = require('../mailer/config')
var log = require('../log')('server')
var log = require('../lib/senders/log')('server')
var mailConfig = config.get('mail')
var packageJson = require('../package.json')
@ -13,16 +13,16 @@ var P = require('bluebird')
// NOTE: Mailer is also used by fxa-auth-server directly with an old logging interface
// the legacy log module provides an interface to convert old logs to new mozlog logging.
var mailerLog = require('../log')('mailer')
var legacyMailerLog = require('../legacy_log')(mailerLog)
var Mailer = require('../mailer')(legacyMailerLog)
var mailerLog = require('../lib/senders/log')('mailer')
var legacyMailerLog = require('../lib/senders/legacy_log')(mailerLog)
var Mailer = require('../lib/senders/email')(legacyMailerLog)
var dbConnect = require('../lib/db_connect')()
var dbConnect = require('../lib/senders/db_connect')()
P.all(
[
require('../translator')(config.get('locales'), config.get('defaultLanguage')),
require('../templates')()
require('../lib/senders/translator')(config.get('locales'), config.get('defaultLanguage')),
require('../lib/senders/templates')()
]
)
.spread(
@ -35,7 +35,7 @@ P.all(
dbConnect()
.then(function (db) {
// fetch and process verification reminders
var verificationReminders = require('../lib/verification-reminders')(mailer, db)
var verificationReminders = require('../lib/senders/verification-reminders')(mailer, db)
verificationReminders.poll()
})
.catch(function (err) {

Просмотреть файл

@ -13,7 +13,7 @@ module.exports = function (grunt) {
bumpVersion: true,
commit: true,
commitMessage: 'Release v%VERSION%',
commitFiles: ['package.json', 'npm-shrinkwrap.json', 'CHANGELOG.md'],
commitFiles: ['package.json', 'npm-shrinkwrap.json', 'CHANGELOG.md', 'AUTHORS'],
createTag: true,
tagName: 'v%VERSION%',
tagMessage: 'Version %VERSION%',

Просмотреть файл

@ -30,7 +30,7 @@ module.exports = function (grunt) {
var done = this.async()
var walker = extract({
'input-dir': path.join(pkgroot, 'templates'),
'input-dir': path.join(pkgroot, 'lib/senders/templates'),
'output-dir': pkgroot,
'output': 'server.pot',
'join-existing': true,
@ -43,12 +43,7 @@ module.exports = function (grunt) {
walker.on('end', function () {
var jsWalker = extract({
'input-dir': pkgroot,
/* node_modules and test should not contain any strings
* Gruntfile causes an error and should contain no strings
* bin/server.js extracts "/", so it is excluded.
*/
exclude: /(node_modules|test|Gruntfile|grunttasks|bin|scripts|\.git|config)/,
'input-dir': path.join(pkgroot, 'lib/senders'),
'output-dir': pkgroot,
'output': 'server.pot',
'join-existing': true,

Просмотреть файл

@ -9,6 +9,7 @@ module.exports = function (grunt) {
grunt.config('nunjucks', {
options: {
paths: 'lib/senders/',
tags: {
blockStart: '<%',
blockEnd: '%>',
@ -23,9 +24,9 @@ module.exports = function (grunt) {
files: [
{
expand: true,
cwd: 'partials/',
cwd: 'lib/senders/partials/',
src: '*.html',
dest: 'templates/',
dest: 'lib/senders/templates/',
ext: '.html'
}
]

Просмотреть файл

@ -2,9 +2,9 @@
* 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 butil = require('./crypto/butil')
var log = require('../log')('db')
var P = require('./promise')
var butil = require('../crypto/butil')
var log = require('./log')('db')
var P = require('../promise')
var Pool = require('./pool')
var qs = require('querystring')
@ -40,7 +40,7 @@ module.exports = function () {
.then(
function (body) {
var data = bufferize(body)
data.emailVerified = !!data.emailVerified
data.emailVerified = !! data.emailVerified
return data
},
function (err) {
@ -55,7 +55,7 @@ module.exports = function () {
.then(
function (body) {
var data = bufferize(body)
data.emailVerified = !!data.emailVerified
data.emailVerified = !! data.emailVerified
return data
},
function (err) {

Просмотреть файл

@ -3,8 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var P = require('bluebird')
var config = require('../config')
var log = require('../log')('db')
var config = require('../../mailer/config')
var log = require('./log')('db')
var DB = require('./db')()
@ -29,10 +29,10 @@ module.exports = function () {
function (err) {
if (err && err.message && err.message.indexOf('ECONNREFUSED') > -1) {
log.warn('db', {message: 'Failed to connect to database, retrying...'})
if (!cancelled) {
if (! cancelled) {
return P.delay(dbConnectionRetry)
.then(function () {
if (!cancelled) {
if (! cancelled) {
return dbConnectPoll()
}
})
@ -51,7 +51,7 @@ module.exports = function () {
// report any errors to the db log and rethrow it to the consumer.
log.error('db', {err: err})
throw err
});
})
}
return dbConnect

Просмотреть файл

Просмотреть файл

@ -4,11 +4,16 @@
'use strict'
const P = require('./promise')
const createSenders = require('../mailer/index')
var P = require('../promise')
// This indirection exists to accommodate different config properties
// in the old auth mailer. If/when the two config files are merged and
// there's nothing left that imports mailer/config, it is safe to merge
// raw.js and this file into one. Be careful not to mix the arguments
// up when you do that, they expect config and log in a different order.
var createSenders = require('./legacy_index')
module.exports = (config, log) => {
const defaultLanguage = config.i18n.defaultLanguage
module.exports = function (config, log) {
var defaultLanguage = config.i18n.defaultLanguage
return createSenders(
log,
@ -20,8 +25,8 @@ module.exports = (config, log) => {
}
)
.then(
senders => {
const mailer = senders.email
function (senders) {
var mailer = senders.email
mailer.sendVerifyCode = function (account, code, opts) {
return P.resolve(mailer.verifyEmail(
{

Просмотреть файл

@ -2,9 +2,16 @@
* 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 P = require('bluebird')
var createMailer = require('./mailer')
var createSms = require('./lib/sms')
// This module exists because some files still use the old mailer config.
// Those files should import this module rather than its sibling index.js.
// If/when we eliminate the old mailer config and everything is importing
// index.js, we can merge this into there and get rid of the indirection.
// Be careful when doing that btw, they expect the log and config arguments
// in a different order.
var P = require('../promise')
var createMailer = require('./email')
var createSms = require('./sms')
module.exports = function (log, config, sender) {
var Mailer = createMailer(log)

Просмотреть файл

Просмотреть файл

@ -4,7 +4,7 @@
var mozlog = require('mozlog')
var logConfig = require('./config').get('logging')
var logConfig = require('../../mailer/config').get('logging')
mozlog.config(logConfig)

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -2,7 +2,7 @@
* 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 P = require('./promise')
var P = require('../promise')
var Poolee = require('poolee')
function parseUrl(url) {

Просмотреть файл

@ -16,7 +16,7 @@ module.exports = function (log, translator, templates, smsConfig) {
apiKey: smsConfig.apiKey,
apiSecret: smsConfig.apiSecret
})
var sendSms = P.promisify(nexmo.message.sendSms, { context: nexmo.message })
var sendSms = P.promisify(nexmo.message.sendSms, nexmo.message)
return {
send: function (phoneNumber, senderId, messageId, acceptLanguage) {

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -1,3 +1,7 @@
/* 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 path = require('path')
var P = require('bluebird')
var handlebars = require('handlebars')

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -1,3 +1,7 @@
/* 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 path = require('path')
var i18n = require('i18n-abide')
var Jed = require('jed')
@ -14,7 +18,7 @@ module.exports = function (locales, defaultLanguage) {
return poParseFile(
path.join(
__dirname,
'node_modules/fxa-content-server-l10n/locale',
'../../node_modules/fxa-content-server-l10n/locale',
i18n.normalizeLocale(locale),
'LC_MESSAGES/server.po'
),

Просмотреть файл

@ -2,9 +2,9 @@
* 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 logger = require('../log')('verification-reminders')
var P = require('./promise')
var config = require('../config')
var logger = require('./log')('verification-reminders')
var P = require('../promise')
var config = require('../../mailer/config')
var reminderConfig = config.get('verificationReminders')
module.exports = function (mailer, db, options) {
@ -22,25 +22,25 @@ module.exports = function (mailer, db, options) {
* @private
*/
_processReminder: function (reminderData) {
log.debug('_processReminder', reminderData)
log.debug('_processReminder', reminderData)
return db.account(reminderData.uid)
.then(function (account) {
if (! account.emailVerified) {
// if account is not verified then send the reminder
mailer.verificationReminderEmail({
email: account.email,
uid: account.uid.toString('hex'),
code: account.emailCode.toString('hex'),
type: reminderData.type,
acceptLanguage: account.locale
})
} else {
log.debug('_processReminder', { msg: 'Already Verified' })
}
}, function (err) {
log.error('_processReminder', { err: err })
})
return db.account(reminderData.uid)
.then(function (account) {
if (! account.emailVerified) {
// if account is not verified then send the reminder
mailer.verificationReminderEmail({
email: account.email,
uid: account.uid.toString('hex'),
code: account.emailCode.toString('hex'),
type: reminderData.type,
acceptLanguage: account.locale
})
} else {
log.debug('_processReminder', { msg: 'Already Verified' })
}
}, function (err) {
log.error('_processReminder', { err: err })
})
},
_continuousPoll: function () {
var self = this

5
mailer/.gitignore поставляемый
Просмотреть файл

@ -1,5 +0,0 @@
node_modules
server.pot
*.log
.mail_output
.nyc_output

Просмотреть файл

@ -1,19 +0,0 @@
#!/usr/bin/env node
/* 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/. */
module.exports = function (grunt) {
'use strict'
require('load-grunt-tasks')(grunt)
grunt.initConfig({
pkg: grunt.file.readJSON('package.json')
})
grunt.loadTasks('grunttasks')
grunt.registerTask('default', [ 'templates', 'copy:strings', 'l10n-extract' ])
}

Просмотреть файл

@ -1,24 +0,0 @@
/* 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/. */
// takes care of bumping the version number in package.json
module.exports = function (grunt) {
grunt.config('bump', {
options: {
files: [ 'package.json', 'npm-shrinkwrap.json' ],
bumpVersion: true,
commit: true,
commitMessage: 'Release v%VERSION%',
commitFiles: ['package.json', 'npm-shrinkwrap.json', 'CHANGELOG.md', 'AUTHORS'],
createTag: true,
tagName: 'v%VERSION%',
tagMessage: 'Version %VERSION%',
push: false,
pushTo: 'origin',
gitDescribeOptions: '--tags --always --abrev=1 --dirty=-d'
}
})
}

Просмотреть файл

@ -1,20 +0,0 @@
/* 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 fxaChangelog = require('fxa-conventional-changelog')()
module.exports = function (grunt) {
grunt.config('conventionalChangelog', {
options: {
changelogOpts: {},
parserOpts: fxaChangelog.parserOpts,
writerOpts: fxaChangelog.writerOpts
},
release: {
src: 'CHANGELOG.md'
}
})
}

Просмотреть файл

@ -1,16 +0,0 @@
/* 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/. */
module.exports = function (grunt) {
'use strict'
grunt.config('eslint', {
options: {
eslintrc: '.eslintrc'
},
app: [
'*.js', 'bin/*.js', 'grunttasks/*.js', 'templates/*.js', 'test/**/*.js', 'scripts/**/*.js'
]
})
}

Просмотреть файл

@ -1,14 +0,0 @@
/* 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/. */
// meta grunt task to run other linters.
module.exports = function (grunt) {
var SUBTASKS = [
'eslint'
]
grunt.registerTask('lint', 'lint all the things', SUBTASKS)
}

Просмотреть файл

@ -1,24 +0,0 @@
/* 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/. */
// A task to stamp a new version.
//
// * version is updated in package.json
// * CHANGELOG.md updated with changes since last version
// * git tag with version name is created.
// * git commit with updated package.json and CHANGELOG.md created.
module.exports = function (grunt) {
grunt.registerTask('version', [
'bump-only:minor',
'conventionalChangelog',
'bump-commit'
])
grunt.registerTask('version:patch', [
'bump-only:patch',
'conventionalChangelog',
'bump-commit'
])
}

Просмотреть файл

@ -1,36 +0,0 @@
/* 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 HEX = /^(?:[a-fA-F0-9]{2})+$/
module.exports.unbuffer = function unbuffer(object, inplace) {
var keys = Object.keys(object)
var copy = inplace ? object : {}
for (var i = 0; i < keys.length; i++) {
var x = object[keys[i]]
copy[keys[i]] = Buffer.isBuffer(x) ? x.toString('hex') : x
}
return copy
}
module.exports.bufferize = function bufferize(object, options) {
var keys = Object.keys(object)
options = options || {}
var copy = options.inplace ? object : {}
var ignore = options.ignore || []
for (var i = 0; i < keys.length; i++) {
var key = keys[i]
var value = object[key]
if (
ignore.indexOf(key) === -1 &&
typeof value === 'string' &&
HEX.test(value)
) {
copy[key] = Buffer(value, 'hex')
} else {
copy[key] = value
}
}
return copy
}

Просмотреть файл

@ -1,6 +0,0 @@
/* 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/. */
// for easy promise lib switching
module.exports = require('bluebird')

9259
mailer/npm-shrinkwrap.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,60 +0,0 @@
{
"name": "fxa-auth-mailer",
"version": "1.81.0",
"description": "Library to send out verification emails in the fxa-auth-server which renders emails from a template (and handles localization).",
"main": "index.js",
"scripts": {
"start": "NODE_ENV=dev node bin/server.js",
"test": "grunt lint && ./scripts/tap-coverage.js test/local",
"prepush": "grunt templates && git status -s | (! grep 'M templates/')",
"postinstall": "scripts/download_l10n.sh",
"shrinkwrap": "npmshrink"
},
"author": "Mozilla (https://mozilla.org/)",
"repository": {
"type": "git",
"url": "https://github.com/mozilla/fxa-auth-mailer"
},
"homepage": "https://github.com/mozilla/fxa-auth-mailer",
"bugs": "https://github.com/mozilla/fxa-auth-mailer/issues",
"license": "MPL-2.0",
"dependencies": {
"bluebird": "3.4.7",
"convict": "2.0.0",
"fxa-shared": "1.0.4",
"grunt-nunjucks-2-html": "vitkarpov/grunt-nunjucks-2-html#1900f91a756b2eaf900b20",
"handlebars": "1.3.0",
"i18n-abide": "0.0.25",
"jed": "0.5.4",
"moment-timezone": "0.5.11",
"mozlog": "2.0.6",
"nexmo": "1.2.0",
"nodemailer": "2.7.2",
"po2json": "0.4.5",
"poolee": "1.0.1",
"request": "2.79.0",
"restify": "4.3.0"
},
"devDependencies": {
"eslint-config-fxa": "2.1.0",
"fxa-auth-db-mysql": "git+https://github.com/mozilla/fxa-auth-db-mysql.git#master",
"fxa-conventional-changelog": "1.1.0",
"grunt": "1.0.1",
"grunt-bump": "0.8.0",
"grunt-cli": "1.2.0",
"grunt-contrib-copy": "1.0.0",
"grunt-conventional-changelog": "5.0.0",
"grunt-copyright": "0.3.0",
"grunt-eslint": "18.0.0",
"husky": "0.13.1",
"jsxgettext-recursive": "0.0.5",
"load-grunt-tasks": "3.5.0",
"mkdirp": "0.5.1",
"npmshrink": "1.0.1",
"proxyquire": "1.7.10",
"simplesmtp": "0.3.35",
"sinon": "1.17.4",
"tap": "6.2.0",
"uuid": "1.4.1"
}
}

Просмотреть файл

@ -1,6 +0,0 @@
{
"rules": {
"handle-callback-err": 0,
"no-console": 0
}
}

Просмотреть файл

@ -1,35 +0,0 @@
#!/usr/bin/env node
/* 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 cp = require('child_process')
var util = require('util')
// Generate legacy-format output that looks something like:
//
// {
// "version": {
// "hash": "88f6f24e53da56faa933c357bffb61cbeaec7ff3",
// "subject": "Merge pull request #2939 from vladikoff/sentry-patch3",
// "committer date": "1439472293",
// "source": "git://github.com/mozilla/fxa-content-server.git"
// }
// }
//
// This content is placed in the stage/prod rpm at `./config/version.json`.
// Ignore errors and always produce a (possibly empty struct) output.
var args = '{"hash":"%H","subject":"%s","committer date":"%ct"}'
var cmd = util.format('git --no-pager log --format=format:\'%s\' -1', args)
cp.exec(cmd, function (err, stdout) {
var info = {
version: JSON.parse(stdout || '{}')
}
var cmd = 'git config --get remote.origin.url'
cp.exec(cmd, function (err, stdout) {
info.version.source = (stdout && stdout.trim()) || ''
console.log(JSON.stringify(info, null, 2))
})
})

Просмотреть файл

@ -1,21 +0,0 @@
#!/usr/bin/env node
/* 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 path = require('path'),
spawn = require('child_process').spawn
var COVERAGE_ARGS = ['--coverage', '--cov']
if (process.env.NO_COVERAGE) {
COVERAGE_ARGS = []
}
var p = spawn(path.join(path.dirname(__dirname), 'node_modules', '.bin', 'tap'),
process.argv.slice(2).concat(COVERAGE_ARGS), { stdio: 'inherit', env: process.env })
// exit this process with the same exit code as the test process
p.on('close', function (code) {
process.exit(code)
})

Просмотреть файл

@ -1,40 +0,0 @@
/* 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 sinon = require('sinon')
var tap = require('tap')
var test = tap.test
var legacyLog = require('../../legacy_log')
var spyLog = {
critical: sinon.spy(),
debug: sinon.spy(),
error: sinon.spy(),
info: sinon.spy(),
warn: sinon.spy()
}
test('legacy_log unit tests', function (t) {
var data = {
op: 'testOp',
err: 'Nooo!'
}
var log = legacyLog(spyLog)
log.trace(data)
t.equal(spyLog.debug.args[0][0], data.op)
t.equal(spyLog.debug.args[0][1], data)
log.error(data)
t.equal(spyLog.error.args[0][0], data.op)
t.equal(spyLog.error.args[0][1], data)
log.fatal(data)
t.equal(spyLog.critical.args[0][0], data.op)
t.equal(spyLog.critical.args[0][1], data)
log.warn(data)
t.equal(spyLog.warn.args[0][0], data.op)
t.equal(spyLog.warn.args[0][1], data)
log.info(data)
t.equal(spyLog.info.args[0][0], data.op)
t.equal(spyLog.info.args[0][1], data)
t.done()
})

Просмотреть файл

@ -1,257 +0,0 @@
/* 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 tap = require('tap')
var test = tap.test
var sinon = require('sinon')
var proxyquire = require('proxyquire')
var Pool, poolee
test(
'pool.request with default options',
function (t) {
setup()
var pool = new Pool('http://example.com/ignore/me')
pool.request()
t.equal(poolee.request.callCount, 1, 'poolee.request was called once')
var args = poolee.request.getCall(0).args
t.equal(args.length, 2, 'poolee.request was passed two arguments')
var options = args[0]
t.equal(typeof options, 'object', 'options is object')
t.equal(Object.keys(options).length, 4, 'options has 4 properties')
t.equal(options.method, 'GET', 'options.method is GET')
t.equal(options.path, undefined, 'options.path is undefined')
t.equal(typeof options.headers, 'object', 'options.headers is object')
t.equal(Object.keys(options.headers).length, 1, 'options.headers has 1 property')
t.equal(options.headers['Content-Type'], 'application/json', 'Content-Type header is application/json')
t.equal(options.data, undefined, 'options.data is undefined')
var callback = args[1]
t.equal(typeof callback, 'function', 'callback is function')
t.end()
}
)
test(
'pool.request with alternative options',
function (t) {
setup()
var pool = new Pool('http://example.com/')
pool.request('POST', '/foo', { bar: 'baz' })
t.equal(poolee.request.callCount, 1, 'poolee.request was called once')
var args = poolee.request.getCall(0).args
t.equal(args.length, 2, 'poolee.request was passed two arguments')
var options = args[0]
t.equal(typeof options, 'object', 'options is object')
t.equal(Object.keys(options).length, 4, 'options has 4 properties')
t.equal(options.method, 'POST', 'options.method is POST')
t.equal(options.path, '/foo', 'options.path is /foo')
t.equal(typeof options.headers, 'object', 'options.headers is object')
t.equal(Object.keys(options.headers).length, 1, 'options.headers has 1 property')
t.equal(options.headers['Content-Type'], 'application/json', 'Content-Type header is application/json')
t.equal(options.data, '{"bar":"baz"}', 'options.data is correct')
var callback = args[1]
t.equal(typeof callback, 'function', 'callback is function')
t.end()
}
)
test(
'pool.request callback with error',
function (t) {
setup()
var pool = new Pool('http://example.com/')
pool.request()
.then(function () {
t.fail('request should have failed')
t.end()
}, function (error) {
t.equal(typeof error, 'string', 'error is string')
t.equal(error, 'foo', 'error is correct')
t.end()
})
var args = poolee.request.getCall(0).args
var callback = args[1]
callback('foo')
}
)
test(
'pool.request callback with HTTP error response',
function (t) {
setup()
var pool = new Pool('http://example.com/')
pool.request()
.then(function () {
t.fail('request should have failed')
t.end()
}, function (error) {
t.ok(error instanceof Error, 'error is Error instance')
t.equal(error.statusCode, 404, 'error.statusCode is 404')
t.equal(error.message, 'wibble', 'error.message is correct')
t.end()
})
var args = poolee.request.getCall(0).args
var callback = args[1]
callback(null, { statusCode: 404 }, 'wibble')
}
)
test(
'pool.request callback with HTTP error response and JSON body',
function (t) {
setup()
var pool = new Pool('http://example.com/')
pool.request()
.then(function () {
t.fail('request should have failed')
t.end()
}, function (error) {
t.equal(error instanceof Error, false, 'error is not Error instance')
t.equal(typeof error, 'object', 'error is object')
t.equal(Object.keys(error).length, 2, 'error has two properties')
t.equal(error.statusCode, 418, 'error.statusCode is 418')
t.equal(error.foo, 'bar', 'other error data is correct')
t.end()
})
var args = poolee.request.getCall(0).args
var callback = args[1]
callback(null, { statusCode: 418 }, '{"foo":"bar"}')
}
)
test(
'pool.request callback with HTTP success response and empty body',
function (t) {
setup()
var pool = new Pool('http://example.com/')
pool.request()
.then(function (result) {
t.equal(result, undefined, 'result is undefined')
t.end()
}, function () {
t.fail('request should have succeeded')
t.end()
})
var args = poolee.request.getCall(0).args
var callback = args[1]
callback(null, { statusCode: 200 }, '')
}
)
test(
'pool.request callback with HTTP success response and valid JSON body',
function (t) {
setup()
var pool = new Pool('http://example.com/')
pool.request()
.then(function (result) {
t.equal(typeof result, 'object', 'result is object')
t.equal(Object.keys(result).length, 1, 'result has 1 property')
t.equal(result.foo, 'bar', 'result data is correct')
t.end()
}, function () {
t.fail('request should have succeeded')
t.end()
})
var args = poolee.request.getCall(0).args
var callback = args[1]
callback(null, { statusCode: 200 }, '{"foo":"bar"}')
}
)
test(
'pool.request callback with HTTP success response and invalid JSON body',
function (t) {
setup()
var pool = new Pool('http://example.com/')
pool.request()
.then(function () {
t.fail('request should have failed')
t.end()
}, function (error) {
t.ok(error instanceof Error, 'error is Error instance')
t.equal(error.statusCode, undefined, 'error.statusCode is undefined')
t.equal(error.message, 'Invalid JSON', 'error.message is correct')
t.end()
})
var args = poolee.request.getCall(0).args
var callback = args[1]
callback(null, { statusCode: 200 }, 'foo')
}
)
test(
'pool.get',
function (t) {
setup()
var pool = new Pool('http://example.com/')
sinon.stub(pool, 'request', function () {})
pool.get('foo')
t.equal(pool.request.callCount, 1, 'pool.request was called once')
var args = pool.request.getCall(0).args
t.equal(args.length, 2, 'pool.request was passed three arguments')
t.equal(args[0], 'GET', 'first argument to pool.request was POST')
t.equal(args[1], 'foo', 'second argument to pool.request was correct')
t.end()
}
)
test(
'pool.put',
function (t) {
setup()
var pool = new Pool('http://example.com/')
sinon.stub(pool, 'request', function () {})
pool.put('baz', 'qux')
t.equal(pool.request.callCount, 1, 'pool.request was called once')
var args = pool.request.getCall(0).args
t.equal(args.length, 3, 'pool.request was passed three arguments')
t.equal(args[0], 'PUT', 'first argument to pool.request was POST')
t.equal(args[1], 'baz', 'second argument to pool.request was correct')
t.equal(args[2], 'qux', 'third argument to pool.request was correct')
t.end()
}
)
function setup () {
poolee = sinon.createStubInstance(require('poolee'))
Pool = proxyquire('../../lib/pool', {
poolee: function () {
return poolee
}
})
}

Просмотреть файл

@ -1,144 +0,0 @@
/* 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/. */
'use strict'
const P = require('bluebird')
const proxyquire = require('proxyquire')
const sinon = require('sinon')
const test = require('tap').test
const log = {
error: sinon.spy(),
info: sinon.spy(),
trace: sinon.spy()
}
let nexmoStatus = '0'
const sendSms = sinon.spy((from, to, message, callback) => {
callback(null, {
message_count: '1',
messages: [
{
to: to.substr(1),
'message-id': 'foo',
status: nexmoStatus,
'error-text': 'bar',
'remaining-balance': '42',
'message-price': '1',
'network': 'baz'
}
]
})
})
function Nexmo () {}
Nexmo.prototype.message = { sendSms }
P.all([
require('../../translator')(['en'], 'en'),
require('../../templates')()
]).spread((translator, templates) => {
const sms = proxyquire('../../lib/sms', {
nexmo: Nexmo
})(log, translator, templates, {
apiKey: 'foo',
apiSecret: 'bar',
installFirefoxLink: 'https://baz/qux'
})
test('interface is correct', t => {
t.equal(typeof sms.send, 'function', 'sms.send is function')
t.equal(sms.send.length, 4, 'sms.send expects 4 arguments')
t.equal(Object.keys(sms).length, 1, 'sms has no other methods')
t.done()
})
test('send a valid sms', t => {
t.plan(13)
return sms.send('+442078553000', 'Firefox', 1, 'en')
.then(() => {
t.equal(sendSms.callCount, 1, 'nexmo.message.sendSms was called once')
const args = sendSms.args[0]
t.equal(args.length, 4, 'nexmo.message.sendSms was passed four arguments')
t.equal(args[0], 'Firefox', 'nexmo.message.sendSms was passed the correct sender id')
t.equal(args[1], '+442078553000', 'nexmo.message.sendSms was passed the correct phone number')
t.equal(args[2], 'As requested, here is a link to install Firefox on your mobile device: https://baz/qux', 'nexmo.message.sendSms was passed the correct message')
t.equal(typeof args[3], 'function', 'nexmo.message.sendSms was passed a callback function')
t.equal(log.trace.callCount, 1, 'log.trace was called once')
t.equal(log.trace.args[0].length, 1, 'log.trace was passed one argument')
t.deepEqual(log.trace.args[0][0], {
op: 'sms.send',
senderId: 'Firefox',
messageId: 1,
acceptLanguage: 'en'
}, 'log.info was passed the correct data')
t.equal(log.info.callCount, 1, 'log.info was called once')
t.equal(log.info.args[0].length, 1, 'log.info was passed one argument')
t.deepEqual(log.info.args[0][0], {
op: 'sms.send.success',
senderId: 'Firefox',
messageId: 1,
acceptLanguage: 'en'
}, 'log.info was passed the correct data')
t.equal(log.error.callCount, 0, 'log.error was not called')
})
.finally(() => {
sendSms.reset()
log.trace.reset()
log.info.reset()
})
})
test('try to send an sms with an invalid message id', t => {
t.plan(7)
return sms.send('+442078553000', 'Firefox', 2, 'en')
.then(() => t.notOk(true, 'sms.send should have rejected'))
.catch(error => {
t.equal(error.status, 400, 'error.statusCode was set correctly')
t.equal(error.message, 'Invalid message id', 'error.message was set correctly')
t.equal(log.trace.callCount, 1, 'log.trace was called once')
t.equal(log.info.callCount, 0, 'log.info was not called')
t.equal(log.error.callCount, 1, 'log.error was called once')
t.deepEqual(log.error.args[0][0], {
op: 'sms.send',
err: error.message
}, 'log.error was passed the correct data')
t.equal(sendSms.callCount, 0, 'nexmo.message.sendSms was not called')
})
.finally(() => {
log.trace.reset()
log.error.reset()
})
})
test('send an sms that is rejected by the network provider', t => {
t.plan(7)
nexmoStatus = '1'
return sms.send('+442078553000', 'Firefox', 1, 'en')
.then(() => t.notOk(true, 'sms.send should have rejected'))
.catch(error => {
t.equal(error.status, 500, 'error.statusCode was set correctly')
t.equal(error.message, 'Message rejected', 'error.message was set correctly')
t.equal(error.reason, 'bar', 'error.reason was set correctly')
t.equal(error.reasonCode, '1', 'error.reasonCode was set correctly')
t.equal(log.trace.callCount, 1, 'log.trace was called once')
t.equal(log.info.callCount, 0, 'log.info was not called')
t.equal(sendSms.callCount, 1, 'nexmo.message.sendSms was called once')
})
.finally(() => {
log.trace.reset()
sendSms.reset()
log.error.reset()
})
})
})

Просмотреть файл

@ -1,23 +0,0 @@
var test = require('tap').test
require('../../translator')(['en', 'pt_br', 'DE', 'ES_AR', 'ES_cl'], 'en')
.done(
function (translator) {
test(
'translator works with upper and lowercase languages',
function (t) {
var x = translator('PT-br,DE')
t.equal(x.language, 'pt-BR')
x = translator('bu-ll,es-ar')
t.equal(x.language, 'es-AR')
x = translator('es-CL')
t.equal(x.language, 'es-CL')
x = translator('en-US')
t.equal(x.language, 'en')
x = translator('db-LB') // a locale that does not exist
t.equal(x.language, 'en')
t.end()
}
)
}
)

4376
npm-shrinkwrap.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -9,9 +9,9 @@
"test": "test"
},
"scripts": {
"prepush": "grunt quicklint && cd mailer && npm run prepush",
"postinstall": "cd mailer && npm install",
"shrinkwrap": "npmshrink",
"prepush": "grunt quicklint && grunt templates && git status -s | (! grep 'M lib/senders/templates/')",
"postinstall": "scripts/download_l10n.sh",
"shrinkwrap": "npmshrink && npm run postinstall",
"start": "NODE_ENV=dev scripts/start-local.sh 2>&1",
"start-mysql": "NODE_ENV=dev scripts/start-local-mysql.sh 2>&1",
"test": "NODE_ENV=dev CORS_ORIGIN=http://foo,http://bar scripts/test-local.sh",
@ -39,27 +39,36 @@
"binary-split": "0.1.2",
"bluebird": "2.10.2",
"buffer-equal-constant-time": "1.0.1",
"convict": "1.5.0",
"convict": "2.0.0",
"email-addresses": "2.0.2",
"envc": "2.4.0",
"fxa-geodb": "0.0.7",
"fxa-jwtool": "0.7.1",
"fxa-shared": "1.0.3",
"fxa-shared": "1.0.4",
"google-libphonenumber": "2.0.10",
"grunt-nunjucks-2-html": "vitkarpov/grunt-nunjucks-2-html#1900f91a756b2eaf900b20",
"handlebars": "4.0.6",
"hapi": "14.2.0",
"hapi-auth-hawk": "3.0.1",
"hapi-fxa-oauth": "2.2.0",
"hapi-hpkp": "git+https://github.com/vbudhram/hapi-hpkp.git#master",
"hkdf": "0.0.2",
"i18n-abide": "0.0.25",
"inert": "4.0.2",
"jed": "0.5.4",
"joi": "9.0.4",
"memcached": "2.2.2",
"mozlog": "2.0.5",
"moment-timezone": "0.5.11",
"mozlog": "2.0.6",
"newrelic": "1.30.1",
"nexmo": "1.2.0",
"node-statsd": "0.1.1",
"node-uap": "git+https://github.com/vladikoff/node-uap.git#9cdd16247",
"nodemailer": "2.7.2",
"po2json": "0.4.5",
"poolee": "1.0.1",
"request": "2.74.0",
"request": "2.79.0",
"restify": "4.3.0",
"scrypt-hash": "1.1.14",
"through": "2.3.8",
"uuid": "1.4.1",
@ -72,18 +81,22 @@
"fxa-conventional-changelog": "1.1.0",
"grunt": "1.0.1",
"grunt-bump": "0.8.0",
"grunt-cli": "1.2.0",
"grunt-contrib-copy": "1.0.0",
"grunt-conventional-changelog": "6.1.0",
"grunt-copyright": "0.3.0",
"grunt-eslint": "19.0.0",
"grunt-newer": "1.2.0",
"grunt-nsp": "2.3.1",
"hawk": "2.3.1",
"husky": "0.11.7",
"husky": "0.13.1",
"insist": "1.0.0",
"jsxgettext-recursive": "0.0.5",
"jws": "3.1.3",
"leftpad": "0.0.0",
"load-grunt-tasks": "3.5.2",
"mailparser": "0.6.1",
"mkdirp": "0.5.1",
"mocha": "3.1.2",
"nock": "8.0.0",
"npmshrink": "1.0.1",

Просмотреть файл

@ -1,6 +1,7 @@
{
"plugins": ["fxa"],
"rules": {
"handle-callback-err": 0,
"no-console": 0,
"fxa/async-crypto-random": 0,
"fxa/no-new-buffer": 2

Просмотреть файл

Просмотреть файл

@ -27,6 +27,8 @@ require('../lib/senders')(config, log)
let message = error.message
if (error.reason && error.reasonCode) {
message = `${message}: ${error.reasonCode} ${error.reason}`
} else if (error.stack) {
message = error.stack
}
fail(message)
})

Просмотреть файл

@ -28,9 +28,9 @@
var P = require('bluebird')
var config = require('../config')
const createSenders = require('../index')
const createSenders = require('../lib/senders')
var fs = require('fs')
const log = require('../legacy_log')(require('../log')('server'))
const log = require('../lib/senders/legacy_log')(require('../lib/senders/log')('server'))
var mkdirp = require('mkdirp')
var path = require('path')
@ -53,7 +53,7 @@ var mailSender = {
}
createSenders(log, config.getProperties(), mailSender)
createSenders(config.getProperties(), log, mailSender)
.then((senders) => {
const mailer = senders.email
checkMessageType(mailer, messageToSend)

Просмотреть файл

@ -2,9 +2,10 @@
* 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/. */
const ROOT_DIR = '../../../..'
const assert = require('insist')
var P = require('bluebird')
var tap = require('tap')
var test = tap.test
var proxyquire = require('proxyquire')
var dbConnect
@ -27,11 +28,11 @@ var mockConfig = {
}
}
test(
it(
'keeps polling until time limit',
function (t) {
dbConnect = proxyquire('../../lib/db_connect', {
'../log': mockLog,
function () {
dbConnect = proxyquire(`${ROOT_DIR}/lib/senders/db_connect`, {
'./log': mockLog,
'./db': function () {
return {
connect: function() {
@ -39,26 +40,25 @@ test(
}
}
},
'../config': mockConfig
'../../mailer/config': mockConfig
})()
dbConnect()
return dbConnect()
.catch(function (err) {
t.equal(err.name, 'TimeoutError')
t.equal(err.message, 'operation timed out')
t.end()
assert.equal(err.name, 'TimeoutError')
assert.equal(err.message, 'operation timed out')
})
}
)
test(
it(
'connects to db after polling',
function (t) {
function () {
var dbConnectedMs = 30
var testStart = Date.now()
dbConnect = proxyquire('../../lib/db_connect', {
'../log': mockLog,
dbConnect = proxyquire(`${ROOT_DIR}/lib/senders/db_connect`, {
'./log': mockLog,
'./db': function () {
return {
connect: function() {
@ -73,13 +73,12 @@ test(
}
}
},
'../config': mockConfig
'../../mailer/config': mockConfig
})()
dbConnect()
return dbConnect()
.then(function (db) {
t.equal(db.name, 'TestDB')
t.end()
assert.equal(db.name, 'TestDB')
})
}
)

Просмотреть файл

@ -2,11 +2,14 @@
* 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 extend = require('util')._extend
'use strict'
const ROOT_DIR = '../../../..'
const assert = require('insist')
var extend = require('util')._extend
var sinon = require('sinon')
var P = require('bluebird')
var test = require('tap').test
var nullLog = {
trace: function () {},
@ -14,8 +17,8 @@ var nullLog = {
error: function () {}
}
var config = require('../../config')
var Mailer = require('../../mailer')(nullLog)
var config = require(`${ROOT_DIR}/mailer/config`)
var Mailer = require(`${ROOT_DIR}/lib/senders/email`)(nullLog)
var messageTypes = [
'newDeviceLoginEmail',
@ -99,19 +102,22 @@ function sesMessageTagsHeaderValue(templateName) {
return 'messageType=fxa-' + templateName + ', app=fxa'
}
P.all(
[
require('../../translator')(['en'], 'en'),
require('../../templates')()
]
)
.spread(
function (translator, templates) {
describe(
'lib/senders/email:',
() => {
let mailer
before(() => {
return P.all([
require(`${ROOT_DIR}/lib/senders/translator`)(['en'], 'en'),
require(`${ROOT_DIR}/lib/senders/templates`)()
]).spread((translator, templates) => {
mailer = new Mailer(translator, templates, config.get('mail'))
})
})
messageTypes.forEach(
function (type) {
var mailer = new Mailer(translator, templates, config.get('mail'))
var message = {
code: 'abc123',
email: 'a@b.com',
@ -123,83 +129,78 @@ P.all(
flowBeginTime: Date.now()
}
test(
it(
'Contains template header for ' + type,
function (t) {
function () {
mailer.mailer.sendMail = function (emailConfig) {
var templateName = emailConfig.headers['X-Template-Name']
if (type === 'verificationReminderEmail') {
// Handle special case for verification reminders
t.equal(templateName, 'verificationReminderFirstEmail' || 'verificationReminderSecondEmail')
assert.equal(templateName, 'verificationReminderFirstEmail' || 'verificationReminderSecondEmail')
} else if (type === 'verifyEmail') {
// Handle special case for verify email
t.equal(templateName, 'verifySyncEmail')
assert.equal(templateName, 'verifySyncEmail')
} else {
t.equal(templateName, type)
assert.equal(templateName, type)
}
t.end()
}
mailer[type](message)
}
)
test(
it(
'Contains flow headers for ' + type,
function (t) {
function () {
if (type !== 'verificationReminderEmail') {
mailer.mailer.sendMail = function (emailConfig) {
var flowIdHeader = emailConfig.headers['X-Flow-Id']
t.equal(flowIdHeader, message.flowId)
assert.equal(flowIdHeader, message.flowId)
var flowBeginHeader = emailConfig.headers['X-Flow-Begin-Time']
t.equal(flowBeginHeader, message.flowBeginTime)
assert.equal(flowBeginHeader, message.flowBeginTime)
}
mailer[type](message)
}
t.end()
}
)
test(
it(
'test privacy link is in email template output for ' + type,
function (t) {
function () {
var privacyLink = mailer.createPrivacyLink(type)
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, privacyLink))
t.ok(includes(emailConfig.text, privacyLink))
t.end()
assert.ok(includes(emailConfig.html, privacyLink))
assert.ok(includes(emailConfig.text, privacyLink))
}
mailer[type](message)
}
)
test(
it(
'If sesConfigurationSet is not defined, then outgoing email does not contain X-SES* headers, for type ' + type,
function (t) {
function () {
mailer.mailer.sendMail = function (emailConfig) {
var sesConfigurationSetHeader = emailConfig.headers['X-SES-CONFIGURATION-SET']
t.ok(! sesConfigurationSetHeader)
assert.ok(! sesConfigurationSetHeader)
var sesMessageTags = emailConfig.headers['X-SES-MESSAGE-TAGS']
t.ok(! sesMessageTags)
t.end()
assert.ok(! sesMessageTags)
}
mailer[type](message) // invoke
}
)
test(
it(
'If sesConfigurationSet is defined, then outgoing email will contain X-SES* headers, for type ' + type,
function (t) {
function () {
var savedSesConfigurationSet = mailer.sesConfigurationSet
mailer.sesConfigurationSet = 'some-defined-value'
mailer.mailer.sendMail = function (emailConfig) {
var sesConfigurationSetHeader = emailConfig.headers['X-SES-CONFIGURATION-SET']
t.equal(sesConfigurationSetHeader, 'some-defined-value')
assert.equal(sesConfigurationSetHeader, 'some-defined-value')
var sesMessageTags = emailConfig.headers['X-SES-MESSAGE-TAGS']
var expectedSesMessageTags = sesMessageTagsHeaderValue(type)
@ -209,10 +210,9 @@ P.all(
expectedSesMessageTags = sesMessageTagsHeaderValue('verificationReminderSecondEmail')
}
}
t.equal(sesMessageTags, expectedSesMessageTags)
assert.equal(sesMessageTags, expectedSesMessageTags)
mailer.sesConfigurationSet = savedSesConfigurationSet
t.end()
}
mailer[type](message) // invoke
@ -220,15 +220,14 @@ P.all(
)
if (includes(typesContainSupportLinks, type)) {
test(
it(
'test support link is in email template output for ' + type,
function (t) {
function () {
var supportTextLink = mailer.createSupportLink(type)
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, supportTextLink))
t.ok(includes(emailConfig.text, supportTextLink))
t.end()
assert.ok(includes(emailConfig.html, supportTextLink))
assert.ok(includes(emailConfig.text, supportTextLink))
}
mailer[type](message)
}
@ -236,15 +235,14 @@ P.all(
}
if (includes(typesContainPasswordResetLinks, type)) {
var resetPasswordLink = mailer.createPasswordResetLink(message.email, type)
test(
it(
'reset password link is in email template output for ' + type,
function (t) {
function () {
var resetPasswordLink = mailer.createPasswordResetLink(message.email, type)
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, resetPasswordLink))
t.ok(includes(emailConfig.text, resetPasswordLink))
t.end()
assert.ok(includes(emailConfig.html, resetPasswordLink))
assert.ok(includes(emailConfig.text, resetPasswordLink))
}
mailer[type](message)
}
@ -252,14 +250,14 @@ P.all(
}
if (includes(typesContainPasswordChangeLinks, type)) {
var passwordChangeLink = mailer.createPasswordChangeLink(message.email, type)
test(
it(
'password change link is in email template output for ' + type,
function (t) {
function () {
var passwordChangeLink = mailer.createPasswordChangeLink(message.email, type)
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, passwordChangeLink))
t.ok(includes(emailConfig.text, passwordChangeLink))
t.end()
assert.ok(includes(emailConfig.html, passwordChangeLink))
assert.ok(includes(emailConfig.text, passwordChangeLink))
}
mailer[type](message)
}
@ -267,14 +265,12 @@ P.all(
}
if (includes(typesContainUnblockCode, type)) {
test(
it(
'unblock code is in email template output for ' + type,
function (t) {
function () {
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, message.unblockCode))
t.ok(includes(emailConfig.text, message.unblockCode))
t.end()
assert.ok(includes(emailConfig.html, message.unblockCode))
assert.ok(includes(emailConfig.text, message.unblockCode))
}
mailer[type](message)
}
@ -282,16 +278,14 @@ P.all(
}
if (includes(typesContainReportSignInLinks, type)) {
test(
it(
'report sign-in link is in email template output for ' + type,
function (t) {
function () {
mailer.mailer.sendMail = function (emailConfig) {
var reportSignInLink =
mailer.createReportSignInLink(type, message)
t.ok(includes(emailConfig.html, reportSignInLink))
t.ok(includes(emailConfig.text, reportSignInLink))
t.end()
assert.ok(includes(emailConfig.html, reportSignInLink))
assert.ok(includes(emailConfig.text, reportSignInLink))
}
mailer[type](message)
}
@ -299,15 +293,14 @@ P.all(
}
if (includes(typesContainAndroidStoreLinks, type)) {
var androidStoreLink = mailer.androidUrl
test(
it(
'Android store link is in email template output for ' + type,
function (t) {
function () {
var androidStoreLink = mailer.androidUrl
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, androidStoreLink))
assert.ok(includes(emailConfig.html, androidStoreLink))
// only the html email contains links to the store
t.end()
}
mailer[type](message)
}
@ -315,15 +308,14 @@ P.all(
}
if (includes(typesContainIOSStoreLinks, type)) {
var iosStoreLink = mailer.iosUrl
test(
it(
'IOS store link is in email template output for ' + type,
function (t) {
function () {
var iosStoreLink = mailer.iosUrl
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, iosStoreLink))
assert.ok(includes(emailConfig.html, iosStoreLink))
// only the html email contains links to the store
t.end()
}
mailer[type](message)
}
@ -331,15 +323,14 @@ P.all(
}
if (includes(typesContainPasswordManagerInfoLinks, type)) {
var passwordManagerInfoUrl = mailer._generateLinks(config.get('mail').passwordManagerInfoUrl, message.email, {}, type).passwordManagerInfoUrl
test(
it(
'password manager info link is in email template output for ' + type,
function (t) {
function () {
var passwordManagerInfoUrl = mailer._generateLinks(config.get('mail').passwordManagerInfoUrl, message.email, {}, type).passwordManagerInfoUrl
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, passwordManagerInfoUrl))
t.ok(includes(emailConfig.text, passwordManagerInfoUrl))
t.end()
assert.ok(includes(emailConfig.html, passwordManagerInfoUrl))
assert.ok(includes(emailConfig.text, passwordManagerInfoUrl))
}
mailer[type](message)
}
@ -354,72 +345,68 @@ P.all(
stateCode: 'CA'
}
test(
it(
'ip data is in template for ' + type,
function (t) {
function () {
var message = getLocationMessage(defaultLocation)
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, message.ip))
assert.ok(includes(emailConfig.html, message.ip))
t.ok(includes(emailConfig.text, message.ip))
t.end()
assert.ok(includes(emailConfig.text, message.ip))
}
mailer[type](message)
}
)
test(
it(
'location is correct with city, country, stateCode for ' + type,
function (t) {
function () {
var location = defaultLocation
var message = getLocationMessage(defaultLocation)
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, location.city + ', ' + location.stateCode + ', ' + location.country))
t.ok(includes(emailConfig.text, location.city + ', ' + location.stateCode + ', ' + location.country))
t.end()
assert.ok(includes(emailConfig.html, location.city + ', ' + location.stateCode + ', ' + location.country))
assert.ok(includes(emailConfig.text, location.city + ', ' + location.stateCode + ', ' + location.country))
}
mailer[type](message)
}
)
test(
it(
'location is correct with city, country for ' + type,
function (t) {
function () {
var location = extend({}, defaultLocation)
delete location.stateCode
var message = getLocationMessage(location)
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, location.city + ', ' + location.country))
t.ok(includes(emailConfig.text, location.city + ', ' + location.country))
t.end()
assert.ok(includes(emailConfig.html, location.city + ', ' + location.country))
assert.ok(includes(emailConfig.text, location.city + ', ' + location.country))
}
mailer[type](message)
}
)
test(
it(
'location is correct with stateCode, country for ' + type,
function (t) {
function () {
var location = extend({}, defaultLocation)
delete location.city
var message = getLocationMessage(location)
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, location.stateCode + ', ' + location.country))
t.ok(includes(emailConfig.text, location.stateCode + ', ' + location.country))
t.end()
assert.ok(includes(emailConfig.html, location.stateCode + ', ' + location.country))
assert.ok(includes(emailConfig.text, location.stateCode + ', ' + location.country))
}
mailer[type](message)
}
)
test(
it(
'location is correct with country for ' + type,
function (t) {
function () {
var location = extend({}, defaultLocation)
delete location.city
delete location.stateCode
@ -427,9 +414,8 @@ P.all(
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, location.country))
t.ok(includes(emailConfig.text, location.country))
t.end()
assert.ok(includes(emailConfig.html, location.country))
assert.ok(includes(emailConfig.text, location.country))
}
mailer[type](message)
}
@ -438,32 +424,29 @@ P.all(
}
if (type === 'verifyLoginEmail') {
test(
it(
'test verify token email',
function (t) {
function () {
mailer.mailer.sendMail = function (emailConfig) {
var verifyLoginUrl = config.get('mail').verifyLoginUrl
t.ok(emailConfig.html.indexOf(verifyLoginUrl) > 0)
t.ok(emailConfig.text.indexOf(verifyLoginUrl) > 0)
t.end()
assert.ok(emailConfig.html.indexOf(verifyLoginUrl) > 0)
assert.ok(emailConfig.text.indexOf(verifyLoginUrl) > 0)
}
mailer[type](message)
}
)
} else if (type === 'postVerifyEmail') {
test(
it(
'test utm params for ' + type,
function (t) {
function () {
var syncLink = mailer._generateUTMLink(config.get('mail').syncUrl, {}, type, 'connect-device')
var androidLink = mailer._generateUTMLink(config.get('mail').androidUrl, {}, type, 'connect-android')
var iosLink = mailer._generateUTMLink(config.get('mail').iosUrl, {}, type, 'connect-ios')
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, syncLink))
t.ok(includes(emailConfig.html, androidLink))
t.ok(includes(emailConfig.html, iosLink))
t.end()
assert.ok(includes(emailConfig.html, syncLink))
assert.ok(includes(emailConfig.html, androidLink))
assert.ok(includes(emailConfig.html, iosLink))
}
mailer[type](message)
}
@ -473,13 +456,12 @@ P.all(
type: 'customType'
})
test(
it(
'custom reminder types are supported in output for ' + type,
function (t) {
function () {
mailer.mailer.sendMail = function (emailConfig) {
t.ok(includes(emailConfig.html, 'reminder=customType'))
t.ok(includes(emailConfig.text, 'reminder=customType'))
t.end()
assert.ok(includes(emailConfig.html, 'reminder=customType'))
assert.ok(includes(emailConfig.text, 'reminder=customType'))
}
mailer[type](reminderMessage)
}
@ -488,82 +470,77 @@ P.all(
}
)
test(
it(
'test user-agent info rendering',
function (t) {
var mailer = new Mailer(translator, templates, config.get('mail'))
t.equal(mailer._formatUserAgentInfo({
function () {
assert.equal(mailer._formatUserAgentInfo({
uaBrowser: 'Firefox',
uaBrowserVersion: '32',
uaOS: 'Windows',
uaOSVersion: '8.1'
}), 'Firefox on Windows 8.1')
t.equal(mailer._formatUserAgentInfo({
assert.equal(mailer._formatUserAgentInfo({
uaBrowser: 'Chrome',
uaBrowserVersion: undefined,
uaOS: 'Windows',
uaOSVersion: '10',
}), 'Chrome on Windows 10')
t.equal(mailer._formatUserAgentInfo({
assert.equal(mailer._formatUserAgentInfo({
uaBrowser: undefined,
uaBrowserVersion: '12',
uaOS: 'Windows',
uaOSVersion: '10'
}), 'Windows 10')
t.equal(mailer._formatUserAgentInfo({
assert.equal(mailer._formatUserAgentInfo({
uaBrowser: 'MSIE',
uaBrowserVersion: '6',
uaOS: 'Linux',
uaOSVersion: '9'
}), 'MSIE on Linux 9')
t.equal(mailer._formatUserAgentInfo({
assert.equal(mailer._formatUserAgentInfo({
uaBrowser: 'MSIE',
uaBrowserVersion: undefined,
uaOS: 'Linux',
uaOSVersion: undefined
}), 'MSIE on Linux')
t.equal(mailer._formatUserAgentInfo({
assert.equal(mailer._formatUserAgentInfo({
uaBrowser: 'MSIE',
uaBrowserVersion: '8',
uaOS: undefined,
uaOSVersion: '4'
}), 'MSIE')
t.equal(mailer._formatUserAgentInfo({
assert.equal(mailer._formatUserAgentInfo({
uaBrowser: 'MSIE',
uaBrowserVersion: undefined,
uaOS: undefined,
uaOSVersion: undefined
}), 'MSIE')
t.equal(mailer._formatUserAgentInfo({
assert.equal(mailer._formatUserAgentInfo({
uaBrowser: undefined,
uaBrowserVersion: undefined,
uaOS: 'Windows',
uaOSVersion: undefined
}), 'Windows')
t.equal(mailer._formatUserAgentInfo({
assert.equal(mailer._formatUserAgentInfo({
uaBrowser: undefined,
uaBrowserVersion: undefined,
uaOS: undefined,
uaOSVersion: undefined
}), '')
t.end()
}
)
test(
it(
'resolves sendMail status',
function (t) {
var mailer = new Mailer(translator, templates, config.get('mail'))
function () {
sinon.stub(mailer.mailer, 'sendMail', function (config, cb) {
cb(null, { resp: 'ok' })
})
@ -577,19 +554,15 @@ P.all(
return mailer.send(message)
.then(function (status) {
t.equal(status.resp, 'ok')
t.done()
assert.equal(status.resp, 'ok')
})
}
)
test(
it(
'rejects sendMail status',
function (t) {
var mailer = new Mailer(translator, templates, config.get('mail'))
sinon.stub(mailer.mailer, 'sendMail', function (config, cb) {
cb(new Error('Fail'))
})
function () {
mailer.mailer.sendMail.reset()
var message = {
email: 'test@restmail.net',
@ -599,9 +572,8 @@ P.all(
}
return mailer.send(message)
.then(t.notOk, function (err) {
t.equal(err.message, 'Fail')
t.done()
.then(assert.notOk, function (err) {
assert.equal(err.message, 'Fail')
})
}
)

Просмотреть файл

@ -0,0 +1,38 @@
/* 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/. */
const assert = require('insist')
var sinon = require('sinon')
var legacyLog = require('../../../../lib/senders/legacy_log')
var spyLog = {
critical: sinon.spy(),
debug: sinon.spy(),
error: sinon.spy(),
info: sinon.spy(),
warn: sinon.spy()
}
it('legacy_log unit tests', function () {
var data = {
op: 'testOp',
err: 'Nooo!'
}
var log = legacyLog(spyLog)
log.trace(data)
assert.equal(spyLog.debug.args[0][0], data.op)
assert.equal(spyLog.debug.args[0][1], data)
log.error(data)
assert.equal(spyLog.error.args[0][0], data.op)
assert.equal(spyLog.error.args[0][1], data)
log.fatal(data)
assert.equal(spyLog.critical.args[0][0], data.op)
assert.equal(spyLog.critical.args[0][1], data)
log.warn(data)
assert.equal(spyLog.warn.args[0][0], data.op)
assert.equal(spyLog.warn.args[0][1], data)
log.info(data)
assert.equal(spyLog.info.args[0][0], data.op)
assert.equal(spyLog.info.args[0][1], data)
})

Просмотреть файл

@ -0,0 +1,248 @@
/* 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/. */
const assert = require('insist')
var sinon = require('sinon')
var proxyquire = require('proxyquire')
var Pool, poolee
it(
'pool.request with default options',
function () {
setup()
var pool = new Pool('http://example.com/ignore/me')
pool.request()
assert.equal(poolee.request.callCount, 1, 'poolee.request was called once')
var args = poolee.request.getCall(0).args
assert.equal(args.length, 2, 'poolee.request was passed two arguments')
var options = args[0]
assert.equal(typeof options, 'object', 'options is object')
assert.equal(Object.keys(options).length, 4, 'options has 4 properties')
assert.equal(options.method, 'GET', 'options.method is GET')
assert.equal(options.path, undefined, 'options.path is undefined')
assert.equal(typeof options.headers, 'object', 'options.headers is object')
assert.equal(Object.keys(options.headers).length, 1, 'options.headers has 1 property')
assert.equal(options.headers['Content-Type'], 'application/json', 'Content-Type header is application/json')
assert.equal(options.data, undefined, 'options.data is undefined')
var callback = args[1]
assert.equal(typeof callback, 'function', 'callback is function')
}
)
it(
'pool.request with alternative options',
function () {
setup()
var pool = new Pool('http://example.com/')
pool.request('POST', '/foo', { bar: 'baz' })
assert.equal(poolee.request.callCount, 1, 'poolee.request was called once')
var args = poolee.request.getCall(0).args
assert.equal(args.length, 2, 'poolee.request was passed two arguments')
var options = args[0]
assert.equal(typeof options, 'object', 'options is object')
assert.equal(Object.keys(options).length, 4, 'options has 4 properties')
assert.equal(options.method, 'POST', 'options.method is POST')
assert.equal(options.path, '/foo', 'options.path is /foo')
assert.equal(typeof options.headers, 'object', 'options.headers is object')
assert.equal(Object.keys(options.headers).length, 1, 'options.headers has 1 property')
assert.equal(options.headers['Content-Type'], 'application/json', 'Content-Type header is application/json')
assert.equal(options.data, '{"bar":"baz"}', 'options.data is correct')
var callback = args[1]
assert.equal(typeof callback, 'function', 'callback is function')
}
)
it(
'pool.request callback with error',
function (done) {
setup()
var pool = new Pool('http://example.com/')
pool.request()
.then(function () {
assert.fail('request should have failed')
done()
}, function (error) {
assert.equal(typeof error, 'string', 'error is string')
assert.equal(error, 'foo', 'error is correct')
done()
})
var args = poolee.request.getCall(0).args
var callback = args[1]
callback('foo')
}
)
it(
'pool.request callback with HTTP error response',
function (done) {
setup()
var pool = new Pool('http://example.com/')
pool.request()
.then(function () {
assert.fail('request should have failed')
done()
}, function (error) {
assert.ok(error instanceof Error, 'error is Error instance')
assert.equal(error.statusCode, 404, 'error.statusCode is 404')
assert.equal(error.message, 'wibble', 'error.message is correct')
done()
})
var args = poolee.request.getCall(0).args
var callback = args[1]
callback(null, { statusCode: 404 }, 'wibble')
}
)
it(
'pool.request callback with HTTP error response and JSON body',
function (done) {
setup()
var pool = new Pool('http://example.com/')
pool.request()
.then(function () {
assert.fail('request should have failed')
done()
}, function (error) {
assert.equal(error instanceof Error, false, 'error is not Error instance')
assert.equal(typeof error, 'object', 'error is object')
assert.equal(Object.keys(error).length, 2, 'error has two properties')
assert.equal(error.statusCode, 418, 'error.statusCode is 418')
assert.equal(error.foo, 'bar', 'other error data is correct')
done()
})
var args = poolee.request.getCall(0).args
var callback = args[1]
callback(null, { statusCode: 418 }, '{"foo":"bar"}')
}
)
it(
'pool.request callback with HTTP success response and empty body',
function (done) {
setup()
var pool = new Pool('http://example.com/')
pool.request()
.then(function (result) {
assert.equal(result, undefined, 'result is undefined')
done()
}, function () {
assert.fail('request should have succeeded')
done()
})
var args = poolee.request.getCall(0).args
var callback = args[1]
callback(null, { statusCode: 200 }, '')
}
)
it(
'pool.request callback with HTTP success response and valid JSON body',
function (done) {
setup()
var pool = new Pool('http://example.com/')
pool.request()
.then(function (result) {
assert.equal(typeof result, 'object', 'result is object')
assert.equal(Object.keys(result).length, 1, 'result has 1 property')
assert.equal(result.foo, 'bar', 'result data is correct')
done()
}, function () {
assert.fail('request should have succeeded')
done()
})
var args = poolee.request.getCall(0).args
var callback = args[1]
callback(null, { statusCode: 200 }, '{"foo":"bar"}')
}
)
it(
'pool.request callback with HTTP success response and invalid JSON body',
function (done) {
setup()
var pool = new Pool('http://example.com/')
pool.request()
.then(function () {
assert.fail('request should have failed')
done()
}, function (error) {
assert.ok(error instanceof Error, 'error is Error instance')
assert.equal(error.statusCode, undefined, 'error.statusCode is undefined')
assert.equal(error.message, 'Invalid JSON', 'error.message is correct')
done()
})
var args = poolee.request.getCall(0).args
var callback = args[1]
callback(null, { statusCode: 200 }, 'foo')
}
)
it(
'pool.get',
function () {
setup()
var pool = new Pool('http://example.com/')
sinon.stub(pool, 'request', function () {})
pool.get('foo')
assert.equal(pool.request.callCount, 1, 'pool.request was called once')
var args = pool.request.getCall(0).args
assert.equal(args.length, 2, 'pool.request was passed three arguments')
assert.equal(args[0], 'GET', 'first argument to pool.request was POST')
assert.equal(args[1], 'foo', 'second argument to pool.request was correct')
}
)
it(
'pool.put',
function () {
setup()
var pool = new Pool('http://example.com/')
sinon.stub(pool, 'request', function () {})
pool.put('baz', 'qux')
assert.equal(pool.request.callCount, 1, 'pool.request was called once')
var args = pool.request.getCall(0).args
assert.equal(args.length, 3, 'pool.request was passed three arguments')
assert.equal(args[0], 'PUT', 'first argument to pool.request was POST')
assert.equal(args[1], 'baz', 'second argument to pool.request was correct')
assert.equal(args[2], 'qux', 'third argument to pool.request was correct')
}
)
function setup () {
poolee = sinon.createStubInstance(require('poolee'))
Pool = proxyquire('../../../../lib/senders/pool', {
poolee: function () {
return poolee
}
})
}

Просмотреть файл

@ -2,12 +2,13 @@
* 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/. */
const ROOT_DIR = '../../../../'
const assert = require('insist')
var sinon = require('sinon')
var extend = require('util')._extend
var tap = require('tap')
var test = tap.test
var P = require('../../lib/promise')
var config = require('../../config')
var P = require(`${ROOT_DIR}/lib/promise`)
var config = require(`${ROOT_DIR}/mailer/config`)
var TEST_EMAIL = 'test@restmail.net'
var TEST_ACCOUNT_RECORD = {
@ -42,44 +43,44 @@ var mockLog = function(methods) {
return log
}
test('_processReminder sends first reminder for unverified emails', function (t) {
it('_processReminder sends first reminder for unverified emails', function () {
setup()
var legacyMailerLog = require('../../legacy_log')(mockLog())
var Mailer = require('../../mailer')(legacyMailerLog)
var legacyMailerLog = require(`${ROOT_DIR}/lib/senders/legacy_log`)(mockLog())
var Mailer = require(`${ROOT_DIR}/lib/senders/email`)(legacyMailerLog)
var mailer = new Mailer({}, {}, config.get('mail'))
sandbox.stub(mailer, 'send', function (vals) {
t.equal(vals.acceptLanguage, TEST_ACCOUNT_RECORD.locale, 'correct locale')
t.equal(vals.uid, TEST_ACCOUNT_RECORD.uid.toString('hex'), 'correct uid')
t.equal(vals.email, TEST_ACCOUNT_RECORD.email, 'correct email')
t.equal(vals.template, 'verificationReminderFirstEmail', 'correct template')
t.equal(vals.subject, 'Hello again.', 'correct subject')
t.equal(vals.headers['X-Verify-Code'], TEST_ACCOUNT_RECORD.emailCode.toString('hex'), 'correct code')
t.ok(vals.templateValues.link.indexOf(TEST_ACCOUNT_RECORD.emailCode.toString('hex')) >= 0, 'correct link')
done(t)
assert.equal(vals.acceptLanguage, TEST_ACCOUNT_RECORD.locale, 'correct locale')
assert.equal(vals.uid, TEST_ACCOUNT_RECORD.uid.toString('hex'), 'correct uid')
assert.equal(vals.email, TEST_ACCOUNT_RECORD.email, 'correct email')
assert.equal(vals.template, 'verificationReminderFirstEmail', 'correct template')
assert.equal(vals.subject, 'Hello again.', 'correct subject')
assert.equal(vals.headers['X-Verify-Code'], TEST_ACCOUNT_RECORD.emailCode.toString('hex'), 'correct code')
assert.ok(vals.templateValues.link.indexOf(TEST_ACCOUNT_RECORD.emailCode.toString('hex')) >= 0, 'correct link')
done()
})
require('../../lib/verification-reminders')(mailer, mockDb)
require(`${ROOT_DIR}/lib/senders/verification-reminders`)(mailer, mockDb)
._processReminder(SAMPLE_REMINDER)
})
test('_processReminder sends second reminder for unverified emails', function (t) {
it('_processReminder sends second reminder for unverified emails', function () {
setup()
var legacyMailerLog = require('../../legacy_log')(mockLog())
var Mailer = require('../../mailer')(legacyMailerLog)
var legacyMailerLog = require(`${ROOT_DIR}/lib/senders/legacy_log`)(mockLog())
var Mailer = require(`${ROOT_DIR}/lib/senders/email`)(legacyMailerLog)
var mailer = new Mailer({}, {}, config.get('mail'))
sandbox.stub(mailer, 'send', function (vals) {
t.equal(vals.template, 'verificationReminderSecondEmail', 'correct template')
t.equal(vals.headers['X-Verify-Code'], TEST_ACCOUNT_RECORD.emailCode.toString('hex'), 'correct code')
t.ok(vals.templateValues.link.indexOf(TEST_ACCOUNT_RECORD.emailCode.toString('hex')) >= 0, 'correct link')
done(t)
assert.equal(vals.template, 'verificationReminderSecondEmail', 'correct template')
assert.equal(vals.headers['X-Verify-Code'], TEST_ACCOUNT_RECORD.emailCode.toString('hex'), 'correct code')
assert.ok(vals.templateValues.link.indexOf(TEST_ACCOUNT_RECORD.emailCode.toString('hex')) >= 0, 'correct link')
done()
})
require('../../lib/verification-reminders')(mailer, mockDb)
require(`${ROOT_DIR}/lib/senders/verification-reminders`)(mailer, mockDb)
._processReminder({uid: TEST_ACCOUNT_RECORD.uid, type: 'second'})
})
test('_processReminder - does not send email for verified emails', function (t) {
it('_processReminder - does not send email for verified emails', function () {
setup()
sandbox.stub(mockDb, 'account', function () {
return P.resolve({
@ -90,16 +91,16 @@ test('_processReminder - does not send email for verified emails', function (t)
var log = mockLog({
debug: function (op, data) {
if (data.msg === 'Already Verified') {
done(t)
done()
}
}
})
require('../../lib/verification-reminders')(mockMailer, mockDb, { log: log })
require(`${ROOT_DIR}/lib/senders/verification-reminders`)(mockMailer, mockDb, { log: log })
._processReminder(SAMPLE_REMINDER)
})
test('_processReminder - catches errors', function (t) {
it('_processReminder - catches errors', function () {
setup()
var errorMsg = 'Something is wrong.'
@ -110,23 +111,23 @@ test('_processReminder - catches errors', function (t) {
var log = mockLog({
error: function (op, data) {
if (data.err && data.err.message === errorMsg) {
done(t)
done()
}
}
})
require('../../lib/verification-reminders')(mockMailer, mockDb, { log: log })
require(`${ROOT_DIR}/lib/senders/verification-reminders`)(mockMailer, mockDb, { log: log })
._processReminder(SAMPLE_REMINDER)
})
test('_continuousPoll - calls _continuousPoll', function (t) {
it('_continuousPoll - calls _continuousPoll', function () {
setup()
sandbox.stub(mockDb, 'fetchReminders', function (options) {
t.ok(options.type)
t.ok(options.reminderTime)
t.ok(options.limit)
assert.ok(options.type)
assert.ok(options.reminderTime)
assert.ok(options.limit)
if (options.type === 'first') {
return P.resolve([SAMPLE_REMINDER])
@ -136,13 +137,13 @@ test('_continuousPoll - calls _continuousPoll', function (t) {
})
sandbox.stub(mockDb, 'account', function () {
done(t)
done()
return P.resolve({
emailVerified: true
})
})
require('../../lib/verification-reminders')(mockMailer, mockDb)
require(`${ROOT_DIR}/lib/senders/verification-reminders`)(mockMailer, mockDb)
._continuousPoll()
})
@ -151,7 +152,6 @@ function setup() {
sandbox = sinon.sandbox.create()
}
function done(t) {
function done() {
sandbox.restore()
t.done()
}

Просмотреть файл

@ -0,0 +1,139 @@
/* 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/. */
'use strict'
const assert = require('insist')
const P = require('bluebird')
const proxyquire = require('proxyquire')
const sinon = require('sinon')
const log = {
error: sinon.spy(),
info: sinon.spy(),
trace: sinon.spy()
}
let nexmoStatus = '0'
const sendSms = sinon.spy((from, to, message, callback) => {
callback(null, {
message_count: '1',
messages: [
{
to: to.substr(1),
'message-id': 'foo',
status: nexmoStatus,
'error-text': 'bar',
'remaining-balance': '42',
'message-price': '1',
'network': 'baz'
}
]
})
})
function Nexmo () {}
Nexmo.prototype.message = { sendSms }
describe('lib/senders/sms:', () => {
let sms
before(() => {
return P.all([
require('../../../../lib/senders/translator')(['en'], 'en'),
require('../../../../lib/senders/templates')()
]).spread((translator, templates) => {
sms = proxyquire('../../../../lib/senders/sms', {
nexmo: Nexmo
})(log, translator, templates, {
apiKey: 'foo',
apiSecret: 'bar',
installFirefoxLink: 'https://baz/qux'
})
})
})
afterEach(() => {
sendSms.reset()
log.error.reset()
log.info.reset()
log.trace.reset()
})
it('interface is correct', () => {
assert.equal(typeof sms.send, 'function', 'sms.send is function')
assert.equal(sms.send.length, 4, 'sms.send expects 4 arguments')
assert.equal(Object.keys(sms).length, 1, 'sms has no other methods')
})
it('sends a valid sms', () => {
return sms.send('+442078553000', 'Firefox', 1, 'en')
.then(() => {
assert.equal(sendSms.callCount, 1, 'nexmo.message.sendSms was called once')
const args = sendSms.args[0]
assert.equal(args.length, 4, 'nexmo.message.sendSms was passed four arguments')
assert.equal(args[0], 'Firefox', 'nexmo.message.sendSms was passed the correct sender id')
assert.equal(args[1], '+442078553000', 'nexmo.message.sendSms was passed the correct phone number')
assert.equal(args[2], 'As requested, here is a link to install Firefox on your mobile device: https://baz/qux', 'nexmo.message.sendSms was passed the correct message')
assert.equal(typeof args[3], 'function', 'nexmo.message.sendSms was passed a callback function')
assert.equal(log.trace.callCount, 1, 'log.trace was called once')
assert.equal(log.trace.args[0].length, 1, 'log.trace was passed one argument')
assert.deepEqual(log.trace.args[0][0], {
op: 'sms.send',
senderId: 'Firefox',
messageId: 1,
acceptLanguage: 'en'
}, 'log.info was passed the correct data')
assert.equal(log.info.callCount, 1, 'log.info was called once')
assert.equal(log.info.args[0].length, 1, 'log.info was passed one argument')
assert.deepEqual(log.info.args[0][0], {
op: 'sms.send.success',
senderId: 'Firefox',
messageId: 1,
acceptLanguage: 'en'
}, 'log.info was passed the correct data')
assert.equal(log.error.callCount, 0, 'log.error was not called')
})
})
it('try to send an sms with an invalid message id', () => {
return sms.send('+442078553000', 'Firefox', 2, 'en')
.then(() => assert.fail('sms.send should have rejected'))
.catch(error => {
assert.equal(error.status, 400, 'error.statusCode was set correctly')
assert.equal(error.message, 'Invalid message id', 'error.message was set correctly')
assert.equal(log.trace.callCount, 1, 'log.trace was called once')
assert.equal(log.info.callCount, 0, 'log.info was not called')
assert.equal(log.error.callCount, 1, 'log.error was called once')
assert.deepEqual(log.error.args[0][0], {
op: 'sms.send',
err: error.message
}, 'log.error was passed the correct data')
assert.equal(sendSms.callCount, 0, 'nexmo.message.sendSms was not called')
})
})
it('send an sms that is rejected by the network provider', () => {
nexmoStatus = '1'
return sms.send('+442078553000', 'Firefox', 1, 'en')
.then(() => assert.fail('sms.send should have rejected'))
.catch(error => {
assert.equal(error.status, 500, 'error.statusCode was set correctly')
assert.equal(error.message, 'Message rejected', 'error.message was set correctly')
assert.equal(error.reason, 'bar', 'error.reason was set correctly')
assert.equal(error.reasonCode, '1', 'error.reasonCode was set correctly')
assert.equal(log.trace.callCount, 1, 'log.trace was called once')
assert.equal(log.info.callCount, 0, 'log.info was not called')
assert.equal(sendSms.callCount, 1, 'nexmo.message.sendSms was called once')
})
})
})

Просмотреть файл

@ -0,0 +1,26 @@
/* 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/. */
const assert = require('insist')
require('../../../../lib/senders/translator')(['en', 'pt_br', 'DE', 'ES_AR', 'ES_cl'], 'en')
.done(
function (translator) {
it(
'translator works with upper and lowercase languages',
function (t) {
var x = translator('PT-br,DE')
assert.equal(x.language, 'pt-BR')
x = translator('bu-ll,es-ar')
assert.equal(x.language, 'es-AR')
x = translator('es-CL')
assert.equal(x.language, 'es-CL')
x = translator('en-US')
assert.equal(x.language, 'en')
x = translator('db-LB') // a locale that does not exist
assert.equal(x.language, 'en')
}
)
}
)

Просмотреть файл

Просмотреть файл

@ -2,55 +2,57 @@
* 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 tap = require('tap')
var test = tap.test
'use strict'
const assert = require('insist')
var butil = require('../../lib/crypto/butil')
var unbuffer = butil.unbuffer
var config = require('../../config').getProperties()
var TestServer = require('../test_server')
var config = require('../../mailer/config').getProperties()
var TestServer = require('../test_mailer_server')
var testHelpers = require('../helpers')
var testHelper = require('../mailer_helper')
var DB = require('../../lib/db')()
var DB = require('../../lib/senders/db')()
var dbServer
var dbConn = TestServer.start(config)
.then(
function (server) {
dbServer = server
return DB.connect(config[config.db.backend])
}
)
describe('mailer db', () => {
let dbServer, dbConn
test(
'ping',
function (t) {
t.plan(1)
before(() => {
return dbConn = TestServer.start(config)
.then(server => {
dbServer = server
return DB.connect(config[config.db.backend])
})
})
after(() => {
return dbConn.then(db => {
return db.close()
}).then(() => {
return dbServer.stop()
})
})
it('ping', () => {
return dbConn
.then(function (db) {
return db.ping()
})
.then(function () {
t.pass('Got the ping ok')
assert.ok('Got the ping ok')
}, function (err) {
throw err
})
}
)
test(
'get email record',
function (t) {
t.plan(1)
})
it('get email record', () => {
var accountData
var db
return dbConn
.then(function (dbObj) {
db = dbObj
accountData = testHelpers.createTestAccount()
accountData = testHelper.createTestAccount()
return db.pool.put(
'/account/' + accountData.uid.toString('hex'),
@ -61,26 +63,20 @@ test(
return db.emailRecord(accountData.email)
})
.then(function (account) {
t.false(account.emailVerified, false)
t.end()
assert.equal(account.emailVerified, false)
}, function (err) {
throw err
})
}
)
test(
'get account by uid',
function (t) {
t.plan(1)
})
it('get account by uid', () => {
var accountData
var db
return dbConn
.then(function (dbObj) {
db = dbObj
accountData = testHelpers.createTestAccount()
accountData = testHelper.createTestAccount()
return db.pool.put(
'/account/' + accountData.uid.toString('hex'),
@ -91,18 +87,13 @@ test(
return db.account(accountData.uid)
})
.then(function (account) {
t.false(account.emailVerified, false)
t.end()
assert.equal(account.emailVerified, false)
}, function (err) {
throw err
})
}
)
})
test(
'throws db errors',
function (t) {
t.plan(2)
it('throws db errors', () => {
var db
return dbConn
@ -111,32 +102,16 @@ test(
return db.emailRecord('unknownEmail@restmail.net')
})
.then(function () {
t.notOk()
assert.fail()
}, function (err) {
t.ok(err)
assert.ok(err)
return db.emailRecord('unknownEmail@restmail.net')
})
.then(function () {
t.notOk()
assert.fail()
}, function (err) {
t.ok(err)
t.end()
assert.ok(err)
})
}
)
test(
'teardown',
function (t) {
return dbConn.then(function(db) {
return db.close()
}).then(function() {
return dbServer.stop()
}).then(function () {
t.end()
})
}
)
})
})

Просмотреть файл

@ -2,37 +2,45 @@
* 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 tap = require('tap')
var test = tap.test
'use strict'
const assert = require('insist')
var P = require('../../lib/promise')
var butil = require('../../lib/crypto/butil')
var unbuffer = butil.unbuffer
var config = require('../../config').getProperties()
var TestServer = require('../test_server')
var testHelpers = require('../helpers')
var TestServer = require('../test_mailer_server')
var testHelper = require('../mailer_helper')
var DB = require('../../lib/db')()
var DB = require('../../lib/senders/db')()
var dbServer
var dbConn = TestServer.start(config)
.then(
function (server) {
dbServer = server
return DB.connect(config[config.db.backend])
}
)
describe('mailer reminder db', () => {
let dbServer, dbConn
test(
'fetchReminders',
function (t) {
before(() => {
return dbConn = TestServer.start(config)
.then(server => {
dbServer = server
return DB.connect(config[config.db.backend])
})
})
after(() => {
return dbConn.then(db => {
return db.close()
}).then(() => {
return dbServer.stop()
})
})
it('fetchReminders', () => {
var accountData
var db
return dbConn
.then(function (dbObj) {
db = dbObj
accountData = testHelpers.createTestAccount()
accountData = testHelper.createTestAccount()
return db.pool.put(
'/account/' + accountData.uid.toString('hex'),
@ -75,25 +83,11 @@ test(
}
})
t.ok(reminderFound, 'fetched the created reminder')
t.end()
assert.ok(reminderFound, 'fetched the created reminder')
},
function (err) {
throw err
}
)
}
)
test(
'teardown',
function (t) {
return dbConn.then(function(db) {
return db.close()
}).then(function() {
return dbServer.stop()
}).then(function () {
t.end()
})
}
)
})
})

Просмотреть файл