mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-29 06:33:40 -05:00
Merge pull request #17731 from overleaf/em-promisify-error-recorder
Promisify ErrorRecorder GitOrigin-RevId: 3736567272a09b4e3b9075118460392c1f66f0d7
This commit is contained in:
parent
f03e3fd51e
commit
3b555ac9e6
2 changed files with 214 additions and 293 deletions
|
@ -1,32 +1,9 @@
|
||||||
// TODO: This file was created by bulk-decaffeinate.
|
import { callbackify } from 'util'
|
||||||
// Fix any style issues and re-enable lint.
|
|
||||||
/*
|
|
||||||
* decaffeinate suggestions:
|
|
||||||
* DS101: Remove unnecessary use of Array.from
|
|
||||||
* DS102: Remove unnecessary code created because of implicit returns
|
|
||||||
* DS207: Consider shorter variations of null checks
|
|
||||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
|
||||||
*/
|
|
||||||
import { promisify } from 'util'
|
|
||||||
import logger from '@overleaf/logger'
|
import logger from '@overleaf/logger'
|
||||||
import metrics from '@overleaf/metrics'
|
import metrics from '@overleaf/metrics'
|
||||||
import OError from '@overleaf/o-error'
|
|
||||||
import { db } from './mongodb.js'
|
import { db } from './mongodb.js'
|
||||||
|
|
||||||
export function record(projectId, queueSize, error, callback) {
|
async function record(projectId, queueSize, error) {
|
||||||
if (callback == null) {
|
|
||||||
callback = function () {}
|
|
||||||
}
|
|
||||||
const _callback = function (mongoError) {
|
|
||||||
if (mongoError != null) {
|
|
||||||
logger.error(
|
|
||||||
{ projectId, mongoError },
|
|
||||||
'failed to change project statues in mongo'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return callback(error || null, queueSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
const errorRecord = {
|
const errorRecord = {
|
||||||
queueSize,
|
queueSize,
|
||||||
|
@ -38,69 +15,62 @@ export function record(projectId, queueSize, error, callback) {
|
||||||
{ projectId, errorRecord },
|
{ projectId, errorRecord },
|
||||||
'recording failed attempt to process updates'
|
'recording failed attempt to process updates'
|
||||||
)
|
)
|
||||||
return db.projectHistoryFailures.updateOne(
|
try {
|
||||||
{
|
await db.projectHistoryFailures.updateOne(
|
||||||
project_id: projectId,
|
{ project_id: projectId },
|
||||||
},
|
{
|
||||||
{
|
$set: errorRecord,
|
||||||
$set: errorRecord,
|
$inc: { attempts: 1 },
|
||||||
$inc: {
|
$push: {
|
||||||
attempts: 1,
|
history: {
|
||||||
|
$each: [errorRecord],
|
||||||
|
$position: 0,
|
||||||
|
$slice: 10,
|
||||||
|
},
|
||||||
|
}, // only keep recent failures
|
||||||
},
|
},
|
||||||
$push: {
|
{ upsert: true }
|
||||||
history: {
|
)
|
||||||
$each: [errorRecord],
|
} catch (mongoError) {
|
||||||
$position: 0,
|
logger.error(
|
||||||
$slice: 10,
|
{ projectId, mongoError },
|
||||||
},
|
'failed to change project statues in mongo'
|
||||||
}, // only keep recent failures
|
)
|
||||||
},
|
}
|
||||||
{
|
throw error
|
||||||
upsert: true,
|
|
||||||
},
|
|
||||||
_callback
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
return db.projectHistoryFailures.deleteOne(
|
try {
|
||||||
{ project_id: projectId },
|
await db.projectHistoryFailures.deleteOne({ project_id: projectId })
|
||||||
_callback
|
} catch (mongoError) {
|
||||||
)
|
logger.error(
|
||||||
|
{ projectId, mongoError },
|
||||||
|
'failed to change project statues in mongo'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return queueSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setForceDebug(projectId, state, callback) {
|
async function setForceDebug(projectId, state) {
|
||||||
if (state == null) {
|
if (state == null) {
|
||||||
state = true
|
state = true
|
||||||
}
|
}
|
||||||
if (callback == null) {
|
|
||||||
callback = function () {}
|
|
||||||
}
|
|
||||||
logger.debug({ projectId, state }, 'setting forceDebug state for project')
|
logger.debug({ projectId, state }, 'setting forceDebug state for project')
|
||||||
return db.projectHistoryFailures.updateOne(
|
await db.projectHistoryFailures.updateOne(
|
||||||
{ project_id: projectId },
|
{ project_id: projectId },
|
||||||
{ $set: { forceDebug: state } },
|
{ $set: { forceDebug: state } },
|
||||||
{ upsert: true },
|
{ upsert: true }
|
||||||
callback
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// we only record the sync start time, and not the end time, because the
|
// we only record the sync start time, and not the end time, because the
|
||||||
// record should be cleared on success.
|
// record should be cleared on success.
|
||||||
export function recordSyncStart(projectId, callback) {
|
async function recordSyncStart(projectId) {
|
||||||
if (callback == null) {
|
await db.projectHistoryFailures.updateOne(
|
||||||
callback = function () {}
|
{ project_id: projectId },
|
||||||
}
|
|
||||||
return db.projectHistoryFailures.updateOne(
|
|
||||||
{
|
{
|
||||||
project_id: projectId,
|
$currentDate: { resyncStartedAt: true },
|
||||||
},
|
$inc: { resyncAttempts: 1 },
|
||||||
{
|
|
||||||
$currentDate: {
|
|
||||||
resyncStartedAt: true,
|
|
||||||
},
|
|
||||||
$inc: {
|
|
||||||
resyncAttempts: 1,
|
|
||||||
},
|
|
||||||
$push: {
|
$push: {
|
||||||
history: {
|
history: {
|
||||||
$each: [{ resyncStartedAt: new Date() }],
|
$each: [{ resyncStartedAt: new Date() }],
|
||||||
|
@ -109,207 +79,176 @@ export function recordSyncStart(projectId, callback) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{ upsert: true }
|
||||||
upsert: true,
|
|
||||||
},
|
|
||||||
callback
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFailureRecord(projectId, callback) {
|
async function getFailureRecord(projectId) {
|
||||||
if (callback == null) {
|
return await db.projectHistoryFailures.findOne({ project_id: projectId })
|
||||||
callback = function () {}
|
|
||||||
}
|
|
||||||
return db.projectHistoryFailures.findOne({ project_id: projectId }, callback)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLastFailure(projectId, callback) {
|
async function getLastFailure(projectId) {
|
||||||
if (callback == null) {
|
const result = await db.projectHistoryFailures.findOneAndUpdate(
|
||||||
callback = function () {}
|
|
||||||
}
|
|
||||||
return db.projectHistoryFailures.findOneAndUpdate(
|
|
||||||
{ project_id: projectId },
|
{ project_id: projectId },
|
||||||
{ $inc: { requestCount: 1 } }, // increment the request count every time we check the last failure
|
{ $inc: { requestCount: 1 } }, // increment the request count every time we check the last failure
|
||||||
{ projection: { error: 1, ts: 1 } },
|
{ projection: { error: 1, ts: 1 } }
|
||||||
(err, result) => callback(err, result && result.value)
|
|
||||||
)
|
)
|
||||||
|
return result && result.value
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFailedProjects(callback) {
|
async function getFailedProjects() {
|
||||||
if (callback == null) {
|
return await db.projectHistoryFailures.find({}).toArray()
|
||||||
callback = function () {}
|
|
||||||
}
|
|
||||||
return db.projectHistoryFailures.find({}).toArray(function (error, results) {
|
|
||||||
if (error != null) {
|
|
||||||
return callback(OError.tag(error))
|
|
||||||
}
|
|
||||||
return callback(null, results)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFailuresByType(callback) {
|
async function getFailuresByType() {
|
||||||
if (callback == null) {
|
const results = await db.projectHistoryFailures.find({}).toArray()
|
||||||
callback = function () {}
|
const failureCounts = {}
|
||||||
|
const failureAttempts = {}
|
||||||
|
const failureRequests = {}
|
||||||
|
const maxQueueSize = {}
|
||||||
|
// count all the failures and number of attempts by type
|
||||||
|
for (const result of results || []) {
|
||||||
|
const failureType = result.error
|
||||||
|
const attempts = result.attempts || 1 // allow for field to be absent
|
||||||
|
const requests = result.requestCount || 0
|
||||||
|
const queueSize = result.queueSize || 0
|
||||||
|
if (failureCounts[failureType] > 0) {
|
||||||
|
failureCounts[failureType]++
|
||||||
|
failureAttempts[failureType] += attempts
|
||||||
|
failureRequests[failureType] += requests
|
||||||
|
maxQueueSize[failureType] = Math.max(queueSize, maxQueueSize[failureType])
|
||||||
|
} else {
|
||||||
|
failureCounts[failureType] = 1
|
||||||
|
failureAttempts[failureType] = attempts
|
||||||
|
failureRequests[failureType] = requests
|
||||||
|
maxQueueSize[failureType] = queueSize
|
||||||
|
}
|
||||||
}
|
}
|
||||||
db.projectHistoryFailures.find({}).toArray(function (error, results) {
|
|
||||||
if (error != null) {
|
return { failureCounts, failureAttempts, failureRequests, maxQueueSize }
|
||||||
return callback(OError.tag(error))
|
}
|
||||||
}
|
|
||||||
const failureCounts = {}
|
async function getFailures() {
|
||||||
const failureAttempts = {}
|
const { failureCounts, failureAttempts, failureRequests, maxQueueSize } =
|
||||||
const failureRequests = {}
|
await getFailuresByType()
|
||||||
const maxQueueSize = {}
|
|
||||||
// count all the failures and number of attempts by type
|
let attempts, failureType, label, requests
|
||||||
for (const result of Array.from(results || [])) {
|
const shortNames = {
|
||||||
const failureType = result.error
|
'Error: bad response from filestore: 404': 'filestore-404',
|
||||||
const attempts = result.attempts || 1 // allow for field to be absent
|
'Error: bad response from filestore: 500': 'filestore-500',
|
||||||
const requests = result.requestCount || 0
|
'NotFoundError: got a 404 from web api': 'web-api-404',
|
||||||
const queueSize = result.queueSize || 0
|
'Error: history store a non-success status code: 413': 'history-store-413',
|
||||||
if (failureCounts[failureType] > 0) {
|
'Error: history store a non-success status code: 422': 'history-store-422',
|
||||||
failureCounts[failureType]++
|
'Error: history store a non-success status code: 500': 'history-store-500',
|
||||||
failureAttempts[failureType] += attempts
|
'Error: history store a non-success status code: 503': 'history-store-503',
|
||||||
failureRequests[failureType] += requests
|
'Error: web returned a non-success status code: 500 (attempts: 2)':
|
||||||
maxQueueSize[failureType] = Math.max(
|
'web-500',
|
||||||
queueSize,
|
'Error: ESOCKETTIMEDOUT': 'socket-timeout',
|
||||||
maxQueueSize[failureType]
|
'Error: no project found': 'no-project-found',
|
||||||
)
|
'OpsOutOfOrderError: project structure version out of order on incoming updates':
|
||||||
} else {
|
'incoming-project-version-out-of-order',
|
||||||
failureCounts[failureType] = 1
|
'OpsOutOfOrderError: doc version out of order on incoming updates':
|
||||||
failureAttempts[failureType] = attempts
|
'incoming-doc-version-out-of-order',
|
||||||
failureRequests[failureType] = requests
|
'OpsOutOfOrderError: project structure version out of order':
|
||||||
maxQueueSize[failureType] = queueSize
|
'chunk-project-version-out-of-order',
|
||||||
}
|
'OpsOutOfOrderError: doc version out of order':
|
||||||
}
|
'chunk-doc-version-out-of-order',
|
||||||
return callback(
|
'Error: failed to extend lock': 'lock-overrun',
|
||||||
null,
|
'Error: tried to release timed out lock': 'lock-overrun',
|
||||||
failureCounts,
|
'Error: Timeout': 'lock-overrun',
|
||||||
failureAttempts,
|
'Error: sync ongoing': 'sync-ongoing',
|
||||||
failureRequests,
|
'SyncError: unexpected resyncProjectStructure update': 'sync-error',
|
||||||
maxQueueSize
|
'[object Error]': 'unknown-error-object',
|
||||||
|
'UpdateWithUnknownFormatError: update with unknown format':
|
||||||
|
'unknown-format',
|
||||||
|
'Error: update with unknown format': 'unknown-format',
|
||||||
|
'TextOperationError: The base length of the second operation has to be the target length of the first operation':
|
||||||
|
'text-op-error',
|
||||||
|
'Error: ENOSPC: no space left on device, write': 'ENOSPC',
|
||||||
|
'*': 'other',
|
||||||
|
}
|
||||||
|
|
||||||
|
// set all the known errors to zero if not present (otherwise gauges stay on their last value)
|
||||||
|
const summaryCounts = {}
|
||||||
|
const summaryAttempts = {}
|
||||||
|
const summaryRequests = {}
|
||||||
|
const summaryMaxQueueSize = {}
|
||||||
|
|
||||||
|
for (failureType in shortNames) {
|
||||||
|
label = shortNames[failureType]
|
||||||
|
summaryCounts[label] = 0
|
||||||
|
summaryAttempts[label] = 0
|
||||||
|
summaryRequests[label] = 0
|
||||||
|
summaryMaxQueueSize[label] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// record a metric for each type of failure
|
||||||
|
for (failureType in failureCounts) {
|
||||||
|
const failureCount = failureCounts[failureType]
|
||||||
|
label = shortNames[failureType] || shortNames['*']
|
||||||
|
summaryCounts[label] += failureCount
|
||||||
|
summaryAttempts[label] += failureAttempts[failureType]
|
||||||
|
summaryRequests[label] += failureRequests[failureType]
|
||||||
|
summaryMaxQueueSize[label] = Math.max(
|
||||||
|
maxQueueSize[failureType],
|
||||||
|
summaryMaxQueueSize[label]
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
|
|
||||||
|
for (label in summaryCounts) {
|
||||||
|
const count = summaryCounts[label]
|
||||||
|
metrics.globalGauge('failed', count, 1, { status: label })
|
||||||
|
}
|
||||||
|
|
||||||
|
for (label in summaryAttempts) {
|
||||||
|
attempts = summaryAttempts[label]
|
||||||
|
metrics.globalGauge('attempts', attempts, 1, { status: label })
|
||||||
|
}
|
||||||
|
|
||||||
|
for (label in summaryRequests) {
|
||||||
|
requests = summaryRequests[label]
|
||||||
|
metrics.globalGauge('requests', requests, 1, { status: label })
|
||||||
|
}
|
||||||
|
|
||||||
|
for (label in summaryMaxQueueSize) {
|
||||||
|
const queueSize = summaryMaxQueueSize[label]
|
||||||
|
metrics.globalGauge('max-queue-size', queueSize, 1, { status: label })
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
counts: summaryCounts,
|
||||||
|
attempts: summaryAttempts,
|
||||||
|
requests: summaryRequests,
|
||||||
|
maxQueueSize: summaryMaxQueueSize,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFailures(callback) {
|
// EXPORTS
|
||||||
if (callback == null) {
|
|
||||||
callback = function () {}
|
|
||||||
}
|
|
||||||
return getFailuresByType(
|
|
||||||
function (
|
|
||||||
error,
|
|
||||||
failureCounts,
|
|
||||||
failureAttempts,
|
|
||||||
failureRequests,
|
|
||||||
maxQueueSize
|
|
||||||
) {
|
|
||||||
let attempts, failureType, label, requests
|
|
||||||
if (error != null) {
|
|
||||||
return callback(OError.tag(error))
|
|
||||||
}
|
|
||||||
|
|
||||||
const shortNames = {
|
const getFailedProjectsCb = callbackify(getFailedProjects)
|
||||||
'Error: bad response from filestore: 404': 'filestore-404',
|
const getFailureRecordCb = callbackify(getFailureRecord)
|
||||||
'Error: bad response from filestore: 500': 'filestore-500',
|
const getFailuresCb = callbackify(getFailures)
|
||||||
'NotFoundError: got a 404 from web api': 'web-api-404',
|
const getLastFailureCb = callbackify(getLastFailure)
|
||||||
'Error: history store a non-success status code: 413':
|
const recordCb = callbackify(record)
|
||||||
'history-store-413',
|
const recordSyncStartCb = callbackify(recordSyncStart)
|
||||||
'Error: history store a non-success status code: 422':
|
const setForceDebugCb = callbackify(setForceDebug)
|
||||||
'history-store-422',
|
|
||||||
'Error: history store a non-success status code: 500':
|
|
||||||
'history-store-500',
|
|
||||||
'Error: history store a non-success status code: 503':
|
|
||||||
'history-store-503',
|
|
||||||
'Error: web returned a non-success status code: 500 (attempts: 2)':
|
|
||||||
'web-500',
|
|
||||||
'Error: ESOCKETTIMEDOUT': 'socket-timeout',
|
|
||||||
'Error: no project found': 'no-project-found',
|
|
||||||
'OpsOutOfOrderError: project structure version out of order on incoming updates':
|
|
||||||
'incoming-project-version-out-of-order',
|
|
||||||
'OpsOutOfOrderError: doc version out of order on incoming updates':
|
|
||||||
'incoming-doc-version-out-of-order',
|
|
||||||
'OpsOutOfOrderError: project structure version out of order':
|
|
||||||
'chunk-project-version-out-of-order',
|
|
||||||
'OpsOutOfOrderError: doc version out of order':
|
|
||||||
'chunk-doc-version-out-of-order',
|
|
||||||
'Error: failed to extend lock': 'lock-overrun',
|
|
||||||
'Error: tried to release timed out lock': 'lock-overrun',
|
|
||||||
'Error: Timeout': 'lock-overrun',
|
|
||||||
'Error: sync ongoing': 'sync-ongoing',
|
|
||||||
'SyncError: unexpected resyncProjectStructure update': 'sync-error',
|
|
||||||
'[object Error]': 'unknown-error-object',
|
|
||||||
'UpdateWithUnknownFormatError: update with unknown format':
|
|
||||||
'unknown-format',
|
|
||||||
'Error: update with unknown format': 'unknown-format',
|
|
||||||
'TextOperationError: The base length of the second operation has to be the target length of the first operation':
|
|
||||||
'text-op-error',
|
|
||||||
'Error: ENOSPC: no space left on device, write': 'ENOSPC',
|
|
||||||
'*': 'other',
|
|
||||||
}
|
|
||||||
|
|
||||||
// set all the known errors to zero if not present (otherwise gauges stay on their last value)
|
export {
|
||||||
const summaryCounts = {}
|
getFailedProjectsCb as getFailedProjects,
|
||||||
const summaryAttempts = {}
|
getFailureRecordCb as getFailureRecord,
|
||||||
const summaryRequests = {}
|
getLastFailureCb as getLastFailure,
|
||||||
const summaryMaxQueueSize = {}
|
getFailuresCb as getFailures,
|
||||||
|
recordCb as record,
|
||||||
for (failureType in shortNames) {
|
recordSyncStartCb as recordSyncStart,
|
||||||
label = shortNames[failureType]
|
setForceDebugCb as setForceDebug,
|
||||||
summaryCounts[label] = 0
|
|
||||||
summaryAttempts[label] = 0
|
|
||||||
summaryRequests[label] = 0
|
|
||||||
summaryMaxQueueSize[label] = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// record a metric for each type of failure
|
|
||||||
for (failureType in failureCounts) {
|
|
||||||
const failureCount = failureCounts[failureType]
|
|
||||||
label = shortNames[failureType] || shortNames['*']
|
|
||||||
summaryCounts[label] += failureCount
|
|
||||||
summaryAttempts[label] += failureAttempts[failureType]
|
|
||||||
summaryRequests[label] += failureRequests[failureType]
|
|
||||||
summaryMaxQueueSize[label] = Math.max(
|
|
||||||
maxQueueSize[failureType],
|
|
||||||
summaryMaxQueueSize[label]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (label in summaryCounts) {
|
|
||||||
const count = summaryCounts[label]
|
|
||||||
metrics.globalGauge('failed', count, 1, { status: label })
|
|
||||||
}
|
|
||||||
|
|
||||||
for (label in summaryAttempts) {
|
|
||||||
attempts = summaryAttempts[label]
|
|
||||||
metrics.globalGauge('attempts', attempts, 1, { status: label })
|
|
||||||
}
|
|
||||||
|
|
||||||
for (label in summaryRequests) {
|
|
||||||
requests = summaryRequests[label]
|
|
||||||
metrics.globalGauge('requests', requests, 1, { status: label })
|
|
||||||
}
|
|
||||||
|
|
||||||
for (label in summaryMaxQueueSize) {
|
|
||||||
const queueSize = summaryMaxQueueSize[label]
|
|
||||||
metrics.globalGauge('max-queue-size', queueSize, 1, { status: label })
|
|
||||||
}
|
|
||||||
|
|
||||||
return callback(null, {
|
|
||||||
counts: summaryCounts,
|
|
||||||
attempts: summaryAttempts,
|
|
||||||
requests: summaryRequests,
|
|
||||||
maxQueueSize: summaryMaxQueueSize,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const promises = {
|
export const promises = {
|
||||||
getFailedProjects: promisify(getFailedProjects),
|
getFailedProjects,
|
||||||
getFailureRecord: promisify(getFailureRecord),
|
getFailureRecord,
|
||||||
getLastFailure: promisify(getLastFailure),
|
getLastFailure,
|
||||||
getFailuresByType: promisify(getFailuresByType),
|
getFailures,
|
||||||
getFailures: promisify(getFailures),
|
record,
|
||||||
record: promisify(record),
|
recordSyncStart,
|
||||||
recordSyncStart: promisify(recordSyncStart),
|
setForceDebug,
|
||||||
setForceDebug: promisify(setForceDebug),
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,5 @@
|
||||||
/* eslint-disable
|
|
||||||
no-return-assign,
|
|
||||||
no-undef,
|
|
||||||
no-unused-vars,
|
|
||||||
*/
|
|
||||||
// TODO: This file was created by bulk-decaffeinate.
|
|
||||||
// Fix any style issues and re-enable lint.
|
|
||||||
/*
|
|
||||||
* decaffeinate suggestions:
|
|
||||||
* DS102: Remove unnecessary code created because of implicit returns
|
|
||||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
|
||||||
*/
|
|
||||||
import sinon from 'sinon'
|
import sinon from 'sinon'
|
||||||
|
import { expect } from 'chai'
|
||||||
import { strict as esmock } from 'esmock'
|
import { strict as esmock } from 'esmock'
|
||||||
import tk from 'timekeeper'
|
import tk from 'timekeeper'
|
||||||
|
|
||||||
|
@ -20,11 +9,10 @@ describe('ErrorRecorder', function () {
|
||||||
beforeEach(async function () {
|
beforeEach(async function () {
|
||||||
this.now = new Date()
|
this.now = new Date()
|
||||||
tk.freeze(this.now)
|
tk.freeze(this.now)
|
||||||
this.callback = sinon.stub()
|
|
||||||
this.db = {
|
this.db = {
|
||||||
projectHistoryFailures: {
|
projectHistoryFailures: {
|
||||||
deleteOne: sinon.stub().yields(),
|
deleteOne: sinon.stub().resolves(),
|
||||||
updateOne: sinon.stub().yields(),
|
updateOne: sinon.stub().resolves(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
this.mongodb = { db: this.db }
|
this.mongodb = { db: this.db }
|
||||||
|
@ -35,27 +23,28 @@ describe('ErrorRecorder', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
this.project_id = 'project-id-123'
|
this.project_id = 'project-id-123'
|
||||||
return (this.queueSize = 445)
|
this.queueSize = 445
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(function () {
|
afterEach(function () {
|
||||||
return tk.reset()
|
tk.reset()
|
||||||
})
|
})
|
||||||
|
|
||||||
return describe('record', function () {
|
describe('record', function () {
|
||||||
describe('with an error', function () {
|
describe('with an error', function () {
|
||||||
beforeEach(function () {
|
beforeEach(async function () {
|
||||||
this.error = new Error('something bad')
|
this.error = new Error('something bad')
|
||||||
return this.ErrorRecorder.record(
|
await expect(
|
||||||
this.project_id,
|
this.ErrorRecorder.promises.record(
|
||||||
this.queueSize,
|
this.project_id,
|
||||||
this.error,
|
this.queueSize,
|
||||||
this.callback
|
this.error
|
||||||
)
|
)
|
||||||
|
).to.be.rejected
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should record the error to mongo', function () {
|
it('should record the error to mongo', function () {
|
||||||
return this.db.projectHistoryFailures.updateOne
|
this.db.projectHistoryFailures.updateOne
|
||||||
.calledWithMatch(
|
.calledWithMatch(
|
||||||
{
|
{
|
||||||
project_id: this.project_id,
|
project_id: this.project_id,
|
||||||
|
@ -91,32 +80,25 @@ describe('ErrorRecorder', function () {
|
||||||
)
|
)
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
return it('should call the callback', function () {
|
|
||||||
return this.callback
|
|
||||||
.calledWith(this.error, this.queueSize)
|
|
||||||
.should.equal(true)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return describe('without an error', function () {
|
describe('without an error', function () {
|
||||||
beforeEach(function () {
|
beforeEach(async function () {
|
||||||
return this.ErrorRecorder.record(
|
this.result = await this.ErrorRecorder.promises.record(
|
||||||
this.project_id,
|
this.project_id,
|
||||||
this.queueSize,
|
this.queueSize,
|
||||||
this.error,
|
this.error
|
||||||
this.callback
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should remove any error from mongo', function () {
|
it('should remove any error from mongo', function () {
|
||||||
return this.db.projectHistoryFailures.deleteOne
|
this.db.projectHistoryFailures.deleteOne
|
||||||
.calledWithMatch({ project_id: this.project_id })
|
.calledWithMatch({ project_id: this.project_id })
|
||||||
.should.equal(true)
|
.should.equal(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
return it('should call the callback', function () {
|
it('should return the queue size', function () {
|
||||||
return this.callback.calledWith(null, this.queueSize).should.equal(true)
|
expect(this.result).to.equal(this.queueSize)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue