From 966a1dd6d98d3270d9e776684e96df901c4045b7 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 14 Apr 2024 21:48:41 +0100 Subject: [PATCH 1/8] Fix and update time-limited job https://eaflood.atlassian.net/browse/WATER-3486 In [Remove licences with charge elements with approaching time limits from billing](https://github.com/DEFRA/water-abstraction-system/pull/443) we added a background job to do just that. Then in [Refactor to use new view based WATER models](https://github.com/DEFRA/water-abstraction-system/pull/569) we updated how we interact with the DB. We updated the service which fetches the data for the job. But we didn't clock that this results in the job erroring because we are no longer passing in `licenceId`. Without it we error trying to create the `workflow` record in the DB because of a constraint on the field. We spotted this when working on [New job to add new & updated licences to workflow](https://github.com/DEFRA/water-abstraction-system/pull/903) so this change is mainly about fixing the bug. But we also realised one of the reasons we'd failed to spot the issue was a lack of logging. So, we also updated the job to use our pattern of logging how long the process took. We also take an idea from the new job and set a flag on the `workflow` record so we can spot _why_ it was created. From cbd37bccd0789b9854ea74a0a4d784a9070758d8 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 14 Apr 2024 21:59:37 +0100 Subject: [PATCH 2/8] Add time logging and update messages This brings the job in line with `/export` and `/licence-updates` and means we should see something in the logs when the job has run. --- .../time-limited/process-time-limited-licences.service.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/services/jobs/time-limited/process-time-limited-licences.service.js b/app/services/jobs/time-limited/process-time-limited-licences.service.js index 1000a32b25..99d6cebc4b 100644 --- a/app/services/jobs/time-limited/process-time-limited-licences.service.js +++ b/app/services/jobs/time-limited/process-time-limited-licences.service.js @@ -6,7 +6,7 @@ */ const FetchTimeLimitedLicencesService = require('./fetch-time-limited-licences.service.js') -const { timestampForPostgres } = require('../../../lib/general.lib.js') +const { calculateAndLogTimeTaken, currentTimeInNanoseconds, timestampForPostgres } = require('../../../lib/general.lib.js') const Workflow = require('../../../models/workflow.model.js') /** @@ -14,13 +14,17 @@ const Workflow = require('../../../models/workflow.model.js') */ async function go () { try { + const startTime = currentTimeInNanoseconds() + const licencesForWorkflow = await FetchTimeLimitedLicencesService.go() if (licencesForWorkflow.length) { await _addLicenceToWorkflow(licencesForWorkflow) } + + calculateAndLogTimeTaken(startTime, 'Time limited job complete', { count: licencesForWorkflow.length }) } catch (error) { - global.GlobalNotifier.omfg('ProcessTimeLimitedLicencesService failed to run', null, error) + global.GlobalNotifier.omfg('Time limited job failed', null, error) } } From ac66ef9c9c0977576a79c86763f3ce575b2a4277 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 14 Apr 2024 22:08:49 +0100 Subject: [PATCH 3/8] Housekeeping - Correct incorrect test title --- .../licence-updates/process-licence-updates.service.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/services/jobs/licence-updates/process-licence-updates.service.test.js b/test/services/jobs/licence-updates/process-licence-updates.service.test.js index b213c18806..76baa25513 100644 --- a/test/services/jobs/licence-updates/process-licence-updates.service.test.js +++ b/test/services/jobs/licence-updates/process-licence-updates.service.test.js @@ -18,7 +18,7 @@ const FetchLicenceUpdatesService = require('../../../../app/services/jobs/licenc // Thing under test const ProcessLicenceUpdatesService = require('../../../../app/services/jobs/licence-updates/process-licence-updates.js') -describe('Process Time Limited Licences service', () => { +describe('Process Licence Updates service', () => { let fetchResults let notifierStub From 98c9d3f98256e800da3ea9ab5b06d2d627f35fc4 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 14 Apr 2024 22:12:34 +0100 Subject: [PATCH 4/8] Housekeeping - remove commented out code --- .../determine-billing-periods.service.test.js | 128 ------------------ 1 file changed, 128 deletions(-) diff --git a/test/services/bill-runs/determine-billing-periods.service.test.js b/test/services/bill-runs/determine-billing-periods.service.test.js index 4324d6e337..89bd06e1f2 100644 --- a/test/services/bill-runs/determine-billing-periods.service.test.js +++ b/test/services/bill-runs/determine-billing-periods.service.test.js @@ -285,132 +285,4 @@ describe('Determine Billing Periods service', () => { }) }) }) - - // describe('and the date is in 2022 and falls within the 2022 financial year', () => { - // beforeEach(() => { - // - // expectedResult = { - // startDate: new Date('2022-04-01'), - // endDate: new Date('2023-03-31') - // } - - // clock = Sinon.useFakeTimers(testDate) - // }) - - // it('returns the expected date range', () => { - // const result = DetermineBillingPeriodsService.go() - - // expect(result).to.have.length(1) - // expect(result[0]).to.equal(expectedResult) - // }) - // }) - - // describe('and the date is in 2023 and falls within the 2022 financial year', () => { - // beforeEach(() => { - // testDate = new Date('2023-03-01') - // expectedResult = { - // startDate: new Date('2022-04-01'), - // endDate: new Date('2023-03-31') - // } - - // clock = Sinon.useFakeTimers(testDate) - // }) - - // it('returns the expected date range', () => { - // const result = DetermineBillingPeriodsService.go() - - // expect(result).to.have.length(1) - // expect(result[0]).to.equal(expectedResult) - // }) - // }) - - // describe('and the date is in 2023 and falls within the 2023 financial year', () => { - // beforeEach(() => { - // testDate = new Date('2023-10-10') - // expectedResult = [ - // { - // startDate: new Date('2023-04-01'), - // endDate: new Date('2024-03-31') - // }, - // { - // startDate: new Date('2022-04-01'), - // endDate: new Date('2023-03-31') - // } - // ] - - // clock = Sinon.useFakeTimers(testDate) - // }) - - // it('returns the expected date range', () => { - // const result = DetermineBillingPeriodsService.go() - - // expect(result).to.have.length(2) - // expect(result).to.equal(expectedResult) - // }) - // }) - - // describe('and the date is in 2030 and falls within the 2030 financial year', () => { - // beforeEach(() => { - // testDate = new Date('2030-10-10') - // expectedResult = [ - // { - // startDate: new Date('2030-04-01'), - // endDate: new Date('2031-03-31') - // }, - // { - // startDate: new Date('2029-04-01'), - // endDate: new Date('2030-03-31') - // }, - // { - // startDate: new Date('2028-04-01'), - // endDate: new Date('2029-03-31') - // }, - // { - // startDate: new Date('2027-04-01'), - // endDate: new Date('2028-03-31') - // }, - // { - // startDate: new Date('2026-04-01'), - // endDate: new Date('2027-03-31') - // }, - // { - // startDate: new Date('2025-04-01'), - // endDate: new Date('2026-03-31') - // } - // ] - - // clock = Sinon.useFakeTimers(testDate) - // }) - - // it('returns the expected date range', () => { - // const result = DetermineBillingPeriodsService.go() - - // expect(result).to.have.length(6) - // expect(result).to.equal(expectedResult) - // }) - // }) - // }) - - // describe('when a financial year is provided', () => { - // const financialYearEnding = 2025 - - // beforeEach(() => { - // testDate = new Date('2024-10-10') - // expectedResult = [ - // { - // startDate: new Date('2024-04-01'), - // endDate: new Date('2025-03-31') - // } - // ] - - // clock = Sinon.useFakeTimers(testDate) - // }) - - // it('only returns the billing period for that financial year', () => { - // const result = DetermineBillingPeriodsService.go(financialYearEnding) - - // expect(result).to.have.length(1) - // expect(result).to.equal(expectedResult) - // }) - // }) }) From b2b7ed149ca1e91301c5b28a48b73566a7bcde5b Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 14 Apr 2024 22:23:26 +0100 Subject: [PATCH 5/8] Housekeeping - Use set test data in assertion --- .../process-licence-updates.service.test.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/services/jobs/licence-updates/process-licence-updates.service.test.js b/test/services/jobs/licence-updates/process-licence-updates.service.test.js index 76baa25513..0947aa55db 100644 --- a/test/services/jobs/licence-updates/process-licence-updates.service.test.js +++ b/test/services/jobs/licence-updates/process-licence-updates.service.test.js @@ -61,15 +61,15 @@ describe('Process Licence Updates service', () => { expect(results).to.have.length(2) - expect(results[0].licenceVersionId).to.equal(fetchResults[0].id) - expect(results[0].licenceId).to.equal(fetchResults[0].licenceId) + expect(results[0].licenceVersionId).to.equal('ece3a745-d7b8-451e-8434-9977fbaa3bc1') + expect(results[0].licenceId).to.equal('a3f0bdeb-edcb-427d-9f79-c345d19d8aa1') expect(results[0].status).to.equal('to_setup') - expect(results[0].data).to.equal({ chargeVersion: null, chargeVersionExists: fetchResults[0].chargeVersionExists }) + expect(results[0].data).to.equal({ chargeVersion: null, chargeVersionExists: false }) - expect(results[1].licenceVersionId).to.equal(fetchResults[1].id) - expect(results[1].licenceId).to.equal(fetchResults[1].licenceId) + expect(results[1].licenceVersionId).to.equal('cbd2195f-17c4-407d-b7ed-c3cd729c3dca') + expect(results[1].licenceId).to.equal('fa25c580-710e-48f0-8932-b2d18e391994') expect(results[1].status).to.equal('to_setup') - expect(results[1].data).to.equal({ chargeVersion: null, chargeVersionExists: fetchResults[1].chargeVersionExists }) + expect(results[1].data).to.equal({ chargeVersion: null, chargeVersionExists: true }) }) it('logs the time taken in milliseconds and seconds', async () => { From 622b796dd7796e304fe4164d8083625c5e23a473 Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 14 Apr 2024 22:33:14 +0100 Subject: [PATCH 6/8] Update fetch service to return charge version ID Taking a lesson from the `licence-updates` job we want to apply something to the workflow `data` property that will indicate why it was added. We could have just gone with `timeLimited: true` and that would have told us why it was added. But if we include the charge version ID instead it gives us something we can build on, for example, directly linking the manage workflow screen to the charge version with the time limited element. --- .../fetch-time-limited-licences.service.js | 9 +++++---- .../fetch-time-limited-licences.service.test.js | 10 +++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/app/services/jobs/time-limited/fetch-time-limited-licences.service.js b/app/services/jobs/time-limited/fetch-time-limited-licences.service.js index 6c6cae8159..d4610b0603 100644 --- a/app/services/jobs/time-limited/fetch-time-limited-licences.service.js +++ b/app/services/jobs/time-limited/fetch-time-limited-licences.service.js @@ -1,14 +1,14 @@ 'use strict' /** - * Fetches licences that have a related `purpose` that is due to expire in less than 50 days + * Fetches licences that have a related charge element that is due to expire in less than 50 days * @module FetchTimeLimitedLicencesService */ const { db } = require('../../../../db/db.js') /** - * Fetch licences that have a related `purpose` that is due to expire in less than 50 days + * Fetches licences that have a related charge element that is due to expire in less than 50 days * * To be selected the licence must * @@ -20,13 +20,14 @@ const { db } = require('../../../../db/db.js') * - not be linked to a licence in the workflow * - have a related `purpose` that is due to expire in less than 50 days * - * @returns {Promise} The licence IDs with time-limited elements & their current version ID (needed else we break the workflow) + * @returns {Promise} The licence IDs with time-limited elements and their current licence version ID (needed + * else we break the workflow). Also the ID of the charge version that has the time limited charge element */ async function go () { // NOTE: We've resorted to Knex rather than Objection JS due to just how many JOINS we need to get from licence to // charge purposes! Our Objection JS skills failed us as we could not get the query to work using innerJoinRelated() return db - .distinct('l.id', 'lv.id AS licenceVersionId') + .distinct('l.id', 'lv.id AS licenceVersionId', 'cv.id AS chargeVersionId') .from('licences as l') .innerJoin('licenceVersions as lv', 'l.id', 'lv.licenceId') .innerJoin('chargeVersions as cv', 'l.id', 'cv.licenceId') diff --git a/test/services/jobs/time-limited/fetch-time-limited-licences.service.test.js b/test/services/jobs/time-limited/fetch-time-limited-licences.service.test.js index 926fc7af91..97098b5835 100644 --- a/test/services/jobs/time-limited/fetch-time-limited-licences.service.test.js +++ b/test/services/jobs/time-limited/fetch-time-limited-licences.service.test.js @@ -31,6 +31,7 @@ describe('Fetch Time Limited Licences service', () => { }) describe('when there are licences with elements due to expire in < 50 days that should be added to workflow', () => { + let chargeVersionId let licenceId let licenceVersionId @@ -42,7 +43,8 @@ describe('Fetch Time Limited Licences service', () => { licenceVersionId = licenceVersion.id // This creates a 'current' SROC charge version - const { id: chargeVersionId } = await ChargeVersionHelper.add({ licenceId }) + const chargeVersion = await ChargeVersionHelper.add({ licenceId }) + chargeVersionId = chargeVersion.id const { id: chargeReferenceId } = await ChargeReferenceHelper.add({ chargeVersionId }) @@ -50,12 +52,13 @@ describe('Fetch Time Limited Licences service', () => { await ChargeElementHelper.add({ chargeReferenceId, timeLimitedEndDate: _offSetCurrentDateByDays(49) }) }) - it('returns the licenceId and licenceVersionId for the SROC licence with an expiring element', async () => { + it('returns the licenceId, licenceVersionId and chargeVersionId for the SROC licence with an expiring element', async () => { const result = await FetchTimeLimitedLicencesService.go() expect(result).to.have.length(1) expect(result[0].id).to.equal(licenceId) expect(result[0].licenceVersionId).to.equal(licenceVersionId) + expect(result[0].chargeVersionId).to.equal(chargeVersionId) }) describe('including those linked to soft-deleted workflow records', () => { @@ -63,12 +66,13 @@ describe('Fetch Time Limited Licences service', () => { await WorkflowHelper.add({ licenceId, deletedAt: new Date('2022-04-01') }) }) - it('returns the licenceId and licenceVersionId for the SROC licence with an expiring element', async () => { + it('returns the licenceId, licenceVersionId and chargeVersionId for the SROC licence with an expiring element', async () => { const result = await FetchTimeLimitedLicencesService.go() expect(result).to.have.length(1) expect(result[0].id).to.equal(licenceId) expect(result[0].licenceVersionId).to.equal(licenceVersionId) + expect(result[0].chargeVersionId).to.equal(chargeVersionId) }) }) }) From e51ff937d93f55575c46a3b633155450138c170a Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 14 Apr 2024 22:45:58 +0100 Subject: [PATCH 7/8] Update process time limited service We bring it in line with what we have done in our licence updates job. For example, there is no need to check if the fetch service returned any results because we now process them in a loop (no results no looping). We process them in a loop because it drops the dependence on the fetch service returning results that directly map to workflow records (the thing we broke and why we're making these changes). Plus it gives us more flexibility, for example, adding the charge version ID with the time limited charge element to the result. --- .../process-time-limited-licences.service.js | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/app/services/jobs/time-limited/process-time-limited-licences.service.js b/app/services/jobs/time-limited/process-time-limited-licences.service.js index 99d6cebc4b..2df796367b 100644 --- a/app/services/jobs/time-limited/process-time-limited-licences.service.js +++ b/app/services/jobs/time-limited/process-time-limited-licences.service.js @@ -16,30 +16,31 @@ async function go () { try { const startTime = currentTimeInNanoseconds() - const licencesForWorkflow = await FetchTimeLimitedLicencesService.go() + const timeLimitedResults = await FetchTimeLimitedLicencesService.go() - if (licencesForWorkflow.length) { - await _addLicenceToWorkflow(licencesForWorkflow) - } + await _addWorkflowRecords(timeLimitedResults) - calculateAndLogTimeTaken(startTime, 'Time limited job complete', { count: licencesForWorkflow.length }) + calculateAndLogTimeTaken(startTime, 'Time limited job complete', { count: timeLimitedResults.length }) } catch (error) { global.GlobalNotifier.omfg('Time limited job failed', null, error) } } -async function _addLicenceToWorkflow (licencesForWorkflow) { +async function _addWorkflowRecords (timeLimitedResults) { const timestamp = timestampForPostgres() - // Attach additional data to the array that the chargeVersionWorkflow table requires to create a valid record - licencesForWorkflow.forEach((licenceForWorkflow) => { - licenceForWorkflow.status = 'to_setup' - licenceForWorkflow.data = { chargeVersion: null } - licenceForWorkflow.createdAt = timestamp - licenceForWorkflow.updatedAt = timestamp - }) - - await Workflow.query().insert(licencesForWorkflow) + for (const timeLimitedResult of timeLimitedResults) { + const { id: licenceId, chargeVersionId: timeLimitedChargeVersionId, licenceVersionId } = timeLimitedResult + + await Workflow.query().insert({ + data: { chargeVersion: null, timeLimitedChargeVersionId }, + licenceId, + licenceVersionId, + status: 'to_setup', + createdAt: timestamp, + updatedAt: timestamp + }) + } } module.exports = { From 4132d3dbd966f7bb419020b4254229a0c2872a5e Mon Sep 17 00:00:00 2001 From: Alan Cruikshanks Date: Sun, 14 Apr 2024 22:49:32 +0100 Subject: [PATCH 8/8] Update process time limited unit tests Whilst in there we also were able to correct some things that might have caused errors down the road; using `returns()` and `throws()` with a stubbed service that is async could cause problems. Instead `resolves()` and `rejects()` should be used. --- ...cess-time-limited-licences.service.test.js | 102 ++++++++++++------ 1 file changed, 72 insertions(+), 30 deletions(-) diff --git a/test/services/jobs/time-limited/process-time-limited-licences.service.test.js b/test/services/jobs/time-limited/process-time-limited-licences.service.test.js index 86b88f1889..ca76233e18 100644 --- a/test/services/jobs/time-limited/process-time-limited-licences.service.test.js +++ b/test/services/jobs/time-limited/process-time-limited-licences.service.test.js @@ -10,8 +10,7 @@ const { expect } = Code // Test helpers const DatabaseSupport = require('../../../support/database.js') -const { generateUUID } = require('../../../../app/lib/general.lib.js') -const Workflow = require('../../../../app/models/workflow.model.js') +const WorkflowModel = require('../../../../app/models/workflow.model.js') // Things we need to stub const FetchTimeLimitedLicencesService = require('../../../../app/services/jobs/time-limited/fetch-time-limited-licences.service.js') @@ -20,14 +19,16 @@ const FetchTimeLimitedLicencesService = require('../../../../app/services/jobs/t const ProcessTimeLimitedLicencesService = require('../../../../app/services/jobs/time-limited/process-time-limited-licences.service.js') describe('Process Time Limited Licences service', () => { + let fetchResults let notifierStub beforeEach(async () => { await DatabaseSupport.clean() + // The service depends on GlobalNotifier to have been set. This happens in app/plugins/global-notifier.plugin.js // when the app starts up and the plugin is registered. As we're not creating an instance of Hapi server in this // test we recreate the condition by setting it directly with our own stub - notifierStub = { omfg: Sinon.stub() } + notifierStub = { omg: Sinon.stub(), omfg: Sinon.stub() } global.GlobalNotifier = notifierStub }) @@ -35,53 +36,94 @@ describe('Process Time Limited Licences service', () => { Sinon.restore() }) - describe('when there are licences to add to the workflow', () => { - const fetchedLicences = [ - { - licenceId: generateUUID(), - licenceVersionId: generateUUID() - }, - { - licenceId: generateUUID(), - licenceVersionId: generateUUID() - } - ] - + describe('when there are licences with time limited charge elements', () => { beforeEach(() => { - Sinon.stub(FetchTimeLimitedLicencesService, 'go').returns(fetchedLicences) + fetchResults = [ + { + id: 'ece3a745-d7b8-451e-8434-9977fbaa3bc1', + licenceVersionId: 'a3f0bdeb-edcb-427d-9f79-c345d19d8aa1', + chargeVersionId: 'dbb98ce9-2cfd-4d74-94ac-c4e6e8f42442' + }, + { + id: 'cbd2195f-17c4-407d-b7ed-c3cd729c3dca', + licenceVersionId: 'fa25c580-710e-48f0-8932-b2d18e391994', + chargeVersionId: 'cc192da9-d0f4-489d-bf44-0de2544bc801' + } + ] + + Sinon.stub(FetchTimeLimitedLicencesService, 'go').resolves(fetchResults) }) it('adds the licences to the workflow table', async () => { await ProcessTimeLimitedLicencesService.go() - const result = await Workflow.query() - .whereIn('licenceId', [fetchedLicences[0].licenceId, fetchedLicences[1].licenceId]) + const results = await WorkflowModel.query().orderBy('createdAt', 'asc') + + expect(results).to.have.length(2) + + expect(results[0].licenceId).to.equal('ece3a745-d7b8-451e-8434-9977fbaa3bc1') + expect(results[0].licenceVersionId).to.equal('a3f0bdeb-edcb-427d-9f79-c345d19d8aa1') + expect(results[0].status).to.equal('to_setup') + expect(results[0].data).to.equal({ + chargeVersion: null, + timeLimitedChargeVersionId: 'dbb98ce9-2cfd-4d74-94ac-c4e6e8f42442' + }) + + expect(results[1].licenceId).to.equal('cbd2195f-17c4-407d-b7ed-c3cd729c3dca') + expect(results[1].licenceVersionId).to.equal('fa25c580-710e-48f0-8932-b2d18e391994') + expect(results[1].status).to.equal('to_setup') + expect(results[1].data).to.equal({ + chargeVersion: null, + timeLimitedChargeVersionId: 'cc192da9-d0f4-489d-bf44-0de2544bc801' + }) + }) - expect(result).to.have.length(2) - expect(result[0].status).to.equal('to_setup') - expect(result[0].data).to.equal({ chargeVersion: null }) + it('logs the time taken in milliseconds and seconds', async () => { + await ProcessTimeLimitedLicencesService.go() + + const logDataArg = notifierStub.omg.firstCall.args[1] + + expect( + notifierStub.omg.calledWith('Time limited job complete') + ).to.be.true() + expect(logDataArg.timeTakenMs).to.exist() + expect(logDataArg.timeTakenSs).to.exist() + expect(logDataArg.count).to.exist() }) }) - describe('when there are NO licences to add to the workflow', () => { - const fetchedLicences = [] - + describe('when there are no time limited licences', () => { beforeEach(() => { - Sinon.stub(FetchTimeLimitedLicencesService, 'go').resolves(fetchedLicences) + fetchResults = [] + + Sinon.stub(FetchTimeLimitedLicencesService, 'go').resolves(fetchResults) + }) + + it('adds nothing to workflow', async () => { + await ProcessTimeLimitedLicencesService.go() + + const results = await WorkflowModel.query().orderBy('createdAt', 'asc') + + expect(results).to.be.empty() }) - it('does not error', async () => { + it('logs the time taken in milliseconds and seconds', async () => { await ProcessTimeLimitedLicencesService.go() - const args = notifierStub.omfg.firstCall?.args + const logDataArg = notifierStub.omg.firstCall.args[1] - expect(args).to.be.undefined() + expect( + notifierStub.omg.calledWith('Time limited job complete') + ).to.be.true() + expect(logDataArg.timeTakenMs).to.exist() + expect(logDataArg.timeTakenSs).to.exist() + expect(logDataArg.count).to.exist() }) }) describe('when there is an error', () => { beforeEach(() => { - Sinon.stub(FetchTimeLimitedLicencesService, 'go').throws() + Sinon.stub(FetchTimeLimitedLicencesService, 'go').rejects() }) it('handles the error', async () => { @@ -89,7 +131,7 @@ describe('Process Time Limited Licences service', () => { const args = notifierStub.omfg.firstCall.args - expect(args[0]).to.equal('ProcessTimeLimitedLicencesService failed to run') + expect(args[0]).to.equal('Time limited job failed') expect(args[1]).to.be.null() expect(args[2]).to.be.an.error() })