test: daily-evaluation auf 1991/1992, jobs-e2e räumt nur eigene Läufe
- Der Ablauf-Schritt der Vorschläge ist ein globales UPDATE. Auf Tagen in 2011 lief er über die offenen 2001-Vorschläge von autopilot und reminders. Vor 2001 nutzt keine andere Suite ein Datum. - jobs.e2e löschte im afterAll alle JobRuns seit Start und nahm rekey die eigenen Läufe weg; jetzt nur cleanup, daily-evaluation, task-templates. Refs #32 Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
2395576c88
commit
62ab080725
2 files changed
+111
-104
No files matched your search
@@ -24,11 +24,13 @@ const NOTHING_NEW = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The job evaluates the whole database. The e2e files share it and run in
|
* The job evaluates the whole database, and the expiry step expires EVERY open
|
||||||
* parallel, so the evaluation runs on days in 2011 and 2012: no other file has
|
* suggestion whose expiresAt lies before the given day. The e2e files share
|
||||||
* records there (autopilot and reminders own 2001; this file used to share it,
|
* the database and run in parallel, so this file runs on days in 1991 and
|
||||||
* so its "nothing new" counts picked up their colonies and its phenology step
|
* 1992: earlier than any date any other file uses (autopilot and reminders
|
||||||
* wrote season rows for their apiaries), and the events of this file stay its own. Called through
|
* use 2001, others 2002 and later). A later year would let the expiry step
|
||||||
|
* expire their open suggestions (and count them in our totals), and an
|
||||||
|
* "own" year in between would still see 2001's records. Called through
|
||||||
* TimeEventsStep.run(day) instead of runCli, which would also write JobRun
|
* TimeEventsStep.run(day) instead of runCli, which would also write JobRun
|
||||||
* rows that test/jobs.e2e-spec.ts counts.
|
* rows that test/jobs.e2e-spec.ts counts.
|
||||||
*/
|
*/
|
||||||
@@ -68,7 +70,7 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
phenologyStep = app.get(PhenologyStep);
|
phenologyStep = app.get(PhenologyStep);
|
||||||
expiryStep = app.get(SuggestionsExpiryStep);
|
expiryStep = app.get(SuggestionsExpiryStep);
|
||||||
// The real AutopilotStep, but on the colonies of this file only: other
|
// The real AutopilotStep, but on the colonies of this file only: other
|
||||||
// files share the database and must not be reconciled on a 2011 day.
|
// files share the database and must not be reconciled on a 1991 day.
|
||||||
autopilotStep = new AutopilotStep(
|
autopilotStep = new AutopilotStep(
|
||||||
{
|
{
|
||||||
colony: {
|
colony: {
|
||||||
@@ -109,18 +111,18 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
});
|
});
|
||||||
ids[`queen:${name}`] = created.id;
|
ids[`queen:${name}`] = created.id;
|
||||||
};
|
};
|
||||||
await queen('aged', { hatchYear: 2009, status: 'ACTIVE' });
|
await queen('aged', { hatchYear: 1989, status: 'ACTIVE' });
|
||||||
await queen('young', { hatchYear: 2010, status: 'ACTIVE' });
|
await queen('young', { hatchYear: 1990, status: 'ACTIVE' });
|
||||||
await queen('reserve', { hatchYear: 2009, status: 'RESERVE' });
|
await queen('reserve', { hatchYear: 1989, status: 'RESERVE' });
|
||||||
|
|
||||||
// Living, created 2011-04-20 and never measured: varroa due 2011-05-18.
|
// Living, created 1991-04-20 and never measured: varroa due 1991-05-18.
|
||||||
const living = await prisma.colony.create({
|
const living = await prisma.colony.create({
|
||||||
data: {
|
data: {
|
||||||
code: `DE-E2E-${suffix}-living`,
|
code: `DE-E2E-${suffix}-living`,
|
||||||
apiaryId: apiary.id,
|
apiaryId: apiary.id,
|
||||||
colonyType: 'PRODUCTION_COLONY',
|
colonyType: 'PRODUCTION_COLONY',
|
||||||
currentQueenId: ids['queen:aged'],
|
currentQueenId: ids['queen:aged'],
|
||||||
createdAt: d('2011-04-20'),
|
createdAt: d('1991-04-20'),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
ids.living = living.id;
|
ids.living = living.id;
|
||||||
@@ -130,15 +132,15 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
apiaryId: apiary.id,
|
apiaryId: apiary.id,
|
||||||
colonyType: 'PRODUCTION_COLONY',
|
colonyType: 'PRODUCTION_COLONY',
|
||||||
status: 'DECEASED',
|
status: 'DECEASED',
|
||||||
createdAt: d('2011-04-20'),
|
createdAt: d('1991-04-20'),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
ids.dead = dead.id;
|
ids.dead = dead.id;
|
||||||
// Inspected 2011-04-28, in the swarm season (every 7 days): the next
|
// Inspected 1991-04-28, in the swarm season (every 7 days): the next
|
||||||
// inspection is due 2011-05-05 and overdue on 2011-05-06.
|
// inspection is due 1991-05-05 and overdue on 1991-05-06.
|
||||||
for (const colonyId of [living.id, dead.id]) {
|
for (const colonyId of [living.id, dead.id]) {
|
||||||
await prisma.inspection.create({
|
await prisma.inspection.create({
|
||||||
data: { colonyId, userId: user.id, date: d('2011-04-28') },
|
data: { colonyId, userId: user.id, date: d('1991-04-28') },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,18 +161,18 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
});
|
});
|
||||||
ids[`treatment:${name}`] = created.id;
|
ids[`treatment:${name}`] = created.id;
|
||||||
};
|
};
|
||||||
// 2011-05-10 + 7 = 2011-05-17, in the window of 2011-05-20.
|
// 1991-05-10 + 7 = 1991-05-17, in the window of 1991-05-20.
|
||||||
await treatment('ending', {
|
await treatment('ending', {
|
||||||
date: d('2011-05-08'),
|
date: d('1991-05-08'),
|
||||||
endDate: d('2011-05-10'),
|
endDate: d('1991-05-10'),
|
||||||
withdrawalPeriodDays: 7,
|
withdrawalPeriodDays: 7,
|
||||||
});
|
});
|
||||||
// 2011-05-01 + 7 = 2011-05-08, before the window.
|
// 1991-05-01 + 7 = 1991-05-08, before the window.
|
||||||
await treatment('ended-earlier', {
|
await treatment('ended-earlier', {
|
||||||
date: d('2011-05-01'),
|
date: d('1991-05-01'),
|
||||||
withdrawalPeriodDays: 7,
|
withdrawalPeriodDays: 7,
|
||||||
});
|
});
|
||||||
await treatment('no-withdrawal', { date: d('2011-05-15') });
|
await treatment('no-withdrawal', { date: d('1991-05-15') });
|
||||||
|
|
||||||
const task = async (
|
const task = async (
|
||||||
name: string,
|
name: string,
|
||||||
@@ -181,8 +183,8 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
});
|
});
|
||||||
ids[`task:${name}`] = created.id;
|
ids[`task:${name}`] = created.id;
|
||||||
};
|
};
|
||||||
await task('open', { dueDate: d('2011-05-18'), status: 'OPEN' });
|
await task('open', { dueDate: d('1991-05-18'), status: 'OPEN' });
|
||||||
await task('done', { dueDate: d('2011-05-18'), status: 'DONE' });
|
await task('done', { dueDate: d('1991-05-18'), status: 'DONE' });
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
@@ -224,10 +226,10 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('running the job twice yields exactly one WithdrawalEnded per treatment and day', async () => {
|
it('running the job twice yields exactly one WithdrawalEnded per treatment and day', async () => {
|
||||||
const first = await step.run('2011-05-20');
|
const first = await step.run('1991-05-20');
|
||||||
const second = await step.run('2011-05-20');
|
const second = await step.run('1991-05-20');
|
||||||
// The next day the occurrence is still in the window - and still known.
|
// The next day the occurrence is still in the window - and still known.
|
||||||
const nextDay = await step.run('2011-05-21');
|
const nextDay = await step.run('1991-05-21');
|
||||||
|
|
||||||
expect(first.WithdrawalEnded).toBeGreaterThanOrEqual(1);
|
expect(first.WithdrawalEnded).toBeGreaterThanOrEqual(1);
|
||||||
expect(second).toEqual(NOTHING_NEW);
|
expect(second).toEqual(NOTHING_NEW);
|
||||||
@@ -236,8 +238,8 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
{
|
{
|
||||||
type: 'WithdrawalEnded',
|
type: 'WithdrawalEnded',
|
||||||
aggregateType: 'Treatment',
|
aggregateType: 'Treatment',
|
||||||
payload: { colonyId: ids.living, endedOn: '2011-05-17' },
|
payload: { colonyId: ids.living, endedOn: '1991-05-17' },
|
||||||
dedupeKey: `WithdrawalEnded:${ids['treatment:ending']}:2011-05-17`,
|
dedupeKey: `WithdrawalEnded:${ids['treatment:ending']}:1991-05-17`,
|
||||||
actorUserId: null,
|
actorUserId: null,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@@ -280,11 +282,11 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
await prisma.notification.deleteMany({
|
await prisma.notification.deleteMany({
|
||||||
where: { relatedType: 'ComplianceItem', relatedId: 'tsk-report:2011' },
|
where: { relatedType: 'ComplianceItem', relatedId: 'tsk-report:1991' },
|
||||||
});
|
});
|
||||||
await prisma.authorityNotice.deleteMany({ where: { year: 2011 } });
|
await prisma.authorityNotice.deleteMany({ where: { year: 1991 } });
|
||||||
await prisma.domainEvent.deleteMany({
|
await prisma.domainEvent.deleteMany({
|
||||||
where: { aggregateId: 'tsk:2011' },
|
where: { aggregateId: 'tsk:1991' },
|
||||||
});
|
});
|
||||||
await prisma.complianceSettings.update({
|
await prisma.complianceSettings.update({
|
||||||
where: { id: 'singleton' },
|
where: { id: 'singleton' },
|
||||||
@@ -293,25 +295,25 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function expectOneDraftAndNotices(): Promise<void> {
|
async function expectOneDraftAndNotices(): Promise<void> {
|
||||||
expect(await eventsOf('tsk:2011')).toEqual([
|
expect(await eventsOf('tsk:1991')).toEqual([
|
||||||
{
|
{
|
||||||
type: 'TskReferenceDayReached',
|
type: 'TskReferenceDayReached',
|
||||||
aggregateType: 'Compliance',
|
aggregateType: 'Compliance',
|
||||||
payload: { year: 2011, referenceDay: '2011-03-03' },
|
payload: { year: 1991, referenceDay: '1991-03-03' },
|
||||||
dedupeKey: 'TskReferenceDayReached:tsk:2011:2011-03-03',
|
dedupeKey: 'TskReferenceDayReached:tsk:1991:1991-03-03',
|
||||||
actorUserId: null,
|
actorUserId: null,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const drafts = await prisma.authorityNotice.findMany({
|
const drafts = await prisma.authorityNotice.findMany({
|
||||||
where: { kind: 'TSK_REPORT', year: 2011 },
|
where: { kind: 'TSK_REPORT', year: 1991 },
|
||||||
});
|
});
|
||||||
expect(drafts).toHaveLength(1);
|
expect(drafts).toHaveLength(1);
|
||||||
expect(drafts[0]).toMatchObject({
|
expect(drafts[0]).toMatchObject({
|
||||||
status: 'DRAFT',
|
status: 'DRAFT',
|
||||||
openKey: 'TSK_REPORT:2011',
|
openKey: 'TSK_REPORT:1991',
|
||||||
});
|
});
|
||||||
const notifications = await prisma.notification.findMany({
|
const notifications = await prisma.notification.findMany({
|
||||||
where: { relatedType: 'ComplianceItem', relatedId: 'tsk-report:2011' },
|
where: { relatedType: 'ComplianceItem', relatedId: 'tsk-report:1991' },
|
||||||
select: { userId: true, priority: true, category: true, message: true },
|
select: { userId: true, priority: true, category: true, message: true },
|
||||||
});
|
});
|
||||||
// One copy per recipient, written once - and every permitted user that
|
// One copy per recipient, written once - and every permitted user that
|
||||||
@@ -333,17 +335,17 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
category: 'COMPLIANCE',
|
category: 'COMPLIANCE',
|
||||||
});
|
});
|
||||||
expect(row.message).toMatch(
|
expect(row.message).toMatch(
|
||||||
/^TSK-Stichtag 03\.03\.2011: \d+ Völker gezählt\. Bitte prüfen und melden\.$/,
|
/^TSK-Stichtag 03\.03\.1991: \d+ Völker gezählt\. Bitte prüfen und melden\.$/,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
it('daily evaluation twice on the reference day: one event, one draft', async () => {
|
it('daily evaluation twice on the reference day: one event, one draft', async () => {
|
||||||
const first = await step.run('2011-03-03');
|
const first = await step.run('1991-03-03');
|
||||||
const second = await step.run('2011-03-03');
|
const second = await step.run('1991-03-03');
|
||||||
await drainDomainEvents(app, ['tsk:2011']);
|
await drainDomainEvents(app, ['tsk:1991']);
|
||||||
await step.run('2011-03-04');
|
await step.run('1991-03-04');
|
||||||
await drainDomainEvents(app, ['tsk:2011']);
|
await drainDomainEvents(app, ['tsk:1991']);
|
||||||
|
|
||||||
expect(first.TskReferenceDayReached).toBe(1);
|
expect(first.TskReferenceDayReached).toBe(1);
|
||||||
expect(second.TskReferenceDayReached).toBe(0);
|
expect(second.TskReferenceDayReached).toBe(0);
|
||||||
@@ -351,9 +353,9 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('catches up a missed reference day on the 5th exactly once', async () => {
|
it('catches up a missed reference day on the 5th exactly once', async () => {
|
||||||
const catchUp = await step.run('2011-03-05');
|
const catchUp = await step.run('1991-03-05');
|
||||||
const again = await step.run('2011-03-05');
|
const again = await step.run('1991-03-05');
|
||||||
await drainDomainEvents(app, ['tsk:2011']);
|
await drainDomainEvents(app, ['tsk:1991']);
|
||||||
|
|
||||||
expect(catchUp.TskReferenceDayReached).toBe(1);
|
expect(catchUp.TskReferenceDayReached).toBe(1);
|
||||||
expect(again.TskReferenceDayReached).toBe(0);
|
expect(again.TskReferenceDayReached).toBe(0);
|
||||||
@@ -362,14 +364,14 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('records due tasks and varroa checks only for open tasks and living colonies', async () => {
|
it('records due tasks and varroa checks only for open tasks and living colonies', async () => {
|
||||||
await step.run('2011-05-20');
|
await step.run('1991-05-20');
|
||||||
|
|
||||||
expect(await eventsOf(ids['task:open'])).toEqual([
|
expect(await eventsOf(ids['task:open'])).toEqual([
|
||||||
{
|
{
|
||||||
type: 'TaskDue',
|
type: 'TaskDue',
|
||||||
aggregateType: 'Task',
|
aggregateType: 'Task',
|
||||||
payload: { dueOn: '2011-05-18' },
|
payload: { dueOn: '1991-05-18' },
|
||||||
dedupeKey: `TaskDue:${ids['task:open']}:2011-05-18`,
|
dedupeKey: `TaskDue:${ids['task:open']}:1991-05-18`,
|
||||||
actorUserId: null,
|
actorUserId: null,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@@ -379,12 +381,12 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
type: 'VarroaMeasurementDue',
|
type: 'VarroaMeasurementDue',
|
||||||
aggregateType: 'Colony',
|
aggregateType: 'Colony',
|
||||||
payload: {
|
payload: {
|
||||||
dueOn: '2011-05-18',
|
dueOn: '1991-05-18',
|
||||||
lastMeasuredOn: null,
|
lastMeasuredOn: null,
|
||||||
kind: 'INTERVAL',
|
kind: 'INTERVAL',
|
||||||
anchor: 'none',
|
anchor: 'none',
|
||||||
},
|
},
|
||||||
dedupeKey: `VarroaMeasurementDue:${ids.living}:2011-05-18`,
|
dedupeKey: `VarroaMeasurementDue:${ids.living}:1991-05-18`,
|
||||||
actorUserId: null,
|
actorUserId: null,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@@ -392,9 +394,9 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('InspectionOverdue follows the segment interval', async () => {
|
it('InspectionOverdue follows the segment interval', async () => {
|
||||||
await step.run('2011-05-12');
|
await step.run('1991-05-12');
|
||||||
|
|
||||||
// SCHWARMZEIT since 2011-04-15: 2011-04-28 + 7 = 2011-05-05, not + 21.
|
// SCHWARMZEIT since 1991-04-15: 1991-04-28 + 7 = 1991-05-05, not + 21.
|
||||||
expect(
|
expect(
|
||||||
(await eventsOf(ids.living)).filter(
|
(await eventsOf(ids.living)).filter(
|
||||||
(event) => event.type === 'InspectionOverdue',
|
(event) => event.type === 'InspectionOverdue',
|
||||||
@@ -404,11 +406,11 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
type: 'InspectionOverdue',
|
type: 'InspectionOverdue',
|
||||||
aggregateType: 'Colony',
|
aggregateType: 'Colony',
|
||||||
payload: {
|
payload: {
|
||||||
dueOn: '2011-05-05',
|
dueOn: '1991-05-05',
|
||||||
lastInspectedOn: '2011-04-28',
|
lastInspectedOn: '1991-04-28',
|
||||||
firstOfYear: false,
|
firstOfYear: false,
|
||||||
},
|
},
|
||||||
dedupeKey: `InspectionOverdue:${ids.living}:2011-05-06`,
|
dedupeKey: `InspectionOverdue:${ids.living}:1991-05-06`,
|
||||||
actorUserId: null,
|
actorUserId: null,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@@ -416,50 +418,50 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('records no inspection in WINTERRUHE and the first one the day after FRUEHJAHR begins', async () => {
|
it('records no inspection in WINTERRUHE and the first one the day after FRUEHJAHR begins', async () => {
|
||||||
await step.run('2012-03-10');
|
await step.run('1992-03-10');
|
||||||
expect(
|
expect(
|
||||||
(await eventsOf(ids.living)).filter((event) =>
|
(await eventsOf(ids.living)).filter((event) =>
|
||||||
event.dedupeKey?.endsWith(':2012-03-21'),
|
event.dedupeKey?.endsWith(':1992-03-21'),
|
||||||
),
|
),
|
||||||
).toEqual([]);
|
).toEqual([]);
|
||||||
|
|
||||||
// FRUEHJAHR begins 2012-03-20; the colony was last inspected in 2011.
|
// FRUEHJAHR begins 1992-03-20; the colony was last inspected in 1991.
|
||||||
await step.run('2012-03-21');
|
await step.run('1992-03-21');
|
||||||
expect(
|
expect(
|
||||||
(await eventsOf(ids.living)).filter((event) =>
|
(await eventsOf(ids.living)).filter((event) =>
|
||||||
event.dedupeKey?.endsWith(':2012-03-21'),
|
event.dedupeKey?.endsWith(':1992-03-21'),
|
||||||
),
|
),
|
||||||
).toEqual([
|
).toEqual([
|
||||||
{
|
{
|
||||||
type: 'InspectionOverdue',
|
type: 'InspectionOverdue',
|
||||||
aggregateType: 'Colony',
|
aggregateType: 'Colony',
|
||||||
payload: {
|
payload: {
|
||||||
dueOn: '2012-03-20',
|
dueOn: '1992-03-20',
|
||||||
lastInspectedOn: '2011-04-28',
|
lastInspectedOn: '1991-04-28',
|
||||||
firstOfYear: true,
|
firstOfYear: true,
|
||||||
},
|
},
|
||||||
dedupeKey: `InspectionOverdue:${ids.living}:2012-03-21`,
|
dedupeKey: `InspectionOverdue:${ids.living}:1992-03-21`,
|
||||||
actorUserId: null,
|
actorUserId: null,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('reports the current queen of a living colony once she is aged, on any job day of the year', async () => {
|
it('reports the current queen of a living colony once she is aged, on any job day of the year', async () => {
|
||||||
await step.run('2011-09-09');
|
await step.run('1991-09-09');
|
||||||
await step.run('2011-09-10');
|
await step.run('1991-09-10');
|
||||||
|
|
||||||
// One per queen and year: the 2012 run of the test above added its own.
|
// One per queen and year: the 1992 run of the test above added its own.
|
||||||
const events = await eventsOf(ids['queen:aged']);
|
const events = await eventsOf(ids['queen:aged']);
|
||||||
expect(events.map((event) => event.dedupeKey)).toEqual([
|
expect(events.map((event) => event.dedupeKey)).toEqual([
|
||||||
`QueenAged:${ids['queen:aged']}:2011-01-01`,
|
`QueenAged:${ids['queen:aged']}:1991-01-01`,
|
||||||
`QueenAged:${ids['queen:aged']}:2012-01-01`,
|
`QueenAged:${ids['queen:aged']}:1992-01-01`,
|
||||||
]);
|
]);
|
||||||
expect(events.slice(0, 1)).toEqual([
|
expect(events.slice(0, 1)).toEqual([
|
||||||
{
|
{
|
||||||
type: 'QueenAged',
|
type: 'QueenAged',
|
||||||
aggregateType: 'Queen',
|
aggregateType: 'Queen',
|
||||||
payload: { hatchYear: 2009, colonyId: ids.living },
|
payload: { hatchYear: 1989, colonyId: ids.living },
|
||||||
dedupeKey: `QueenAged:${ids['queen:aged']}:2011-01-01`,
|
dedupeKey: `QueenAged:${ids['queen:aged']}:1991-01-01`,
|
||||||
actorUserId: null,
|
actorUserId: null,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@@ -468,7 +470,7 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('phenology step', () => {
|
describe('phenology step', () => {
|
||||||
const DAY = '2011-04-30';
|
const DAY = '1991-04-30';
|
||||||
let weatherApiaryId = '';
|
let weatherApiaryId = '';
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
@@ -483,8 +485,8 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
// 10 degrees every day from January 1st to April 29th: GTS 965.
|
// 10 degrees every day from January 1st to April 29th: GTS 965.
|
||||||
const days: Prisma.ApiaryWeatherDayCreateManyInput[] = [];
|
const days: Prisma.ApiaryWeatherDayCreateManyInput[] = [];
|
||||||
for (
|
for (
|
||||||
let t = d('2011-01-01').getTime();
|
let t = d('1991-01-01').getTime();
|
||||||
t <= d('2011-04-29').getTime();
|
t <= d('1991-04-29').getTime();
|
||||||
t += 86_400_000
|
t += 86_400_000
|
||||||
) {
|
) {
|
||||||
days.push({
|
days.push({
|
||||||
@@ -499,7 +501,7 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
data: {
|
data: {
|
||||||
apiaryId: apiary.id,
|
apiaryId: apiary.id,
|
||||||
phase: 'HOLUNDER',
|
phase: 'HOLUNDER',
|
||||||
date: d('2011-04-29'),
|
date: d('1991-04-29'),
|
||||||
userId: ids.user,
|
userId: ids.user,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -512,8 +514,8 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
await prisma.phenologyReport.deleteMany({
|
await prisma.phenologyReport.deleteMany({
|
||||||
where: { apiaryId: weatherApiaryId },
|
where: { apiaryId: weatherApiaryId },
|
||||||
});
|
});
|
||||||
// Rows of 2011 would feed the season of the other tests of this file.
|
// Rows of 1991 would feed the season of the other tests of this file.
|
||||||
await prisma.apiaryPhenology.deleteMany({ where: { year: 2011 } });
|
await prisma.apiaryPhenology.deleteMany({ where: { year: 1991 } });
|
||||||
await prisma.apiary.deleteMany({ where: { id: weatherApiaryId } });
|
await prisma.apiary.deleteMany({ where: { id: weatherApiaryId } });
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -532,7 +534,7 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
|
|
||||||
expect(Number(result.phenologyApiaries)).toBeGreaterThanOrEqual(2);
|
expect(Number(result.phenologyApiaries)).toBeGreaterThanOrEqual(2);
|
||||||
const rows = await prisma.apiaryPhenology.findMany({
|
const rows = await prisma.apiaryPhenology.findMany({
|
||||||
where: { apiaryId: { in: [ids.apiary, weatherApiaryId] }, year: 2011 },
|
where: { apiaryId: { in: [ids.apiary, weatherApiaryId] }, year: 1991 },
|
||||||
orderBy: { apiaryId: 'asc' },
|
orderBy: { apiaryId: 'asc' },
|
||||||
});
|
});
|
||||||
expect(rows).toHaveLength(2);
|
expect(rows).toHaveLength(2);
|
||||||
@@ -547,7 +549,7 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
// A report for HOLUNDER beats GTS and calendar.
|
// A report for HOLUNDER beats GTS and calendar.
|
||||||
expect(byApiary.get(weatherApiaryId)).toMatchObject({
|
expect(byApiary.get(weatherApiaryId)).toMatchObject({
|
||||||
gts: 965,
|
gts: 965,
|
||||||
gtsThroughDay: d('2011-04-29'),
|
gtsThroughDay: d('1991-04-29'),
|
||||||
estimatedPhase: 'APFEL',
|
estimatedPhase: 'APFEL',
|
||||||
reportedPhase: 'HOLUNDER',
|
reportedPhase: 'HOLUNDER',
|
||||||
effectivePhase: 'HOLUNDER',
|
effectivePhase: 'HOLUNDER',
|
||||||
@@ -581,25 +583,25 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('autopilot and suggestions-expiry steps', () => {
|
describe('autopilot and suggestions-expiry steps', () => {
|
||||||
/** Living colony, inspected 2011-05-03 and measured 2011-05-10. */
|
/** Living colony, inspected 1991-05-03 and measured 1991-05-10. */
|
||||||
async function lateColony(name: string): Promise<string> {
|
async function lateColony(name: string): Promise<string> {
|
||||||
const colony = await prisma.colony.create({
|
const colony = await prisma.colony.create({
|
||||||
data: {
|
data: {
|
||||||
code: `DE-E2E-${suffix}-ap-${name}`,
|
code: `DE-E2E-${suffix}-ap-${name}`,
|
||||||
apiaryId: ids.apiary,
|
apiaryId: ids.apiary,
|
||||||
colonyType: 'PRODUCTION_COLONY',
|
colonyType: 'PRODUCTION_COLONY',
|
||||||
createdAt: d('2011-04-20'),
|
createdAt: d('1991-04-20'),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
autopilotColonyIds.push(colony.id);
|
autopilotColonyIds.push(colony.id);
|
||||||
await prisma.inspection.create({
|
await prisma.inspection.create({
|
||||||
data: { colonyId: colony.id, userId: ids.user, date: d('2011-05-03') },
|
data: { colonyId: colony.id, userId: ids.user, date: d('1991-05-03') },
|
||||||
});
|
});
|
||||||
await prisma.varroaMeasurement.create({
|
await prisma.varroaMeasurement.create({
|
||||||
data: {
|
data: {
|
||||||
colonyId: colony.id,
|
colonyId: colony.id,
|
||||||
userId: ids.user,
|
userId: ids.user,
|
||||||
date: d('2011-05-10'),
|
date: d('1991-05-10'),
|
||||||
method: 'NATURAL_MITE_FALL',
|
method: 'NATURAL_MITE_FALL',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -615,10 +617,10 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
it('running autopilot and expiry twice yields the same suggestion counts', async () => {
|
it('running autopilot and expiry twice yields the same suggestion counts', async () => {
|
||||||
const colonyId = await lateColony('twice');
|
const colonyId = await lateColony('twice');
|
||||||
|
|
||||||
const first = await autopilotStep.run('2011-05-12');
|
const first = await autopilotStep.run('1991-05-12');
|
||||||
const firstExpiry = await expiryStep.run('2011-05-12');
|
const firstExpiry = await expiryStep.run('1991-05-12');
|
||||||
const second = await autopilotStep.run('2011-05-12');
|
const second = await autopilotStep.run('1991-05-12');
|
||||||
const secondExpiry = await expiryStep.run('2011-05-12');
|
const secondExpiry = await expiryStep.run('1991-05-12');
|
||||||
|
|
||||||
expect(first).toMatchObject({
|
expect(first).toMatchObject({
|
||||||
autopilotColonies: 1,
|
autopilotColonies: 1,
|
||||||
@@ -637,13 +639,13 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
|
|
||||||
it('an OPEN suggestion past expiresAt becomes EXPIRED', async () => {
|
it('an OPEN suggestion past expiresAt becomes EXPIRED', async () => {
|
||||||
const colonyId = await lateColony('expires');
|
const colonyId = await lateColony('expires');
|
||||||
await autopilotStep.run('2011-05-12');
|
await autopilotStep.run('1991-05-12');
|
||||||
|
|
||||||
// expiresAt = 2011-06-11
|
// expiresAt = 1991-06-11
|
||||||
expect(await expiryStep.run('2011-06-11')).toEqual({
|
expect(await expiryStep.run('1991-06-11')).toEqual({
|
||||||
suggestionsExpired: 0,
|
suggestionsExpired: 0,
|
||||||
});
|
});
|
||||||
expect(await expiryStep.run('2011-06-12')).toEqual({
|
expect(await expiryStep.run('1991-06-12')).toEqual({
|
||||||
suggestionsExpired: expect.any(Number) as number,
|
suggestionsExpired: expect.any(Number) as number,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -653,10 +655,10 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
|
|
||||||
it('an expired INSPECT suggestion of the same anchor is proposed again on the next sync (dedupeKey was released)', async () => {
|
it('an expired INSPECT suggestion of the same anchor is proposed again on the next sync (dedupeKey was released)', async () => {
|
||||||
const colonyId = await lateColony('again');
|
const colonyId = await lateColony('again');
|
||||||
await autopilotStep.run('2011-05-12');
|
await autopilotStep.run('1991-05-12');
|
||||||
await expiryStep.run('2011-06-12');
|
await expiryStep.run('1991-06-12');
|
||||||
|
|
||||||
const result = await autopilotStep.run('2011-06-12');
|
const result = await autopilotStep.run('1991-06-12');
|
||||||
|
|
||||||
expect(result.suggestionsOpened).toBeGreaterThanOrEqual(1);
|
expect(result.suggestionsOpened).toBeGreaterThanOrEqual(1);
|
||||||
expect((await inspectSuggestions(colonyId)).map((s) => s.status)).toEqual(
|
expect((await inspectSuggestions(colonyId)).map((s) => s.status)).toEqual(
|
||||||
@@ -668,13 +670,13 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
const colonyId = await lateColony('overdue20');
|
const colonyId = await lateColony('overdue20');
|
||||||
await prisma.inspection.updateMany({
|
await prisma.inspection.updateMany({
|
||||||
where: { colonyId },
|
where: { colonyId },
|
||||||
data: { date: d('2011-04-10') },
|
data: { date: d('1991-04-10') },
|
||||||
});
|
});
|
||||||
|
|
||||||
await step.run('2011-05-12');
|
await step.run('1991-05-12');
|
||||||
await autopilotStep.run('2011-05-12');
|
await autopilotStep.run('1991-05-12');
|
||||||
|
|
||||||
// Due 2011-04-17: the event of 04-18 is outside the 7-day catch-up.
|
// Due 1991-04-17: the event of 04-18 is outside the 7-day catch-up.
|
||||||
expect(
|
expect(
|
||||||
await prisma.domainEvent.count({
|
await prisma.domainEvent.count({
|
||||||
where: { aggregateId: colonyId, type: 'InspectionOverdue' },
|
where: { aggregateId: colonyId, type: 'InspectionOverdue' },
|
||||||
@@ -682,19 +684,19 @@ describe('daily-evaluation (e2e)', () => {
|
|||||||
).toBe(0);
|
).toBe(0);
|
||||||
const [suggestion] = await inspectSuggestions(colonyId);
|
const [suggestion] = await inspectSuggestions(colonyId);
|
||||||
expect(suggestion).toMatchObject({ status: 'OPEN', priority: 'HIGH' });
|
expect(suggestion).toMatchObject({ status: 'OPEN', priority: 'HIGH' });
|
||||||
expect(suggestion.dueDate?.toISOString().slice(0, 10)).toBe('2011-04-17');
|
expect(suggestion.dueDate?.toISOString().slice(0, 10)).toBe('1991-04-17');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('a RESOLVED autopilot suggestion whose condition returns is proposed again', async () => {
|
it('a RESOLVED autopilot suggestion whose condition returns is proposed again', async () => {
|
||||||
const colonyId = await lateColony('returns');
|
const colonyId = await lateColony('returns');
|
||||||
await autopilotStep.run('2011-05-12');
|
await autopilotStep.run('1991-05-12');
|
||||||
const fresh = await prisma.inspection.create({
|
const fresh = await prisma.inspection.create({
|
||||||
data: { colonyId, userId: ids.user, date: d('2011-05-12') },
|
data: { colonyId, userId: ids.user, date: d('1991-05-12') },
|
||||||
});
|
});
|
||||||
const resolved = await autopilotStep.run('2011-05-12');
|
const resolved = await autopilotStep.run('1991-05-12');
|
||||||
await prisma.inspection.delete({ where: { id: fresh.id } });
|
await prisma.inspection.delete({ where: { id: fresh.id } });
|
||||||
|
|
||||||
const returned = await autopilotStep.run('2011-05-12');
|
const returned = await autopilotStep.run('1991-05-12');
|
||||||
|
|
||||||
expect(resolved.suggestionsResolved).toBeGreaterThanOrEqual(1);
|
expect(resolved.suggestionsResolved).toBeGreaterThanOrEqual(1);
|
||||||
expect(returned.suggestionsOpened).toBeGreaterThanOrEqual(1);
|
expect(returned.suggestionsOpened).toBeGreaterThanOrEqual(1);
|
||||||
|
|||||||
@@ -39,8 +39,13 @@ describe('Jobs (e2e)', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
|
// Only the jobs this file runs: other files (rekey, app-backup, voice)
|
||||||
|
// record their own runs in the same window and read them back.
|
||||||
const runs = await prisma.jobRun.findMany({
|
const runs = await prisma.jobRun.findMany({
|
||||||
where: { startedAt: { gte: testStart } },
|
where: {
|
||||||
|
job: { in: ['cleanup', 'daily-evaluation', 'task-templates'] },
|
||||||
|
startedAt: { gte: testStart },
|
||||||
|
},
|
||||||
select: { id: true },
|
select: { id: true },
|
||||||
});
|
});
|
||||||
const runIds = [...jobRunIds, ...runs.map((run) => run.id)];
|
const runIds = [...jobRunIds, ...runs.map((run) => run.id)];
|
||||||
|
|||||||
Reference in new issue
Block a user