budibase/packages/server/src/automations/tests/triggers/cron.spec.ts

151 lines
4.3 KiB
TypeScript
Raw Normal View History

import { createAutomationBuilder } from "../utilities/AutomationTestBuilder"
import TestConfiguration from "../../../tests/utilities/TestConfiguration"
2025-02-17 18:39:38 +01:00
import {
2025-02-18 11:48:16 +01:00
captureAutomationMessages,
captureAutomationRemovals,
2025-02-17 18:39:38 +01:00
captureAutomationResults,
2025-02-18 11:48:16 +01:00
triggerCron,
2025-02-17 18:39:38 +01:00
} from "../utilities"
import { automations } from "@budibase/pro"
2025-02-18 11:48:16 +01:00
import { AutomationData, AutomationStatus } from "@budibase/types"
import { MAX_AUTOMATION_RECURRING_ERRORS } from "../../../constants"
2025-02-18 15:01:32 +01:00
import { queue } from "@budibase/backend-core"
describe("cron trigger", () => {
const config = new TestConfiguration()
2025-02-05 18:19:11 +01:00
beforeAll(async () => {
await config.init()
2025-03-03 18:22:09 +01:00
await config.api.automation.deleteAll()
})
afterAll(() => {
config.end()
})
2025-02-17 18:39:38 +01:00
beforeEach(async () => {
const { automations } = await config.api.automation.fetch()
for (const automation of automations) {
await config.api.automation.delete(automation)
}
})
2025-02-05 10:22:37 +01:00
it("should queue a Bull cron job", async () => {
2025-02-10 17:15:53 +01:00
const { automation } = await createAutomationBuilder(config)
2025-02-06 16:47:10 +01:00
.onCron({ cron: "* * * * *" })
.serverLog({
text: "Hello, world!",
})
.save()
2025-02-18 11:48:16 +01:00
const messages = await captureAutomationMessages(automation, () =>
config.api.application.publish()
)
2025-02-17 18:39:38 +01:00
expect(messages).toHaveLength(1)
2025-02-05 10:22:37 +01:00
2025-02-17 18:39:38 +01:00
const repeat = messages[0].opts?.repeat
2025-02-05 10:22:37 +01:00
if (!repeat || !("cron" in repeat)) {
throw new Error("Expected cron repeat")
}
expect(repeat.cron).toEqual("* * * * *")
})
2025-02-05 16:24:54 +01:00
it("should fail if the cron expression is invalid", async () => {
await createAutomationBuilder(config)
2025-02-06 16:47:10 +01:00
.onCron({ cron: "* * * * * *" })
2025-02-05 16:24:54 +01:00
.serverLog({
text: "Hello, world!",
})
.save()
await config.api.application.publish(config.getAppId(), {
status: 500,
body: {
message:
'Deployment Failed: Invalid automation CRON "* * * * * *" - Expected 5 values, but got 6.',
},
})
})
2025-02-17 18:39:38 +01:00
2025-02-18 12:59:14 +01:00
it("should stop if the job fails more than N times", async () => {
2025-02-18 11:48:16 +01:00
const { automation } = await createAutomationBuilder(config)
2025-02-17 18:39:38 +01:00
.onCron({ cron: "* * * * *" })
.queryRows({
// @ts-expect-error intentionally sending invalid data
tableId: null,
})
.save()
2025-02-18 11:48:16 +01:00
const [message] = await captureAutomationMessages(automation, () =>
config.api.application.publish()
2025-02-17 18:39:38 +01:00
)
await config.withProdApp(async () => {
2025-02-18 15:01:32 +01:00
let results: queue.TestQueueMessage<AutomationData>[] = []
2025-02-18 11:48:16 +01:00
const removed = await captureAutomationRemovals(automation, async () => {
results = await captureAutomationResults(automation, async () => {
for (let i = 0; i < MAX_AUTOMATION_RECURRING_ERRORS; i++) {
triggerCron(message)
}
})
})
expect(removed).toHaveLength(1)
expect(removed[0].id).toEqual(message.id)
expect(results).toHaveLength(5)
const search = await automations.logs.logSearch({
automationId: automation._id,
2025-02-18 12:47:18 +01:00
status: AutomationStatus.STOPPED_ERROR,
2025-02-17 18:39:38 +01:00
})
2025-02-18 11:48:16 +01:00
expect(search.data).toHaveLength(1)
expect(search.data[0].status).toEqual(AutomationStatus.STOPPED_ERROR)
2025-02-17 18:39:38 +01:00
})
})
it("should fill in the timestamp if one is not provided", async () => {
const runner = await createAutomationBuilder(config)
.onCron({ cron: "* * * * *" })
.serverLog({
text: "Hello, world!",
})
.save()
await config.api.application.publish()
const results = await captureAutomationResults(
runner.automation,
async () => {
await runner.trigger({ timeout: 1000, fields: {} })
}
)
expect(results).toHaveLength(1)
expect(results[0].data.event.timestamp).toBeWithin(
Date.now() - 1000,
Date.now() + 1000
)
})
it("should use the given timestamp if one is given", async () => {
const timestamp = 1234
const runner = await createAutomationBuilder(config)
.onCron({ cron: "* * * * *" })
.serverLog({
text: "Hello, world!",
})
.save()
await config.api.application.publish()
const results = await captureAutomationResults(
runner.automation,
async () => {
await runner.trigger({ timeout: 1000, fields: {}, timestamp })
}
)
expect(results).toHaveLength(1)
expect(results[0].data.event.timestamp).toEqual(timestamp)
})
})