Merge pull request #16038 from mozilla/FXA-8265-login-complete-glean

feat(metrics): emit a login_complete glean event on login completion
This commit is contained in:
Barry Chen 2023-11-08 12:54:33 -06:00 коммит произвёл GitHub
Родитель 320c6c190b fdfb840db9
Коммит 3f8deef7be
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 64 добавлений и 9 удалений

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

@ -82,7 +82,7 @@ function shouldLogFlowEvent(event, service) {
return true;
}
module.exports = (log, config) => {
module.exports = (log, config, glean) => {
const amplitude = require('./amplitude')(log, config);
return {
@ -140,6 +140,10 @@ module.exports = (log, config) => {
});
await amplitude('flow.complete', request, data, metricsContext);
if (metricsContext.flowType === 'login') {
glean.login.complete(request, { uid: data?.uid ?? '' });
}
return request.clearMetricsContext();
}
},

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

@ -136,6 +136,7 @@ export function gleanMetrics(config: ConfigType) {
totpFailure: createEventFn('login_totp_code_failure'),
verifyCodeEmailSent: createEventFn('login_email_confirmation_sent'),
verifyCodeConfirmed: createEventFn('login_email_confirmation_success'),
complete: createEventFn('login_complete'),
},
resetPassword: {

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

@ -68,7 +68,7 @@ function logEndpointErrors(response, log) {
async function create(log, error, config, routes, db, statsd, glean) {
const getGeoData = require('./geodb')(log);
const metricsContext = require('./metrics/context')(log, config);
const metricsEvents = require('./metrics/events')(log, config);
const metricsEvents = require('./metrics/events')(log, config, glean);
const { sharedSecret: SUBSCRIPTIONS_SECRET } = config.subscriptions;
// Hawk needs to calculate request signatures based on public URL,

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

@ -14,6 +14,8 @@ const log = {
info: sinon.spy(),
trace: sinon.spy(),
};
const mocks = require('../../mocks');
const glean = mocks.mockGlean();
const proxyquire = require('proxyquire');
const amplitudeModule = proxyquire('../../../lib/metrics/amplitude', {
'fxa-shared/db/models/auth': {
@ -24,16 +26,23 @@ const amplitudeModule = proxyquire('../../../lib/metrics/amplitude', {
});
const events = proxyquire('../../../lib/metrics/events', {
'./amplitude': amplitudeModule,
})(log, {
})(
log,
{
amplitude: { rawEvents: false },
oauth: {
clientIds: {},
},
verificationReminders: {},
});
const mocks = require('../../mocks');
},
glean
);
describe('metrics/events', () => {
beforeEach(() => {
glean.login.complete.reset();
});
afterEach(() => {
log.activityEvent.resetHistory();
log.amplitudeEvent.resetHistory();
@ -1201,6 +1210,47 @@ describe('metrics/events', () => {
});
});
it('.emit on login flow complete', () => {
const time = Date.now();
sinon.stub(Date, 'now').callsFake(() => time);
const metricsContext = mocks.mockMetricsContext();
const request = mocks.mockRequest({
credentials: {
uid: 'deadbeef',
},
metricsContext,
payload: {
metricsContext: {
entrypoint: 'wibble',
entrypointExperiment: 'exp',
entrypointVariation: 'var',
flowId: 'bar',
flowBeginTime: time - 1000,
flowCompleteSignal: 'account.signed',
flowType: 'login',
planId: 'planId',
productId: 'productId',
utmCampaign: 'utm campaign',
utmContent: 'utm content',
utmMedium: 'utm medium',
utmSource: 'utm source',
utmTerm: 'utm term',
},
service: 'baz',
},
});
return events.emit
.call(request, 'account.signed', { uid: 'quux' })
.then(() => {
sinon.assert.calledOnceWithExactly(glean.login.complete, request, {
uid: 'quux',
});
})
.finally(() => {
Date.now.restore();
});
});
it('.emitRouteFlowEvent with matching route and response.statusCode', () => {
const time = Date.now();
sinon.stub(Date, 'now').callsFake(() => time);