refactor(logging): decorate request object with metricsContext methods
#1503 r=seanmonstar
This commit is contained in:
Родитель
230b85ee8f
Коммит
16cf030e91
|
@ -13,9 +13,6 @@ var log = require('../lib/log')(config.log.level)
|
||||||
var getGeoData = require('../lib/geodb')(log)
|
var getGeoData = require('../lib/geodb')(log)
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
var metricsContext = require('../lib/metrics/context')(log, config)
|
|
||||||
log.setMetricsContext(metricsContext)
|
|
||||||
|
|
||||||
// Force the geo to load and run at startup, not waiting for it to run on
|
// Force the geo to load and run at startup, not waiting for it to run on
|
||||||
// some route later.
|
// some route later.
|
||||||
var knownIp = '63.245.221.32' // Mozilla MTV
|
var knownIp = '63.245.221.32' // Mozilla MTV
|
||||||
|
@ -108,8 +105,7 @@ function main() {
|
||||||
mailer,
|
mailer,
|
||||||
Password,
|
Password,
|
||||||
config,
|
config,
|
||||||
customs,
|
customs
|
||||||
metricsContext
|
|
||||||
)
|
)
|
||||||
server = Server.create(log, error, config, routes, db)
|
server = Server.create(log, error, config, routes, db)
|
||||||
|
|
||||||
|
|
28
lib/log.js
28
lib/log.js
|
@ -64,15 +64,6 @@ Lug.prototype.close = function() {
|
||||||
return this.statsd.close()
|
return this.statsd.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Certain events can include contextual metrics data
|
|
||||||
// such as utm_* tracking parameters. This helper method
|
|
||||||
// is here to work around a circular dependency between
|
|
||||||
// this module and the `metricsContext` module.
|
|
||||||
Lug.prototype.setMetricsContext = function (metricsContext) {
|
|
||||||
this.metricsContext = metricsContext
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Expose the standard error/warn/info/debug/etc log methods.
|
// Expose the standard error/warn/info/debug/etc log methods.
|
||||||
|
|
||||||
Lug.prototype.trace = function (data) {
|
Lug.prototype.trace = function (data) {
|
||||||
|
@ -176,16 +167,15 @@ Lug.prototype.summary = function (request, response) {
|
||||||
// and broadcast to relying services over SNS/SQS.
|
// and broadcast to relying services over SNS/SQS.
|
||||||
|
|
||||||
Lug.prototype.notifyAttachedServices = function (name, request, data) {
|
Lug.prototype.notifyAttachedServices = function (name, request, data) {
|
||||||
var self = this
|
return request.gatherMetricsContext({})
|
||||||
return this.metricsContext.gather({}, request)
|
|
||||||
.then(
|
.then(
|
||||||
function (metricsContextData) {
|
metricsContextData => {
|
||||||
var e = {
|
var e = {
|
||||||
event: name,
|
event: name,
|
||||||
data: unbuffer(data)
|
data: unbuffer(data)
|
||||||
}
|
}
|
||||||
e.data.metricsContext = metricsContextData
|
e.data.metricsContext = metricsContextData
|
||||||
self.stdout.write(JSON.stringify(e) + '\n')
|
this.stdout.write(JSON.stringify(e) + '\n')
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -229,8 +219,6 @@ Lug.prototype.activityEvent = function (event, request, data) {
|
||||||
// These events help understand the user's sign-in or sign-up journey.
|
// These events help understand the user's sign-in or sign-up journey.
|
||||||
|
|
||||||
Lug.prototype.flowEvent = function (event, request) {
|
Lug.prototype.flowEvent = function (event, request) {
|
||||||
var self = this
|
|
||||||
|
|
||||||
if (! event) {
|
if (! event) {
|
||||||
this.error({ op: 'log.flowEvent', missingEvent: true })
|
this.error({ op: 'log.flowEvent', missingEvent: true })
|
||||||
return P.resolve()
|
return P.resolve()
|
||||||
|
@ -247,18 +235,18 @@ Lug.prototype.flowEvent = function (event, request) {
|
||||||
return P.resolve()
|
return P.resolve()
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.metricsContext.gather({
|
return request.gatherMetricsContext({
|
||||||
event: event,
|
event: event,
|
||||||
userAgent: request.headers['user-agent']
|
userAgent: request.headers['user-agent']
|
||||||
}, request).then(
|
}).then(
|
||||||
function (info) {
|
info => {
|
||||||
if (info.flow_id) {
|
if (info.flow_id) {
|
||||||
info.event = event
|
info.event = event
|
||||||
optionallySetService(info, request)
|
optionallySetService(info, request)
|
||||||
|
|
||||||
self.logger.info('flowEvent', info)
|
this.logger.info('flowEvent', info)
|
||||||
} else if (ALWAYS_ACTIVITY_FLOW_EVENTS[event]) {
|
} else if (ALWAYS_ACTIVITY_FLOW_EVENTS[event]) {
|
||||||
self.error({ op: 'log.flowEvent', event: event, missingFlowId: true })
|
this.error({ op: 'log.flowEvent', event: event, missingFlowId: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -42,7 +42,6 @@ module.exports = function (log, config) {
|
||||||
let _memcached
|
let _memcached
|
||||||
|
|
||||||
return {
|
return {
|
||||||
schema: SCHEMA,
|
|
||||||
stash: stash,
|
stash: stash,
|
||||||
gather: gather,
|
gather: gather,
|
||||||
validate: validate
|
validate: validate
|
||||||
|
@ -52,10 +51,13 @@ module.exports = function (log, config) {
|
||||||
* Stashes metrics context metadata using a key derived from a token.
|
* Stashes metrics context metadata using a key derived from a token.
|
||||||
* Asynchronous, returns a promise.
|
* Asynchronous, returns a promise.
|
||||||
*
|
*
|
||||||
|
* @name stashMetricsContext
|
||||||
|
* @this request
|
||||||
* @param token token to stash the metadata against
|
* @param token token to stash the metadata against
|
||||||
* @param metadata metrics context metadata
|
|
||||||
*/
|
*/
|
||||||
function stash (token, metadata) {
|
function stash (token) {
|
||||||
|
const metadata = this.payload && this.payload.metricsContext
|
||||||
|
|
||||||
if (! metadata) {
|
if (! metadata) {
|
||||||
return P.resolve()
|
return P.resolve()
|
||||||
}
|
}
|
||||||
|
@ -92,18 +94,18 @@ module.exports = function (log, config) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gathers metrics context metadata onto data, using either metadata
|
* Gathers metrics context metadata onto data, using either metadata
|
||||||
* passed in from a request or previously-stashed metadata for a
|
* passed in with a request or previously-stashed metadata for a
|
||||||
* token. Asynchronous, returns a promise that resolves to data,
|
* token. Asynchronous, returns a promise that resolves to data, with
|
||||||
* with metrics context metadata copied to it.
|
* metrics context metadata copied to it.
|
||||||
*
|
*
|
||||||
|
* @name gatherMetricsContext
|
||||||
|
* @this request
|
||||||
* @param data target object
|
* @param data target object
|
||||||
* @param request request object
|
|
||||||
*/
|
*/
|
||||||
function gather (data, request) {
|
function gather (data) {
|
||||||
const metadata = request.payload && request.payload.metricsContext
|
const metadata = this.payload && this.payload.metricsContext
|
||||||
const token = request.auth && request.auth.credentials
|
const doNotTrack = this.headers && this.headers.dnt === '1'
|
||||||
const doNotTrack = request.headers && request.headers.dnt === '1'
|
let token
|
||||||
const memcached = getMemcached()
|
|
||||||
|
|
||||||
return P.resolve()
|
return P.resolve()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
@ -111,7 +113,9 @@ module.exports = function (log, config) {
|
||||||
return metadata
|
return metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
return memcached.getAsync(getKey(token))
|
token = getToken(this)
|
||||||
|
|
||||||
|
return getMemcached().getAsync(getKey(token))
|
||||||
})
|
})
|
||||||
.then(metadata => {
|
.then(metadata => {
|
||||||
if (metadata) {
|
if (metadata) {
|
||||||
|
@ -136,28 +140,44 @@ module.exports = function (log, config) {
|
||||||
.then(() => data)
|
.then(() => data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getToken (request) {
|
||||||
|
if (request.auth && request.auth.credentials) {
|
||||||
|
return request.auth.credentials
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.payload && request.payload.uid && request.payload.code) {
|
||||||
|
return {
|
||||||
|
uid: Buffer(request.payload.uid, 'hex'),
|
||||||
|
id: request.payload.code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Invalid credentials')
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether a request's flowId and flowBeginTime are valid.
|
* Checks whether a request's flowId and flowBeginTime are valid.
|
||||||
* Returns a boolean, `true` if the request is valid, `false` if
|
* Returns a boolean, `true` if the request is valid, `false` if
|
||||||
* it's invalid.
|
* it's invalid.
|
||||||
*
|
*
|
||||||
* @param request object
|
* @name validateMetricsContext
|
||||||
|
* @this request
|
||||||
*/
|
*/
|
||||||
function validate(request) {
|
function validate() {
|
||||||
const metadata = request.payload.metricsContext
|
const metadata = this.payload.metricsContext
|
||||||
|
|
||||||
if (!metadata) {
|
if (!metadata) {
|
||||||
return logInvalidContext(request, 'missing context')
|
return logInvalidContext(this, 'missing context')
|
||||||
}
|
}
|
||||||
if (!metadata.flowId) {
|
if (!metadata.flowId) {
|
||||||
return logInvalidContext(request, 'missing flowId')
|
return logInvalidContext(this, 'missing flowId')
|
||||||
}
|
}
|
||||||
if (!metadata.flowBeginTime) {
|
if (!metadata.flowBeginTime) {
|
||||||
return logInvalidContext(request, 'missing flowBeginTime')
|
return logInvalidContext(this, 'missing flowBeginTime')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Date.now() - metadata.flowBeginTime > config.metrics.flow_id_expiry) {
|
if (Date.now() - metadata.flowBeginTime > config.metrics.flow_id_expiry) {
|
||||||
return logInvalidContext(request, 'expired flowBeginTime')
|
return logInvalidContext(this, 'expired flowBeginTime')
|
||||||
}
|
}
|
||||||
|
|
||||||
// The first half of the id is random bytes, the second half is a HMAC of
|
// The first half of the id is random bytes, the second half is a HMAC of
|
||||||
|
@ -166,15 +186,15 @@ module.exports = function (log, config) {
|
||||||
// share state between content-server and auth-server.
|
// share state between content-server and auth-server.
|
||||||
const flowSignature = metadata.flowId.substr(FLOW_ID_LENGTH / 2, FLOW_ID_LENGTH)
|
const flowSignature = metadata.flowId.substr(FLOW_ID_LENGTH / 2, FLOW_ID_LENGTH)
|
||||||
const flowSignatureBytes = new Buffer(flowSignature, 'hex')
|
const flowSignatureBytes = new Buffer(flowSignature, 'hex')
|
||||||
const expectedSignatureBytes = calculateFlowSignatureBytes(request, metadata)
|
const expectedSignatureBytes = calculateFlowSignatureBytes(this, metadata)
|
||||||
if (! bufferEqualConstantTime(flowSignatureBytes, expectedSignatureBytes)) {
|
if (! bufferEqualConstantTime(flowSignatureBytes, expectedSignatureBytes)) {
|
||||||
return logInvalidContext(request, 'invalid signature')
|
return logInvalidContext(this, 'invalid signature')
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info({
|
log.info({
|
||||||
op: 'metrics.context.validate',
|
op: 'metrics.context.validate',
|
||||||
valid: true,
|
valid: true,
|
||||||
agent: request.headers['user-agent']
|
agent: this.headers['user-agent']
|
||||||
})
|
})
|
||||||
log.increment('metrics.context.valid')
|
log.increment('metrics.context.valid')
|
||||||
return true
|
return true
|
||||||
|
@ -231,3 +251,6 @@ function calculateFlowTime (time, flowBeginTime) {
|
||||||
|
|
||||||
return time - flowBeginTime
|
return time - flowBeginTime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports.schema = SCHEMA
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@ var butil = require('../crypto/butil')
|
||||||
var userAgent = require('../userAgent')
|
var userAgent = require('../userAgent')
|
||||||
var requestHelper = require('../routes/utils/request_helper')
|
var requestHelper = require('../routes/utils/request_helper')
|
||||||
|
|
||||||
|
const METRICS_CONTEXT_SCHEMA = require('../metrics/context').schema
|
||||||
|
|
||||||
module.exports = function (
|
module.exports = function (
|
||||||
log,
|
log,
|
||||||
crypto,
|
crypto,
|
||||||
|
@ -42,7 +44,6 @@ module.exports = function (
|
||||||
isPreVerified,
|
isPreVerified,
|
||||||
checkPassword,
|
checkPassword,
|
||||||
push,
|
push,
|
||||||
metricsContext,
|
|
||||||
devices
|
devices
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@ -77,7 +78,7 @@ module.exports = function (
|
||||||
redirectTo: validators.redirectTo(config.smtp.redirectDomain).optional(),
|
redirectTo: validators.redirectTo(config.smtp.redirectDomain).optional(),
|
||||||
resume: isA.string().max(2048).optional(),
|
resume: isA.string().max(2048).optional(),
|
||||||
preVerifyToken: isA.string().max(2048).regex(BASE64_JWT).optional(),
|
preVerifyToken: isA.string().max(2048).regex(BASE64_JWT).optional(),
|
||||||
metricsContext: metricsContext.schema
|
metricsContext: METRICS_CONTEXT_SCHEMA
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
response: {
|
response: {
|
||||||
|
@ -104,7 +105,7 @@ module.exports = function (
|
||||||
var tokenVerificationId = emailCode
|
var tokenVerificationId = emailCode
|
||||||
var preVerified, password, verifyHash, account, sessionToken, keyFetchToken
|
var preVerified, password, verifyHash, account, sessionToken, keyFetchToken
|
||||||
|
|
||||||
metricsContext.validate(request)
|
request.validateMetricsContext()
|
||||||
|
|
||||||
customs.check(request, email, 'accountCreate')
|
customs.check(request, email, 'accountCreate')
|
||||||
.then(db.emailRecord.bind(db, email))
|
.then(db.emailRecord.bind(db, email))
|
||||||
|
@ -239,17 +240,17 @@ module.exports = function (
|
||||||
.then(
|
.then(
|
||||||
function (result) {
|
function (result) {
|
||||||
sessionToken = result
|
sessionToken = result
|
||||||
return metricsContext.stash(sessionToken, form.metricsContext)
|
return request.stashMetricsContext(sessionToken)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.then(
|
.then(
|
||||||
function () {
|
function () {
|
||||||
// There is no session token when we emit account.verified
|
// There is no session token when we emit account.verified
|
||||||
// so stash the data against a synthesized "token" instead.
|
// so stash the data against a synthesized "token" instead.
|
||||||
return metricsContext.stash({
|
return request.stashMetricsContext({
|
||||||
uid: account.uid,
|
uid: account.uid,
|
||||||
id: account.emailCode.toString('hex')
|
id: account.emailCode.toString('hex')
|
||||||
}, form.metricsContext)
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -312,7 +313,7 @@ module.exports = function (
|
||||||
.then(
|
.then(
|
||||||
function (result) {
|
function (result) {
|
||||||
keyFetchToken = result
|
keyFetchToken = result
|
||||||
return metricsContext.stash(keyFetchToken, form.metricsContext)
|
return request.stashMetricsContext(keyFetchToken)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -360,7 +361,7 @@ module.exports = function (
|
||||||
resume: isA.string().optional(),
|
resume: isA.string().optional(),
|
||||||
reason: isA.string().max(16).optional(),
|
reason: isA.string().max(16).optional(),
|
||||||
unblockCode: isA.string().regex(BASE_36).length(unblockCodeLen).optional(),
|
unblockCode: isA.string().regex(BASE_36).length(unblockCodeLen).optional(),
|
||||||
metricsContext: metricsContext.schema
|
metricsContext: METRICS_CONTEXT_SCHEMA
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
response: {
|
response: {
|
||||||
|
@ -389,7 +390,7 @@ module.exports = function (
|
||||||
var emailRecord, sessions, sessionToken, keyFetchToken, mustVerifySession, doSigninConfirmation, emailSent, unblockCode, customsErr, allowSigninUnblock, didSigninUnblock
|
var emailRecord, sessions, sessionToken, keyFetchToken, mustVerifySession, doSigninConfirmation, emailSent, unblockCode, customsErr, allowSigninUnblock, didSigninUnblock
|
||||||
var ip = request.app.clientAddress
|
var ip = request.app.clientAddress
|
||||||
|
|
||||||
metricsContext.validate(request)
|
request.validateMetricsContext()
|
||||||
|
|
||||||
// Monitor for any clients still sending obsolete 'contentToken' param.
|
// Monitor for any clients still sending obsolete 'contentToken' param.
|
||||||
if (request.payload.contentToken) {
|
if (request.payload.contentToken) {
|
||||||
|
@ -639,7 +640,7 @@ module.exports = function (
|
||||||
.then(
|
.then(
|
||||||
function (result) {
|
function (result) {
|
||||||
sessionToken = result
|
sessionToken = result
|
||||||
return metricsContext.stash(sessionToken, form.metricsContext)
|
return request.stashMetricsContext(sessionToken)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.then(
|
.then(
|
||||||
|
@ -647,10 +648,10 @@ module.exports = function (
|
||||||
if (doSigninConfirmation) {
|
if (doSigninConfirmation) {
|
||||||
// There is no session token when we emit account.confirmed
|
// There is no session token when we emit account.confirmed
|
||||||
// so stash the data against a synthesized "token" instead.
|
// so stash the data against a synthesized "token" instead.
|
||||||
return metricsContext.stash({
|
return request.stashMetricsContext({
|
||||||
uid: emailRecord.uid,
|
uid: emailRecord.uid,
|
||||||
id: tokenVerificationId.toString('hex')
|
id: tokenVerificationId.toString('hex')
|
||||||
}, form.metricsContext)
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -677,7 +678,7 @@ module.exports = function (
|
||||||
.then(
|
.then(
|
||||||
function (result) {
|
function (result) {
|
||||||
keyFetchToken = result
|
keyFetchToken = result
|
||||||
return metricsContext.stash(keyFetchToken, form.metricsContext)
|
return request.stashMetricsContext(keyFetchToken)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1454,22 +1455,6 @@ module.exports = function (
|
||||||
var service = request.payload.service || request.query.service
|
var service = request.payload.service || request.query.service
|
||||||
var reminder = request.payload.reminder || request.query.reminder
|
var reminder = request.payload.reminder || request.query.reminder
|
||||||
|
|
||||||
// Because we have no session token on this endpoint, metrics context
|
|
||||||
// metadata was stashed against a synthesized token for the benefit of
|
|
||||||
// the activity events. This fake request object allows the correct
|
|
||||||
// metadata to be gathered when we emit the events.
|
|
||||||
var fakeRequestObject = {
|
|
||||||
auth: {
|
|
||||||
credentials: {
|
|
||||||
uid: uid,
|
|
||||||
id: request.payload.code
|
|
||||||
}
|
|
||||||
},
|
|
||||||
headers: request.headers,
|
|
||||||
payload: request.payload,
|
|
||||||
query: request.query
|
|
||||||
}
|
|
||||||
|
|
||||||
log.begin('Account.RecoveryEmailVerify', request)
|
log.begin('Account.RecoveryEmailVerify', request)
|
||||||
db.account(uid)
|
db.account(uid)
|
||||||
.then(
|
.then(
|
||||||
|
@ -1508,7 +1493,7 @@ module.exports = function (
|
||||||
uid: uidHex,
|
uid: uidHex,
|
||||||
code: request.payload.code
|
code: request.payload.code
|
||||||
})
|
})
|
||||||
log.activityEvent('account.confirmed', fakeRequestObject, {
|
log.activityEvent('account.confirmed', request, {
|
||||||
uid: uidHex
|
uid: uidHex
|
||||||
})
|
})
|
||||||
push.notifyUpdate(uid, 'accountConfirm')
|
push.notifyUpdate(uid, 'accountConfirm')
|
||||||
|
@ -1544,14 +1529,14 @@ module.exports = function (
|
||||||
.then(function () {
|
.then(function () {
|
||||||
log.timing('account.verified', Date.now() - account.createdAt)
|
log.timing('account.verified', Date.now() - account.createdAt)
|
||||||
log.increment('account.verified')
|
log.increment('account.verified')
|
||||||
return log.notifyAttachedServices('verified', fakeRequestObject, {
|
return log.notifyAttachedServices('verified', request, {
|
||||||
email: account.email,
|
email: account.email,
|
||||||
uid: account.uid,
|
uid: account.uid,
|
||||||
locale: account.locale
|
locale: account.locale
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return log.activityEvent('account.verified', fakeRequestObject, {
|
return log.activityEvent('account.verified', request, {
|
||||||
uid: uidHex
|
uid: uidHex
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1627,7 +1612,7 @@ module.exports = function (
|
||||||
validate: {
|
validate: {
|
||||||
payload: {
|
payload: {
|
||||||
email: validators.email().required(),
|
email: validators.email().required(),
|
||||||
metricsContext: metricsContext.schema
|
metricsContext: METRICS_CONTEXT_SCHEMA
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -18,8 +18,7 @@ module.exports = function (
|
||||||
mailer,
|
mailer,
|
||||||
Password,
|
Password,
|
||||||
config,
|
config,
|
||||||
customs,
|
customs
|
||||||
metricsContext
|
|
||||||
) {
|
) {
|
||||||
var isPreVerified = require('../preverifier')(error, config)
|
var isPreVerified = require('../preverifier')(error, config)
|
||||||
var defaults = require('./defaults')(log, P, db, error)
|
var defaults = require('./defaults')(log, P, db, error)
|
||||||
|
@ -42,7 +41,6 @@ module.exports = function (
|
||||||
isPreVerified,
|
isPreVerified,
|
||||||
checkPassword,
|
checkPassword,
|
||||||
push,
|
push,
|
||||||
metricsContext,
|
|
||||||
devices
|
devices
|
||||||
)
|
)
|
||||||
var password = require('./password')(
|
var password = require('./password')(
|
||||||
|
@ -56,8 +54,7 @@ module.exports = function (
|
||||||
config.verifierVersion,
|
config.verifierVersion,
|
||||||
customs,
|
customs,
|
||||||
checkPassword,
|
checkPassword,
|
||||||
push,
|
push
|
||||||
metricsContext
|
|
||||||
)
|
)
|
||||||
var session = require('./session')(log, isA, error, db)
|
var session = require('./session')(log, isA, error, db)
|
||||||
var sign = require('./sign')(log, P, isA, error, signer, db, config.domain, devices)
|
var sign = require('./sign')(log, P, isA, error, signer, db, config.domain, devices)
|
||||||
|
|
|
@ -10,6 +10,8 @@ var butil = require('../crypto/butil')
|
||||||
var P = require('../promise')
|
var P = require('../promise')
|
||||||
var requestHelper = require('../routes/utils/request_helper')
|
var requestHelper = require('../routes/utils/request_helper')
|
||||||
|
|
||||||
|
const METRICS_CONTEXT_SCHEMA = require('../metrics/context').schema
|
||||||
|
|
||||||
module.exports = function (
|
module.exports = function (
|
||||||
log,
|
log,
|
||||||
isA,
|
isA,
|
||||||
|
@ -21,8 +23,7 @@ module.exports = function (
|
||||||
verifierVersion,
|
verifierVersion,
|
||||||
customs,
|
customs,
|
||||||
checkPassword,
|
checkPassword,
|
||||||
push,
|
push
|
||||||
metricsContext
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
function failVerifyAttempt(passwordForgotToken) {
|
function failVerifyAttempt(passwordForgotToken) {
|
||||||
|
@ -304,7 +305,7 @@ module.exports = function (
|
||||||
service: isA.string().max(16).alphanum().optional(),
|
service: isA.string().max(16).alphanum().optional(),
|
||||||
redirectTo: validators.redirectTo(redirectDomain).optional(),
|
redirectTo: validators.redirectTo(redirectDomain).optional(),
|
||||||
resume: isA.string().max(2048).optional(),
|
resume: isA.string().max(2048).optional(),
|
||||||
metricsContext: metricsContext.schema
|
metricsContext: METRICS_CONTEXT_SCHEMA
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
response: {
|
response: {
|
||||||
|
@ -380,7 +381,7 @@ module.exports = function (
|
||||||
service: isA.string().max(16).alphanum().optional(),
|
service: isA.string().max(16).alphanum().optional(),
|
||||||
redirectTo: validators.redirectTo(redirectDomain).optional(),
|
redirectTo: validators.redirectTo(redirectDomain).optional(),
|
||||||
resume: isA.string().max(2048).optional(),
|
resume: isA.string().max(2048).optional(),
|
||||||
metricsContext: metricsContext.schema
|
metricsContext: METRICS_CONTEXT_SCHEMA
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
response: {
|
response: {
|
||||||
|
@ -438,7 +439,7 @@ module.exports = function (
|
||||||
validate: {
|
validate: {
|
||||||
payload: {
|
payload: {
|
||||||
code: isA.string().min(32).max(32).regex(HEX_STRING).required(),
|
code: isA.string().min(32).max(32).regex(HEX_STRING).required(),
|
||||||
metricsContext: metricsContext.schema
|
metricsContext: METRICS_CONTEXT_SCHEMA
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
response: {
|
response: {
|
||||||
|
|
|
@ -296,6 +296,12 @@ function create(log, error, config, routes, db) {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const metricsContext = require('./metrics/context')(log, config)
|
||||||
|
|
||||||
|
server.decorate('request', 'stashMetricsContext', metricsContext.stash)
|
||||||
|
server.decorate('request', 'gatherMetricsContext', metricsContext.gather)
|
||||||
|
server.decorate('request', 'validateMetricsContext', metricsContext.validate)
|
||||||
|
|
||||||
server.stat = function() {
|
server.stat = function() {
|
||||||
return {
|
return {
|
||||||
stat: 'mem',
|
stat: 'mem',
|
||||||
|
|
|
@ -49,7 +49,6 @@ var makeRoutes = function (options, requireMocks) {
|
||||||
}
|
}
|
||||||
var checkPassword = options.checkPassword || require('../../lib/routes/utils/password_check')(log, config, Password, customs, db)
|
var checkPassword = options.checkPassword || require('../../lib/routes/utils/password_check')(log, config, Password, customs, db)
|
||||||
var push = options.push || require('../../lib/push')(log, db, {})
|
var push = options.push || require('../../lib/push')(log, db, {})
|
||||||
var metricsContext = options.metricsContext || log.metricsContext || require('../../lib/metrics/context')(log, config)
|
|
||||||
return proxyquire('../../lib/routes/account', requireMocks || {})(
|
return proxyquire('../../lib/routes/account', requireMocks || {})(
|
||||||
log,
|
log,
|
||||||
crypto,
|
crypto,
|
||||||
|
@ -65,7 +64,6 @@ var makeRoutes = function (options, requireMocks) {
|
||||||
isPreVerified,
|
isPreVerified,
|
||||||
checkPassword,
|
checkPassword,
|
||||||
push,
|
push,
|
||||||
metricsContext,
|
|
||||||
options.devices || require('../../lib/devices')(log, db, push)
|
options.devices || require('../../lib/devices')(log, db, push)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -566,7 +564,13 @@ test('/account/device/destroy', function (t) {
|
||||||
})
|
})
|
||||||
|
|
||||||
test('/account/create', function (t) {
|
test('/account/create', function (t) {
|
||||||
|
var mockMetricsContext = mocks.mockMetricsContext({
|
||||||
|
gather: sinon.spy(function (data) {
|
||||||
|
return P.resolve(this.payload && this.payload.metricsContext)
|
||||||
|
})
|
||||||
|
})
|
||||||
var mockRequest = mocks.mockRequest({
|
var mockRequest = mocks.mockRequest({
|
||||||
|
metricsContext: mockMetricsContext,
|
||||||
payload: {
|
payload: {
|
||||||
email: TEST_EMAIL,
|
email: TEST_EMAIL,
|
||||||
authPW: crypto.randomBytes(32).toString('hex'),
|
authPW: crypto.randomBytes(32).toString('hex'),
|
||||||
|
@ -609,12 +613,6 @@ test('/account/create', function (t) {
|
||||||
write: sinon.spy()
|
write: sinon.spy()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
var mockMetricsContext = mocks.mockMetricsContext({
|
|
||||||
gather: sinon.spy(function (data, request) {
|
|
||||||
return P.resolve(request.payload.metricsContext)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
mockLog.setMetricsContext(mockMetricsContext)
|
|
||||||
mockLog.activityEvent = sinon.spy(function () {
|
mockLog.activityEvent = sinon.spy(function () {
|
||||||
return P.resolve()
|
return P.resolve()
|
||||||
})
|
})
|
||||||
|
@ -629,7 +627,6 @@ test('/account/create', function (t) {
|
||||||
db: mockDB,
|
db: mockDB,
|
||||||
log: mockLog,
|
log: mockLog,
|
||||||
mailer: mockMailer,
|
mailer: mockMailer,
|
||||||
metricsContext: mockMetricsContext,
|
|
||||||
Password: function () {
|
Password: function () {
|
||||||
return {
|
return {
|
||||||
unwrap: function () {
|
unwrap: function () {
|
||||||
|
@ -662,29 +659,27 @@ test('/account/create', function (t) {
|
||||||
t.deepEqual(args[2], { uid: uid.toString('hex') }, 'third argument contained uid')
|
t.deepEqual(args[2], { uid: uid.toString('hex') }, 'third argument contained uid')
|
||||||
|
|
||||||
t.equal(mockMetricsContext.validate.callCount, 1, 'metricsContext.validate was called')
|
t.equal(mockMetricsContext.validate.callCount, 1, 'metricsContext.validate was called')
|
||||||
args = mockMetricsContext.validate.args[0]
|
t.equal(mockMetricsContext.validate.args[0].length, 0, 'validate was called without arguments')
|
||||||
t.equal(args.length, 1, 'validate was called with a single argument')
|
|
||||||
t.deepEqual(args[0], mockRequest, 'validate was called with the request')
|
|
||||||
|
|
||||||
t.equal(mockMetricsContext.stash.callCount, 3, 'metricsContext.stash was called three times')
|
t.equal(mockMetricsContext.stash.callCount, 3, 'metricsContext.stash was called three times')
|
||||||
|
|
||||||
args = mockMetricsContext.stash.args[0]
|
args = mockMetricsContext.stash.args[0]
|
||||||
t.equal(args.length, 2, 'metricsContext.stash was passed two arguments first time')
|
t.equal(args.length, 1, 'metricsContext.stash was passed one argument first time')
|
||||||
t.deepEqual(args[0].tokenId, sessionTokenId, 'first argument was session token')
|
t.deepEqual(args[0].tokenId, sessionTokenId, 'argument was session token')
|
||||||
t.deepEqual(args[0].uid, uid, 'sessionToken.uid was correct')
|
t.deepEqual(args[0].uid, uid, 'sessionToken.uid was correct')
|
||||||
t.equal(args[1], mockRequest.payload.metricsContext, 'second argument was metrics context')
|
t.equal(mockMetricsContext.stash.thisValues[0], mockRequest, 'this was request')
|
||||||
|
|
||||||
args = mockMetricsContext.stash.args[1]
|
args = mockMetricsContext.stash.args[1]
|
||||||
t.equal(args.length, 2, 'metricsContext.stash was passed two arguments second time')
|
t.equal(args.length, 1, 'metricsContext.stash was passed one argument second time')
|
||||||
t.equal(args[0].id, emailCode.toString('hex'), 'first argument was synthesized token')
|
t.equal(args[0].id, emailCode.toString('hex'), 'argument was synthesized token')
|
||||||
t.deepEqual(args[0].uid, uid, 'token.uid was correct')
|
t.deepEqual(args[0].uid, uid, 'token.uid was correct')
|
||||||
t.equal(args[1], mockRequest.payload.metricsContext, 'second argument was metrics context')
|
t.equal(mockMetricsContext.stash.thisValues[1], mockRequest, 'this was request')
|
||||||
|
|
||||||
args = mockMetricsContext.stash.args[2]
|
args = mockMetricsContext.stash.args[2]
|
||||||
t.equal(args.length, 2, 'metricsContext.stash was passed two arguments third time')
|
t.equal(args.length, 1, 'metricsContext.stash was passed one argument third time')
|
||||||
t.deepEqual(args[0].tokenId, keyFetchTokenId, 'first argument was key fetch token')
|
t.deepEqual(args[0].tokenId, keyFetchTokenId, 'argument was key fetch token')
|
||||||
t.deepEqual(args[0].uid, uid, 'keyFetchToken.uid was correct')
|
t.deepEqual(args[0].uid, uid, 'keyFetchToken.uid was correct')
|
||||||
t.equal(args[1], mockRequest.payload.metricsContext, 'second argument was metrics context')
|
t.equal(mockMetricsContext.stash.thisValues[2], mockRequest, 'this was request')
|
||||||
|
|
||||||
var securityEvent = mockDB.securityEvent
|
var securityEvent = mockDB.securityEvent
|
||||||
t.equal(securityEvent.callCount, 1, 'db.securityEvent is called')
|
t.equal(securityEvent.callCount, 1, 'db.securityEvent is called')
|
||||||
|
@ -711,10 +706,13 @@ test('/account/login', function (t) {
|
||||||
enabled: true
|
enabled: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var mockMetricsContext = mocks.mockMetricsContext({
|
||||||
|
gather: sinon.spy(function (data) {
|
||||||
|
return P.resolve(this.payload && this.payload.metricsContext)
|
||||||
|
})
|
||||||
|
})
|
||||||
var mockRequest = mocks.mockRequest({
|
var mockRequest = mocks.mockRequest({
|
||||||
query: {
|
metricsContext: mockMetricsContext,
|
||||||
keys: 'true'
|
|
||||||
},
|
|
||||||
payload: {
|
payload: {
|
||||||
authPW: crypto.randomBytes(32).toString('hex'),
|
authPW: crypto.randomBytes(32).toString('hex'),
|
||||||
email: TEST_EMAIL,
|
email: TEST_EMAIL,
|
||||||
|
@ -727,10 +725,13 @@ test('/account/login', function (t) {
|
||||||
entrypoint: 'preferences',
|
entrypoint: 'preferences',
|
||||||
utmContent: 'some-content-string'
|
utmContent: 'some-content-string'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
keys: 'true'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
var mockRequestNoKeys = mocks.mockRequest({
|
var mockRequestNoKeys = mocks.mockRequest({
|
||||||
query: {},
|
metricsContext: mockMetricsContext,
|
||||||
payload: {
|
payload: {
|
||||||
authPW: crypto.randomBytes(32).toString('hex'),
|
authPW: crypto.randomBytes(32).toString('hex'),
|
||||||
email: 'test@mozilla.com',
|
email: 'test@mozilla.com',
|
||||||
|
@ -741,7 +742,8 @@ test('/account/login', function (t) {
|
||||||
flowId: 'F1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF103',
|
flowId: 'F1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF103',
|
||||||
service: 'dcdb5ae7add825d2'
|
service: 'dcdb5ae7add825d2'
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
query: {}
|
||||||
})
|
})
|
||||||
var mockRequestWithUnblockCode = mocks.mockRequest({
|
var mockRequestWithUnblockCode = mocks.mockRequest({
|
||||||
query: {},
|
query: {},
|
||||||
|
@ -779,12 +781,6 @@ test('/account/login', function (t) {
|
||||||
write: sinon.spy()
|
write: sinon.spy()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
var mockMetricsContext = mocks.mockMetricsContext({
|
|
||||||
gather: sinon.spy(function (data, request) {
|
|
||||||
return P.resolve(request.payload.metricsContext)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
mockLog.setMetricsContext(mockMetricsContext)
|
|
||||||
mockLog.activityEvent = sinon.spy(function () {
|
mockLog.activityEvent = sinon.spy(function () {
|
||||||
return P.resolve()
|
return P.resolve()
|
||||||
})
|
})
|
||||||
|
@ -802,7 +798,6 @@ test('/account/login', function (t) {
|
||||||
db: mockDB,
|
db: mockDB,
|
||||||
log: mockLog,
|
log: mockLog,
|
||||||
mailer: mockMailer,
|
mailer: mockMailer,
|
||||||
metricsContext: mockMetricsContext,
|
|
||||||
push: mockPush
|
push: mockPush
|
||||||
})
|
})
|
||||||
var route = getRoute(accountRoutes, '/account/login')
|
var route = getRoute(accountRoutes, '/account/login')
|
||||||
|
@ -833,23 +828,21 @@ test('/account/login', function (t) {
|
||||||
t.deepEqual(args[2], {uid: uid.toString('hex')}, 'third argument contained uid')
|
t.deepEqual(args[2], {uid: uid.toString('hex')}, 'third argument contained uid')
|
||||||
|
|
||||||
t.equal(mockMetricsContext.validate.callCount, 1, 'metricsContext.validate was called')
|
t.equal(mockMetricsContext.validate.callCount, 1, 'metricsContext.validate was called')
|
||||||
args = mockMetricsContext.validate.args[0]
|
t.equal(mockMetricsContext.validate.args[0].length, 0, 'validate was called without arguments')
|
||||||
t.equal(args.length, 1, 'validate was called with a single argument')
|
|
||||||
t.deepEqual(args[0], mockRequest, 'validate was called with the request')
|
|
||||||
|
|
||||||
t.equal(mockMetricsContext.stash.callCount, 2, 'metricsContext.stash was called twice')
|
t.equal(mockMetricsContext.stash.callCount, 2, 'metricsContext.stash was called twice')
|
||||||
|
|
||||||
args = mockMetricsContext.stash.args[0]
|
args = mockMetricsContext.stash.args[0]
|
||||||
t.equal(args.length, 2, 'metricsContext.stash was passed two arguments first time')
|
t.equal(args.length, 1, 'metricsContext.stash was passed one argument first time')
|
||||||
t.deepEqual(args[0].tokenId, sessionTokenId, 'first argument was session token')
|
t.deepEqual(args[0].tokenId, sessionTokenId, 'argument was session token')
|
||||||
t.deepEqual(args[0].uid, uid, 'sessionToken.uid was correct')
|
t.deepEqual(args[0].uid, uid, 'sessionToken.uid was correct')
|
||||||
t.equal(args[1], mockRequest.payload.metricsContext, 'second argument was metrics context')
|
t.equal(mockMetricsContext.stash.thisValues[0], mockRequest, 'this was request')
|
||||||
|
|
||||||
args = mockMetricsContext.stash.args[1]
|
args = mockMetricsContext.stash.args[1]
|
||||||
t.equal(args.length, 2, 'metricsContext.stash was passed two arguments second time')
|
t.equal(args.length, 1, 'metricsContext.stash was passed one argument second time')
|
||||||
t.deepEqual(args[0].tokenId, keyFetchTokenId, 'first argument was key fetch token')
|
t.deepEqual(args[0].tokenId, keyFetchTokenId, 'argument was key fetch token')
|
||||||
t.deepEqual(args[0].uid, uid, 'keyFetchToken.uid was correct')
|
t.deepEqual(args[0].uid, uid, 'keyFetchToken.uid was correct')
|
||||||
t.equal(args[1], mockRequest.payload.metricsContext, 'second argument was metrics context')
|
t.equal(mockMetricsContext.stash.thisValues[1], mockRequest, 'this was request')
|
||||||
|
|
||||||
t.equal(mockMailer.sendNewDeviceLoginNotification.callCount, 1, 'mailer.sendNewDeviceLoginNotification was called')
|
t.equal(mockMailer.sendNewDeviceLoginNotification.callCount, 1, 'mailer.sendNewDeviceLoginNotification was called')
|
||||||
t.equal(mockMailer.sendNewDeviceLoginNotification.getCall(0).args[1].location.city, 'Mountain View')
|
t.equal(mockMailer.sendNewDeviceLoginNotification.getCall(0).args[1].location.city, 'Mountain View')
|
||||||
|
@ -944,10 +937,10 @@ test('/account/login', function (t) {
|
||||||
|
|
||||||
t.equal(mockMetricsContext.stash.callCount, 3, 'metricsContext.stash was called three times')
|
t.equal(mockMetricsContext.stash.callCount, 3, 'metricsContext.stash was called three times')
|
||||||
var args = mockMetricsContext.stash.args[1]
|
var args = mockMetricsContext.stash.args[1]
|
||||||
t.equal(args.length, 2, 'metricsContext.stash was passed two arguments second time')
|
t.equal(args.length, 1, 'metricsContext.stash was passed one argument second time')
|
||||||
t.ok(/^[0-9a-f]{32}$/.test(args[0].id), 'first argument was synthesized token')
|
t.ok(/^[0-9a-f]{32}$/.test(args[0].id), 'argument was synthesized token')
|
||||||
t.deepEqual(args[0].uid, uid, 'token.uid was correct')
|
t.deepEqual(args[0].uid, uid, 'token.uid was correct')
|
||||||
t.equal(args[1], mockRequest.payload.metricsContext, 'second argument was metrics context')
|
t.equal(mockMetricsContext.stash.thisValues[1], mockRequest, 'this was request')
|
||||||
|
|
||||||
t.equal(mockMailer.sendVerifyLoginEmail.callCount, 1, 'mailer.sendVerifyLoginEmail was called')
|
t.equal(mockMailer.sendVerifyLoginEmail.callCount, 1, 'mailer.sendVerifyLoginEmail was called')
|
||||||
t.equal(mockMailer.sendVerifyLoginEmail.getCall(0).args[2].location.city, 'Mountain View')
|
t.equal(mockMailer.sendVerifyLoginEmail.getCall(0).args[2].location.city, 'Mountain View')
|
||||||
|
@ -1453,17 +1446,7 @@ test('/recovery_email/verify_code', function (t) {
|
||||||
var args = mockLog.activityEvent.args[0]
|
var args = mockLog.activityEvent.args[0]
|
||||||
t.equal(args.length, 3, 'activityEvent was passed three arguments')
|
t.equal(args.length, 3, 'activityEvent was passed three arguments')
|
||||||
t.equal(args[0], 'account.verified', 'first argument was event name')
|
t.equal(args[0], 'account.verified', 'first argument was event name')
|
||||||
t.deepEqual(args[1], {
|
t.equal(args[1], mockRequest, 'second argument was request object')
|
||||||
auth: {
|
|
||||||
credentials: {
|
|
||||||
uid: Buffer(uid, 'hex'),
|
|
||||||
id: mockRequest.payload.code,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
headers: mockRequest.headers,
|
|
||||||
payload: mockRequest.payload,
|
|
||||||
query: mockRequest.query
|
|
||||||
}, 'second argument was synthesized request object')
|
|
||||||
t.deepEqual(args[2], { uid: uid }, 'third argument contained uid')
|
t.deepEqual(args[2], { uid: uid }, 'third argument contained uid')
|
||||||
|
|
||||||
t.equal(mockPush.notifyUpdate.callCount, 1, 'mockPush.notifyUpdate should have been called once')
|
t.equal(mockPush.notifyUpdate.callCount, 1, 'mockPush.notifyUpdate should have been called once')
|
||||||
|
@ -1545,17 +1528,7 @@ test('/recovery_email/verify_code', function (t) {
|
||||||
var args = mockLog.activityEvent.args[0]
|
var args = mockLog.activityEvent.args[0]
|
||||||
t.equal(args.length, 3, 'log.activityEvent was passed three arguments')
|
t.equal(args.length, 3, 'log.activityEvent was passed three arguments')
|
||||||
t.equal(args[0], 'account.confirmed', 'first argument was event name')
|
t.equal(args[0], 'account.confirmed', 'first argument was event name')
|
||||||
t.deepEqual(args[1], {
|
t.equal(args[1], mockRequest, 'second argument was request object')
|
||||||
auth: {
|
|
||||||
credentials: {
|
|
||||||
uid: Buffer(uid, 'hex'),
|
|
||||||
id: mockRequest.payload.code,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
headers: mockRequest.headers,
|
|
||||||
payload: mockRequest.payload,
|
|
||||||
query: mockRequest.query
|
|
||||||
}, 'second argument was synthesized request object')
|
|
||||||
t.deepEqual(args[2], { uid: uid }, 'third argument contained uid')
|
t.deepEqual(args[2], { uid: uid }, 'third argument contained uid')
|
||||||
|
|
||||||
t.equal(mockPush.notifyUpdate.callCount, 1, 'mockPush.notifyUpdate should have been called once')
|
t.equal(mockPush.notifyUpdate.callCount, 1, 'mockPush.notifyUpdate should have been called once')
|
||||||
|
|
|
@ -19,10 +19,10 @@ var statsd = {
|
||||||
write: sinon.spy()
|
write: sinon.spy()
|
||||||
}
|
}
|
||||||
var metricsContext = {
|
var metricsContext = {
|
||||||
gather: sinon.spy(function (data, request) {
|
gather: sinon.spy(function (data) {
|
||||||
return P.resolve(request.payload && {
|
return P.resolve(this.payload && {
|
||||||
flow_id: request.payload.metricsContext.flowId,
|
flow_id: this.payload.metricsContext.flowId,
|
||||||
service: request.payload.metricsContext.service
|
service: this.payload.metricsContext.service
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,6 @@ mocks['./metrics/statsd'] = function () {
|
||||||
return statsd
|
return statsd
|
||||||
}
|
}
|
||||||
var log = proxyquire('../../lib/log', mocks)('foo', 'bar')
|
var log = proxyquire('../../lib/log', mocks)('foo', 'bar')
|
||||||
log.setMetricsContext(metricsContext)
|
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'initialised correctly',
|
'initialised correctly',
|
||||||
|
@ -85,6 +84,7 @@ test(
|
||||||
'log.activityEvent',
|
'log.activityEvent',
|
||||||
function (t) {
|
function (t) {
|
||||||
var request = {
|
var request = {
|
||||||
|
gatherMetricsContext: metricsContext.gather,
|
||||||
headers: {
|
headers: {
|
||||||
'user-agent': 'foo'
|
'user-agent': 'foo'
|
||||||
},
|
},
|
||||||
|
@ -126,6 +126,7 @@ test(
|
||||||
'log.activityEvent with flow event',
|
'log.activityEvent with flow event',
|
||||||
function (t) {
|
function (t) {
|
||||||
var request = {
|
var request = {
|
||||||
|
gatherMetricsContext: metricsContext.gather,
|
||||||
headers: {
|
headers: {
|
||||||
'user-agent': 'foo'
|
'user-agent': 'foo'
|
||||||
},
|
},
|
||||||
|
@ -140,13 +141,13 @@ test(
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
t.equal(metricsContext.gather.callCount, 1, 'metricsContext.gather was called once')
|
t.equal(metricsContext.gather.callCount, 1, 'metricsContext.gather was called once')
|
||||||
var args = metricsContext.gather.args[0]
|
var args = metricsContext.gather.args[0]
|
||||||
t.equal(args.length, 2, 'metricsContext.gather was passed two arguments')
|
t.equal(args.length, 1, 'metricsContext.gather was passed one argument')
|
||||||
t.equal(typeof args[0], 'object', 'first argument was object')
|
t.equal(typeof args[0], 'object', 'argument was object')
|
||||||
t.notEqual(args[0], null, 'first argument was not null')
|
t.notEqual(args[0], null, 'argument was not null')
|
||||||
t.equal(Object.keys(args[0]).length, 2, 'first argument had two properties')
|
t.equal(Object.keys(args[0]).length, 2, 'argument had two properties')
|
||||||
t.equal(args[0].event, 'account.created', 'event property was correct')
|
t.equal(args[0].event, 'account.created', 'event property was correct')
|
||||||
t.equal(args[0].userAgent, 'foo', 'userAgent property was correct')
|
t.equal(args[0].userAgent, 'foo', 'userAgent property was correct')
|
||||||
t.equal(args[1], request, 'second argument was request object')
|
t.equal(metricsContext.gather.thisValues[0], request, 'this was request object')
|
||||||
|
|
||||||
t.equal(logger.info.callCount, 2, 'logger.info was called twice')
|
t.equal(logger.info.callCount, 2, 'logger.info was called twice')
|
||||||
t.equal(logger.info.args[0][0], 'activityEvent', 'first call was activityEvent')
|
t.equal(logger.info.args[0][0], 'activityEvent', 'first call was activityEvent')
|
||||||
|
@ -171,6 +172,7 @@ test(
|
||||||
'log.activityEvent with flow event and missing flowId',
|
'log.activityEvent with flow event and missing flowId',
|
||||||
function (t) {
|
function (t) {
|
||||||
var request = {
|
var request = {
|
||||||
|
gatherMetricsContext: metricsContext.gather,
|
||||||
headers: {
|
headers: {
|
||||||
'user-agent': 'foo'
|
'user-agent': 'foo'
|
||||||
},
|
},
|
||||||
|
@ -214,6 +216,7 @@ test(
|
||||||
'log.activityEvent with optional flow event and missing flowId',
|
'log.activityEvent with optional flow event and missing flowId',
|
||||||
function (t) {
|
function (t) {
|
||||||
var request = {
|
var request = {
|
||||||
|
gatherMetricsContext: metricsContext.gather,
|
||||||
headers: {
|
headers: {
|
||||||
'user-agent': 'foo'
|
'user-agent': 'foo'
|
||||||
},
|
},
|
||||||
|
@ -249,6 +252,7 @@ test(
|
||||||
'log.activityEvent with service payload parameter',
|
'log.activityEvent with service payload parameter',
|
||||||
function (t) {
|
function (t) {
|
||||||
return log.activityEvent('wibble', {
|
return log.activityEvent('wibble', {
|
||||||
|
gatherMetricsContext: metricsContext.gather,
|
||||||
headers: {},
|
headers: {},
|
||||||
payload: {
|
payload: {
|
||||||
metricsContext: {},
|
metricsContext: {},
|
||||||
|
@ -267,6 +271,7 @@ test(
|
||||||
t.equal(statsd.write.callCount, 1, 'statsd.write was called once')
|
t.equal(statsd.write.callCount, 1, 'statsd.write was called once')
|
||||||
t.equal(statsd.write.args[0][0], args[1], 'statsd.write argument was correct')
|
t.equal(statsd.write.args[0][0], args[1], 'statsd.write argument was correct')
|
||||||
|
|
||||||
|
t.equal(metricsContext.gather.callCount, 0, 'metricsContext.gather was not called')
|
||||||
t.equal(logger.debug.callCount, 0, 'logger.debug was not called')
|
t.equal(logger.debug.callCount, 0, 'logger.debug was not called')
|
||||||
t.equal(logger.error.callCount, 0, 'logger.error was not called')
|
t.equal(logger.error.callCount, 0, 'logger.error was not called')
|
||||||
t.equal(logger.critical.callCount, 0, 'logger.critical was not called')
|
t.equal(logger.critical.callCount, 0, 'logger.critical was not called')
|
||||||
|
@ -282,6 +287,7 @@ test(
|
||||||
'log.activityEvent with service query parameter',
|
'log.activityEvent with service query parameter',
|
||||||
function (t) {
|
function (t) {
|
||||||
return log.activityEvent('foo', {
|
return log.activityEvent('foo', {
|
||||||
|
gatherMetricsContext: metricsContext.gather,
|
||||||
headers: {},
|
headers: {},
|
||||||
payload: {
|
payload: {
|
||||||
metricsContext: {}
|
metricsContext: {}
|
||||||
|
@ -298,6 +304,7 @@ test(
|
||||||
t.equal(statsd.write.callCount, 1, 'statsd.write was called once')
|
t.equal(statsd.write.callCount, 1, 'statsd.write was called once')
|
||||||
t.equal(statsd.write.args[0][0], logger.info.args[0][1], 'statsd.write argument was correct')
|
t.equal(statsd.write.args[0][0], logger.info.args[0][1], 'statsd.write argument was correct')
|
||||||
|
|
||||||
|
t.equal(metricsContext.gather.callCount, 0, 'metricsContext.gather was not called')
|
||||||
t.equal(logger.debug.callCount, 0, 'logger.debug was not called')
|
t.equal(logger.debug.callCount, 0, 'logger.debug was not called')
|
||||||
t.equal(logger.error.callCount, 0, 'logger.error was not called')
|
t.equal(logger.error.callCount, 0, 'logger.error was not called')
|
||||||
t.equal(logger.critical.callCount, 0, 'logger.critical was not called')
|
t.equal(logger.critical.callCount, 0, 'logger.critical was not called')
|
||||||
|
@ -313,6 +320,7 @@ test(
|
||||||
'log.activityEvent with extra data',
|
'log.activityEvent with extra data',
|
||||||
function (t) {
|
function (t) {
|
||||||
return log.activityEvent('foo', {
|
return log.activityEvent('foo', {
|
||||||
|
gatherMetricsContext: metricsContext.gather,
|
||||||
headers: {
|
headers: {
|
||||||
'user-agent': 'bar'
|
'user-agent': 'bar'
|
||||||
},
|
},
|
||||||
|
@ -333,6 +341,7 @@ test(
|
||||||
t.equal(statsd.write.callCount, 1, 'statsd.write was called once')
|
t.equal(statsd.write.callCount, 1, 'statsd.write was called once')
|
||||||
t.equal(statsd.write.args[0][0], args[1], 'statsd.write argument was correct')
|
t.equal(statsd.write.args[0][0], args[1], 'statsd.write argument was correct')
|
||||||
|
|
||||||
|
t.equal(metricsContext.gather.callCount, 0, 'metricsContext.gather was not called')
|
||||||
t.equal(logger.debug.callCount, 0, 'logger.debug was not called')
|
t.equal(logger.debug.callCount, 0, 'logger.debug was not called')
|
||||||
t.equal(logger.error.callCount, 0, 'logger.error was not called')
|
t.equal(logger.error.callCount, 0, 'logger.error was not called')
|
||||||
t.equal(logger.critical.callCount, 0, 'logger.critical was not called')
|
t.equal(logger.critical.callCount, 0, 'logger.critical was not called')
|
||||||
|
@ -348,6 +357,7 @@ test(
|
||||||
'log.activityEvent with no data',
|
'log.activityEvent with no data',
|
||||||
function (t) {
|
function (t) {
|
||||||
return log.activityEvent('foo', {
|
return log.activityEvent('foo', {
|
||||||
|
gatherMetricsContext: metricsContext.gather,
|
||||||
headers: {},
|
headers: {},
|
||||||
payload: {
|
payload: {
|
||||||
metricsContext: {}
|
metricsContext: {}
|
||||||
|
@ -376,6 +386,7 @@ test(
|
||||||
'log.activityEvent with no uid',
|
'log.activityEvent with no uid',
|
||||||
function (t) {
|
function (t) {
|
||||||
return log.activityEvent('foo', {
|
return log.activityEvent('foo', {
|
||||||
|
gatherMetricsContext: metricsContext.gather,
|
||||||
headers: {},
|
headers: {},
|
||||||
payload: {
|
payload: {
|
||||||
metricsContext: {}
|
metricsContext: {}
|
||||||
|
@ -403,7 +414,18 @@ test(
|
||||||
test(
|
test(
|
||||||
'log.flowEvent with bad event name',
|
'log.flowEvent with bad event name',
|
||||||
t => {
|
t => {
|
||||||
return log.flowEvent(undefined).then(() => {
|
return log.flowEvent(undefined, {
|
||||||
|
gatherMetricsContext: metricsContext.gather,
|
||||||
|
headers: {
|
||||||
|
'user-agent': 'foo'
|
||||||
|
},
|
||||||
|
payload: {
|
||||||
|
metricsContext: {
|
||||||
|
flowId: 'bar',
|
||||||
|
service: 'baz'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).then(() => {
|
||||||
t.equal(logger.error.callCount, 1, 'logger.error was called once')
|
t.equal(logger.error.callCount, 1, 'logger.error was called once')
|
||||||
const args = logger.error.args[0]
|
const args = logger.error.args[0]
|
||||||
t.equal(args[0], 'log.flowEvent', 'correct op')
|
t.equal(args[0], 'log.flowEvent', 'correct op')
|
||||||
|
@ -423,7 +445,15 @@ test(
|
||||||
test(
|
test(
|
||||||
'log.flowEvent with a bad request',
|
'log.flowEvent with a bad request',
|
||||||
t => {
|
t => {
|
||||||
return log.flowEvent('account.signed').then(() => {
|
return log.flowEvent('account.signed', {
|
||||||
|
gatherMetricsContext: metricsContext.gather,
|
||||||
|
payload: {
|
||||||
|
metricsContext: {
|
||||||
|
flowId: 'foo',
|
||||||
|
service: 'bar'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).then(() => {
|
||||||
t.equal(logger.error.callCount, 1, 'logger.error was called once')
|
t.equal(logger.error.callCount, 1, 'logger.error was called once')
|
||||||
const args = logger.error.args[0]
|
const args = logger.error.args[0]
|
||||||
t.equal(args[0], 'log.flowEvent', 'correct op')
|
t.equal(args[0], 'log.flowEvent', 'correct op')
|
||||||
|
@ -445,6 +475,7 @@ test(
|
||||||
'log.flowEvent with content server account.signed event',
|
'log.flowEvent with content server account.signed event',
|
||||||
t => {
|
t => {
|
||||||
return log.flowEvent('account.signed', {
|
return log.flowEvent('account.signed', {
|
||||||
|
gatherMetricsContext: metricsContext.gather,
|
||||||
headers: {
|
headers: {
|
||||||
'user-agent': 'foo'
|
'user-agent': 'foo'
|
||||||
},
|
},
|
||||||
|
@ -473,6 +504,7 @@ test(
|
||||||
'log.flowEvent properly logs with no errors',
|
'log.flowEvent properly logs with no errors',
|
||||||
t => {
|
t => {
|
||||||
return log.flowEvent('account.signed', {
|
return log.flowEvent('account.signed', {
|
||||||
|
gatherMetricsContext: metricsContext.gather,
|
||||||
headers: {
|
headers: {
|
||||||
'user-agent': 'foo'
|
'user-agent': 'foo'
|
||||||
},
|
},
|
||||||
|
@ -508,6 +540,7 @@ test(
|
||||||
'log.flowEvent with flow event and missing flowId',
|
'log.flowEvent with flow event and missing flowId',
|
||||||
t => {
|
t => {
|
||||||
return log.flowEvent('account.login', {
|
return log.flowEvent('account.login', {
|
||||||
|
gatherMetricsContext: metricsContext.gather,
|
||||||
headers: {
|
headers: {
|
||||||
'user-agent': 'foo'
|
'user-agent': 'foo'
|
||||||
},
|
},
|
||||||
|
@ -539,6 +572,7 @@ test(
|
||||||
'log.flowEvent with optional flow event and missing flowId',
|
'log.flowEvent with optional flow event and missing flowId',
|
||||||
t => {
|
t => {
|
||||||
return log.flowEvent('account.keyfetch', {
|
return log.flowEvent('account.keyfetch', {
|
||||||
|
gatherMetricsContext: metricsContext.gather,
|
||||||
headers: {
|
headers: {
|
||||||
'user-agent': 'foo'
|
'user-agent': 'foo'
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,7 +10,8 @@ const test = require('../ptaptest')
|
||||||
const mocks = require('../mocks')
|
const mocks = require('../mocks')
|
||||||
const log = mocks.spyLog()
|
const log = mocks.spyLog()
|
||||||
const Memcached = require('memcached')
|
const Memcached = require('memcached')
|
||||||
const metricsContext = require('../../lib/metrics/context')(log, {
|
const metricsContextModule = require('../../lib/metrics/context')
|
||||||
|
const metricsContext = metricsContextModule(log, {
|
||||||
memcached: {
|
memcached: {
|
||||||
address: '127.0.0.1:1121',
|
address: '127.0.0.1:1121',
|
||||||
idle: 500,
|
idle: 500,
|
||||||
|
@ -22,21 +23,22 @@ const P = require('../../lib/promise')
|
||||||
test(
|
test(
|
||||||
'metricsContext interface is correct',
|
'metricsContext interface is correct',
|
||||||
function (t) {
|
function (t) {
|
||||||
|
t.equal(typeof metricsContextModule, 'function', 'function is exported')
|
||||||
|
t.equal(typeof metricsContextModule.schema, 'object', 'metricsContext.schema is object')
|
||||||
|
t.notEqual(metricsContextModule.schema, null, 'metricsContext.schema is not null')
|
||||||
|
|
||||||
t.equal(typeof metricsContext, 'object', 'metricsContext is object')
|
t.equal(typeof metricsContext, 'object', 'metricsContext is object')
|
||||||
t.notEqual(metricsContext, null, 'metricsContext is not null')
|
t.notEqual(metricsContext, null, 'metricsContext is not null')
|
||||||
t.equal(Object.keys(metricsContext).length, 4, 'metricsContext has 4 properties')
|
t.equal(Object.keys(metricsContext).length, 3, 'metricsContext has 3 properties')
|
||||||
|
|
||||||
t.equal(typeof metricsContext.schema, 'object', 'metricsContext.schema is object')
|
|
||||||
t.notEqual(metricsContext.schema, null, 'metricsContext.schema is not null')
|
|
||||||
|
|
||||||
t.equal(typeof metricsContext.stash, 'function', 'metricsContext.stash is function')
|
t.equal(typeof metricsContext.stash, 'function', 'metricsContext.stash is function')
|
||||||
t.equal(metricsContext.stash.length, 2, 'metricsContext.stash expects 2 arguments')
|
t.equal(metricsContext.stash.length, 1, 'metricsContext.stash expects 1 argument')
|
||||||
|
|
||||||
t.equal(typeof metricsContext.gather, 'function', 'metricsContext.gather is function')
|
t.equal(typeof metricsContext.gather, 'function', 'metricsContext.gather is function')
|
||||||
t.equal(metricsContext.gather.length, 2, 'metricsContext.gather expects 2 arguments')
|
t.equal(metricsContext.gather.length, 1, 'metricsContext.gather expects 1 argument')
|
||||||
|
|
||||||
t.equal(typeof metricsContext.validate, 'function', 'metricsContext.validate is function')
|
t.equal(typeof metricsContext.validate, 'function', 'metricsContext.validate is function')
|
||||||
t.equal(metricsContext.validate.length, 1, 'metricsContext.validate expects 1 argument')
|
t.equal(metricsContext.validate.length, 0, 'metricsContext.validate expects no arguments')
|
||||||
|
|
||||||
t.end()
|
t.end()
|
||||||
}
|
}
|
||||||
|
@ -53,10 +55,14 @@ test(
|
||||||
sinon.stub(Memcached.prototype, 'setAsync', function () {
|
sinon.stub(Memcached.prototype, 'setAsync', function () {
|
||||||
return P.resolve('wibble')
|
return P.resolve('wibble')
|
||||||
})
|
})
|
||||||
metricsContext.stash({
|
metricsContext.stash.call({
|
||||||
|
payload: {
|
||||||
|
metricsContext: 'bar'
|
||||||
|
}
|
||||||
|
}, {
|
||||||
uid: uid,
|
uid: uid,
|
||||||
id: id
|
id: id
|
||||||
}, 'bar').then(function (result) {
|
}).then(result => {
|
||||||
t.equal(result, 'wibble', 'result is correct')
|
t.equal(result, 'wibble', 'result is correct')
|
||||||
|
|
||||||
t.equal(Memcached.prototype.setAsync.callCount, 1, 'memcached.setAsync was called once')
|
t.equal(Memcached.prototype.setAsync.callCount, 1, 'memcached.setAsync was called once')
|
||||||
|
@ -80,10 +86,14 @@ test(
|
||||||
sinon.stub(Memcached.prototype, 'setAsync', function () {
|
sinon.stub(Memcached.prototype, 'setAsync', function () {
|
||||||
return P.reject('wibble')
|
return P.reject('wibble')
|
||||||
})
|
})
|
||||||
metricsContext.stash({
|
metricsContext.stash.call({
|
||||||
|
payload: {
|
||||||
|
metricsContext: 'bar'
|
||||||
|
}
|
||||||
|
}, {
|
||||||
uid: Buffer.alloc(32, 'cd'),
|
uid: Buffer.alloc(32, 'cd'),
|
||||||
id: 'foo'
|
id: 'foo'
|
||||||
}, 'bar').then(function (result) {
|
}).then(result => {
|
||||||
t.equal(result, undefined, 'result is undefined')
|
t.equal(result, undefined, 'result is undefined')
|
||||||
|
|
||||||
t.equal(Memcached.prototype.setAsync.callCount, 1, 'memcached.setAsync was called once')
|
t.equal(Memcached.prototype.setAsync.callCount, 1, 'memcached.setAsync was called once')
|
||||||
|
@ -102,14 +112,18 @@ test(
|
||||||
)
|
)
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'metricsContext.stash without token',
|
'metricsContext.stash with bad token',
|
||||||
function (t) {
|
function (t) {
|
||||||
sinon.stub(Memcached.prototype, 'setAsync', function () {
|
sinon.stub(Memcached.prototype, 'setAsync', function () {
|
||||||
return P.resolve('wibble')
|
return P.resolve('wibble')
|
||||||
})
|
})
|
||||||
metricsContext.stash({
|
metricsContext.stash.call({
|
||||||
|
payload: {
|
||||||
|
metricsContext: 'bar'
|
||||||
|
}
|
||||||
|
}, {
|
||||||
id: 'foo'
|
id: 'foo'
|
||||||
}, 'bar').then(function (result) {
|
}).then(result => {
|
||||||
t.equal(result, undefined, 'result is undefined')
|
t.equal(result, undefined, 'result is undefined')
|
||||||
|
|
||||||
t.equal(log.error.callCount, 1, 'log.error was called once')
|
t.equal(log.error.callCount, 1, 'log.error was called once')
|
||||||
|
@ -134,10 +148,12 @@ test(
|
||||||
sinon.stub(Memcached.prototype, 'setAsync', function () {
|
sinon.stub(Memcached.prototype, 'setAsync', function () {
|
||||||
return P.resolve('wibble')
|
return P.resolve('wibble')
|
||||||
})
|
})
|
||||||
metricsContext.stash({
|
metricsContext.stash.call({
|
||||||
|
payload: {}
|
||||||
|
}, {
|
||||||
uid: Buffer.alloc(32, 'cd'),
|
uid: Buffer.alloc(32, 'cd'),
|
||||||
id: 'foo'
|
id: 'foo'
|
||||||
}).then(function (result) {
|
}).then(result => {
|
||||||
t.equal(result, undefined, 'result is undefined')
|
t.equal(result, undefined, 'result is undefined')
|
||||||
|
|
||||||
t.equal(Memcached.prototype.setAsync.callCount, 0, 'memcached.setAsync was not called')
|
t.equal(Memcached.prototype.setAsync.callCount, 0, 'memcached.setAsync was not called')
|
||||||
|
@ -160,7 +176,7 @@ test(
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
var time = Date.now() - 1
|
var time = Date.now() - 1
|
||||||
metricsContext.gather({}, {
|
metricsContext.gather.call({
|
||||||
payload: {
|
payload: {
|
||||||
metricsContext: {
|
metricsContext: {
|
||||||
flowId: 'mock flow id',
|
flowId: 'mock flow id',
|
||||||
|
@ -177,7 +193,7 @@ test(
|
||||||
ignore: 'mock ignorable property'
|
ignore: 'mock ignorable property'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).then(function (result) {
|
}, {}).then(function (result) {
|
||||||
t.equal(typeof result, 'object', 'result is object')
|
t.equal(typeof result, 'object', 'result is object')
|
||||||
t.notEqual(result, null, 'result is not null')
|
t.notEqual(result, null, 'result is not null')
|
||||||
t.equal(Object.keys(result).length, 12, 'result has 12 properties')
|
t.equal(Object.keys(result).length, 12, 'result has 12 properties')
|
||||||
|
@ -208,13 +224,13 @@ test(
|
||||||
test(
|
test(
|
||||||
'metricsContext.gather with bad flowBeginTime',
|
'metricsContext.gather with bad flowBeginTime',
|
||||||
function (t) {
|
function (t) {
|
||||||
metricsContext.gather({}, {
|
metricsContext.gather.call({
|
||||||
payload: {
|
payload: {
|
||||||
metricsContext: {
|
metricsContext: {
|
||||||
flowBeginTime: Date.now() + 10000
|
flowBeginTime: Date.now() + 10000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).then(function (result) {
|
}, {}).then(function (result) {
|
||||||
t.equal(typeof result, 'object', 'result is object')
|
t.equal(typeof result, 'object', 'result is object')
|
||||||
t.notEqual(result, null, 'result is not null')
|
t.notEqual(result, null, 'result is not null')
|
||||||
t.strictEqual(result.flow_time, 0, 'result.time is zero')
|
t.strictEqual(result.flow_time, 0, 'result.time is zero')
|
||||||
|
@ -230,7 +246,7 @@ test(
|
||||||
'metricsContext.gather with DNT header',
|
'metricsContext.gather with DNT header',
|
||||||
function (t) {
|
function (t) {
|
||||||
var time = Date.now() - 1
|
var time = Date.now() - 1
|
||||||
metricsContext.gather({}, {
|
metricsContext.gather.call({
|
||||||
headers: {
|
headers: {
|
||||||
dnt: '1'
|
dnt: '1'
|
||||||
},
|
},
|
||||||
|
@ -250,7 +266,7 @@ test(
|
||||||
ignore: 'mock ignorable property'
|
ignore: 'mock ignorable property'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).then(function (result) {
|
}, {}).then(function (result) {
|
||||||
t.equal(Object.keys(result).length, 7, 'result has 7 properties')
|
t.equal(Object.keys(result).length, 7, 'result has 7 properties')
|
||||||
t.equal(result.utm_campaign, undefined, 'result.utm_campaign is undefined')
|
t.equal(result.utm_campaign, undefined, 'result.utm_campaign is undefined')
|
||||||
t.equal(result.utm_content, undefined, 'result.utm_content is undefined')
|
t.equal(result.utm_content, undefined, 'result.utm_content is undefined')
|
||||||
|
@ -290,14 +306,14 @@ test(
|
||||||
ignore: 'ignore me'
|
ignore: 'ignore me'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
metricsContext.gather({}, {
|
metricsContext.gather.call({
|
||||||
auth: {
|
auth: {
|
||||||
credentials: {
|
credentials: {
|
||||||
uid: uid,
|
uid: uid,
|
||||||
id: id
|
id: id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).then(function (result) {
|
}, {}).then(function (result) {
|
||||||
t.equal(Memcached.prototype.getAsync.callCount, 1, 'memcached.getAsync was called once')
|
t.equal(Memcached.prototype.getAsync.callCount, 1, 'memcached.getAsync was called once')
|
||||||
t.equal(Memcached.prototype.getAsync.args[0].length, 1, 'memcached.getAsync was passed one argument')
|
t.equal(Memcached.prototype.getAsync.args[0].length, 1, 'memcached.getAsync was passed one argument')
|
||||||
t.equal(Memcached.prototype.getAsync.args[0][0], hash.digest('base64'), 'memcached.getAsync argument was correct')
|
t.equal(Memcached.prototype.getAsync.args[0][0], hash.digest('base64'), 'memcached.getAsync argument was correct')
|
||||||
|
@ -328,6 +344,48 @@ test(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
'metricsContext.gather with fake token',
|
||||||
|
function (t) {
|
||||||
|
const time = Date.now() - 1
|
||||||
|
const uid = Buffer.alloc(32, '77')
|
||||||
|
const id = 'wibble'
|
||||||
|
const hash = crypto.createHash('sha256')
|
||||||
|
hash.update(uid)
|
||||||
|
hash.update(id)
|
||||||
|
sinon.stub(Memcached.prototype, 'getAsync', function () {
|
||||||
|
return P.resolve({
|
||||||
|
flowId: 'flowId',
|
||||||
|
flowBeginTime: time
|
||||||
|
})
|
||||||
|
})
|
||||||
|
metricsContext.gather.call({
|
||||||
|
payload: {
|
||||||
|
uid: uid.toString('hex'),
|
||||||
|
code: id
|
||||||
|
}
|
||||||
|
}, {}).then(function (result) {
|
||||||
|
t.equal(Memcached.prototype.getAsync.callCount, 1, 'memcached.getAsync was called once')
|
||||||
|
t.equal(Memcached.prototype.getAsync.args[0].length, 1, 'memcached.getAsync was passed one argument')
|
||||||
|
t.equal(Memcached.prototype.getAsync.args[0][0], hash.digest('base64'), 'memcached.getAsync argument was correct')
|
||||||
|
|
||||||
|
t.equal(typeof result, 'object', 'result is object')
|
||||||
|
t.notEqual(result, null, 'result is not null')
|
||||||
|
t.equal(Object.keys(result).length, 12, 'result has 12 properties')
|
||||||
|
t.ok(result.time > time, 'result.time seems correct')
|
||||||
|
t.equal(result.flow_id, 'flowId', 'result.flow_id is correct')
|
||||||
|
t.ok(result.flow_time > 0, 'result.flow_time is greater than zero')
|
||||||
|
t.ok(result.flow_time < time, 'result.flow_time is less than the current time')
|
||||||
|
|
||||||
|
t.equal(log.error.callCount, 0, 'log.error was not called')
|
||||||
|
|
||||||
|
Memcached.prototype.getAsync.restore()
|
||||||
|
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'metricsContext.gather with bad token',
|
'metricsContext.gather with bad token',
|
||||||
function (t) {
|
function (t) {
|
||||||
|
@ -337,13 +395,13 @@ test(
|
||||||
flowBeginTime: Date.now()
|
flowBeginTime: Date.now()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
metricsContext.gather({}, {
|
metricsContext.gather.call({
|
||||||
auth: {
|
auth: {
|
||||||
credentials: {
|
credentials: {
|
||||||
uid: Buffer.alloc(32, 'cd')
|
uid: Buffer.alloc(32, 'cd')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).then(function (result) {
|
}, {}).then(function (result) {
|
||||||
t.equal(typeof result, 'object', 'result is object')
|
t.equal(typeof result, 'object', 'result is object')
|
||||||
t.notEqual(result, null, 'result is not null')
|
t.notEqual(result, null, 'result is not null')
|
||||||
t.equal(Object.keys(result).length, 0, 'result is empty')
|
t.equal(Object.keys(result).length, 0, 'result is empty')
|
||||||
|
@ -362,6 +420,36 @@ test(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
test(
|
||||||
|
'metricsContext.gather with no token',
|
||||||
|
function (t) {
|
||||||
|
sinon.stub(Memcached.prototype, 'getAsync', function () {
|
||||||
|
return P.resolve({
|
||||||
|
flowId: 'flowId',
|
||||||
|
flowBeginTime: Date.now()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
metricsContext.gather.call({
|
||||||
|
auth: {}
|
||||||
|
}, {}).then(function (result) {
|
||||||
|
t.equal(typeof result, 'object', 'result is object')
|
||||||
|
t.notEqual(result, null, 'result is not null')
|
||||||
|
t.equal(Object.keys(result).length, 0, 'result is empty')
|
||||||
|
|
||||||
|
t.equal(log.error.callCount, 1, 'log.error was called once')
|
||||||
|
t.equal(log.error.args[0].length, 1, 'log.error was passed one argument')
|
||||||
|
t.equal(log.error.args[0][0].op, 'metricsContext.gather', 'op property was correct')
|
||||||
|
t.equal(log.error.args[0][0].err.message, 'Invalid credentials', 'err.message property was correct')
|
||||||
|
t.equal(log.error.args[0][0].token, undefined, 'token property was correct')
|
||||||
|
|
||||||
|
Memcached.prototype.getAsync.restore()
|
||||||
|
log.error.reset()
|
||||||
|
|
||||||
|
t.end()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'metricsContext.gather with metadata and token',
|
'metricsContext.gather with metadata and token',
|
||||||
function (t) {
|
function (t) {
|
||||||
|
@ -372,7 +460,7 @@ test(
|
||||||
flowBeginTime: time
|
flowBeginTime: time
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
metricsContext.gather({}, {
|
metricsContext.gather.call({
|
||||||
auth: {
|
auth: {
|
||||||
credentials: {
|
credentials: {
|
||||||
uid: Buffer.alloc(8, 'ff'),
|
uid: Buffer.alloc(8, 'ff'),
|
||||||
|
@ -385,7 +473,7 @@ test(
|
||||||
flowBeginTime: time
|
flowBeginTime: time
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).then(function (result) {
|
}, {}).then(function (result) {
|
||||||
t.equal(typeof result, 'object', 'result is object')
|
t.equal(typeof result, 'object', 'result is object')
|
||||||
t.notEqual(result, null, 'result is not null')
|
t.notEqual(result, null, 'result is not null')
|
||||||
t.equal(result.flow_id, 'baz', 'result.flow_id is correct')
|
t.equal(result.flow_id, 'baz', 'result.flow_id is correct')
|
||||||
|
@ -406,14 +494,14 @@ test(
|
||||||
sinon.stub(Memcached.prototype, 'getAsync', function () {
|
sinon.stub(Memcached.prototype, 'getAsync', function () {
|
||||||
return P.reject('foo')
|
return P.reject('foo')
|
||||||
})
|
})
|
||||||
metricsContext.gather({}, {
|
metricsContext.gather.call({
|
||||||
auth: {
|
auth: {
|
||||||
credentials: {
|
credentials: {
|
||||||
uid: Buffer.alloc(8, 'ff'),
|
uid: Buffer.alloc(8, 'ff'),
|
||||||
id: 'bar'
|
id: 'bar'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).then(function () {
|
}, {}).then(function () {
|
||||||
t.equal(log.error.callCount, 1, 'log.error was called once')
|
t.equal(log.error.callCount, 1, 'log.error was called once')
|
||||||
t.equal(log.error.args[0].length, 1, 'log.error was passed one argument')
|
t.equal(log.error.args[0].length, 1, 'log.error was passed one argument')
|
||||||
t.equal(log.error.args[0][0].op, 'metricsContext.gather', 'argument op property was correct')
|
t.equal(log.error.args[0][0].op, 'metricsContext.gather', 'argument op property was correct')
|
||||||
|
@ -445,7 +533,11 @@ test(
|
||||||
metricsContextWithoutMemcached.stash({
|
metricsContextWithoutMemcached.stash({
|
||||||
uid: Buffer.alloc(8, 'ff'),
|
uid: Buffer.alloc(8, 'ff'),
|
||||||
id: 'bar'
|
id: 'bar'
|
||||||
}, 'baz').then(function (result) {
|
}, {
|
||||||
|
payload: {
|
||||||
|
metricsContext: 'baz'
|
||||||
|
}
|
||||||
|
}).then(result => {
|
||||||
t.equal(result, undefined, 'result is undefined')
|
t.equal(result, undefined, 'result is undefined')
|
||||||
|
|
||||||
t.equal(Memcached.prototype.setAsync.callCount, 0, 'memcached.setAsync was not called')
|
t.equal(Memcached.prototype.setAsync.callCount, 0, 'memcached.setAsync was not called')
|
||||||
|
@ -474,14 +566,14 @@ test(
|
||||||
flowBeginTime: 42
|
flowBeginTime: 42
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
metricsContextWithoutMemcached.gather({}, {
|
metricsContextWithoutMemcached.gather.call({
|
||||||
auth: {
|
auth: {
|
||||||
credentials: {
|
credentials: {
|
||||||
uid: Buffer.alloc(8, 'ff'),
|
uid: Buffer.alloc(8, 'ff'),
|
||||||
id: 'baz'
|
id: 'baz'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).then(function () {
|
}, {}).then(function () {
|
||||||
t.equal(Memcached.prototype.getAsync.callCount, 0, 'memcached.getAsync was not called')
|
t.equal(Memcached.prototype.getAsync.callCount, 0, 'memcached.getAsync was not called')
|
||||||
t.equal(log.error.callCount, 0, 'log.error was not called')
|
t.equal(log.error.callCount, 0, 'log.error was not called')
|
||||||
|
|
||||||
|
@ -514,7 +606,7 @@ test(
|
||||||
}
|
}
|
||||||
|
|
||||||
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
|
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
|
||||||
var valid = metricsContext.validate(mockRequest)
|
var valid = metricsContext.validate.call(mockRequest)
|
||||||
|
|
||||||
t.notOk(valid, 'the data is treated as invalid')
|
t.notOk(valid, 'the data is treated as invalid')
|
||||||
t.equal(mockLog.info.callCount, 0, 'log.info was not called')
|
t.equal(mockLog.info.callCount, 0, 'log.info was not called')
|
||||||
|
@ -551,7 +643,7 @@ test(
|
||||||
}
|
}
|
||||||
|
|
||||||
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
|
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
|
||||||
var valid = metricsContext.validate(mockRequest)
|
var valid = metricsContext.validate.call(mockRequest)
|
||||||
|
|
||||||
t.notOk(valid, 'the data is treated as invalid')
|
t.notOk(valid, 'the data is treated as invalid')
|
||||||
t.notOk(mockRequest.payload.metricsContext.flowBeginTime, 'the invalid flow data was removed')
|
t.notOk(mockRequest.payload.metricsContext.flowBeginTime, 'the invalid flow data was removed')
|
||||||
|
@ -589,7 +681,7 @@ test(
|
||||||
}
|
}
|
||||||
|
|
||||||
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
|
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
|
||||||
var valid = metricsContext.validate(mockRequest)
|
var valid = metricsContext.validate.call(mockRequest)
|
||||||
|
|
||||||
t.notOk(valid, 'the data is treated as invalid')
|
t.notOk(valid, 'the data is treated as invalid')
|
||||||
t.notOk(mockRequest.payload.metricsContext.flowId, 'the invalid flow data was removed')
|
t.notOk(mockRequest.payload.metricsContext.flowId, 'the invalid flow data was removed')
|
||||||
|
@ -628,7 +720,7 @@ test(
|
||||||
}
|
}
|
||||||
|
|
||||||
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
|
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
|
||||||
var valid = metricsContext.validate(mockRequest)
|
var valid = metricsContext.validate.call(mockRequest)
|
||||||
|
|
||||||
t.notOk(valid, 'the data is treated as invalid')
|
t.notOk(valid, 'the data is treated as invalid')
|
||||||
t.notOk(mockRequest.payload.metricsContext.flowId, 'the invalid flow data was removed')
|
t.notOk(mockRequest.payload.metricsContext.flowId, 'the invalid flow data was removed')
|
||||||
|
@ -667,7 +759,7 @@ test(
|
||||||
}
|
}
|
||||||
|
|
||||||
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
|
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
|
||||||
var valid = metricsContext.validate(mockRequest)
|
var valid = metricsContext.validate.call(mockRequest)
|
||||||
|
|
||||||
t.notOk(valid, 'the data is treated as invalid')
|
t.notOk(valid, 'the data is treated as invalid')
|
||||||
t.notOk(mockRequest.payload.metricsContext.flowId, 'the invalid flow data was removed')
|
t.notOk(mockRequest.payload.metricsContext.flowId, 'the invalid flow data was removed')
|
||||||
|
@ -713,7 +805,7 @@ test(
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
|
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
|
||||||
var valid = metricsContext.validate(mockRequest)
|
var valid = metricsContext.validate.call(mockRequest)
|
||||||
} finally {
|
} finally {
|
||||||
Date.now.restore()
|
Date.now.restore()
|
||||||
}
|
}
|
||||||
|
@ -762,7 +854,7 @@ test(
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
|
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
|
||||||
var valid = metricsContext.validate(mockRequest)
|
var valid = metricsContext.validate.call(mockRequest)
|
||||||
} finally {
|
} finally {
|
||||||
Date.now.restore()
|
Date.now.restore()
|
||||||
}
|
}
|
||||||
|
@ -811,7 +903,7 @@ test(
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
|
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
|
||||||
var valid = metricsContext.validate(mockRequest)
|
var valid = metricsContext.validate.call(mockRequest)
|
||||||
} finally {
|
} finally {
|
||||||
Date.now.restore()
|
Date.now.restore()
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ var makeRoutes = function (options) {
|
||||||
var Password = require('../../lib/crypto/password')(log, config)
|
var Password = require('../../lib/crypto/password')(log, config)
|
||||||
var customs = options.customs || {}
|
var customs = options.customs || {}
|
||||||
var checkPassword = require('../../lib/routes/utils/password_check')(log, config, Password, customs, db)
|
var checkPassword = require('../../lib/routes/utils/password_check')(log, config, Password, customs, db)
|
||||||
var metricsContext = options.metricsContext || log.metricsContext || require('../../lib/metrics/context')(log, config)
|
|
||||||
return require('../../lib/routes/password')(
|
return require('../../lib/routes/password')(
|
||||||
log,
|
log,
|
||||||
isA,
|
isA,
|
||||||
|
@ -38,8 +37,7 @@ var makeRoutes = function (options) {
|
||||||
config.verifierVersion,
|
config.verifierVersion,
|
||||||
options.customs || {},
|
options.customs || {},
|
||||||
checkPassword,
|
checkPassword,
|
||||||
options.push || {},
|
options.push || {}
|
||||||
metricsContext
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -267,6 +267,8 @@ function spyLog (methods) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function mockRequest (data) {
|
function mockRequest (data) {
|
||||||
|
const metricsContext = data.metricsContext || module.exports.mockMetricsContext()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
app: {
|
app: {
|
||||||
acceptLanguage: 'en-US',
|
acceptLanguage: 'en-US',
|
||||||
|
@ -275,11 +277,14 @@ function mockRequest (data) {
|
||||||
auth: {
|
auth: {
|
||||||
credentials: data.credentials
|
credentials: data.credentials
|
||||||
},
|
},
|
||||||
|
gatherMetricsContext: metricsContext.gather,
|
||||||
headers: {
|
headers: {
|
||||||
'user-agent': 'test user-agent'
|
'user-agent': 'test user-agent'
|
||||||
},
|
},
|
||||||
|
payload: data.payload,
|
||||||
query: data.query,
|
query: data.query,
|
||||||
payload: data.payload
|
stashMetricsContext: metricsContext.stash,
|
||||||
|
validateMetricsContext: metricsContext.validate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче