automation events + tests
This commit is contained in:
parent
ec4e9df4c2
commit
266b34aaa0
5 changed files with 200 additions and 43 deletions
|
@ -125,9 +125,10 @@ exports.Events = {
|
|||
AUTOMATION_CREATED: "automation:created",
|
||||
AUTOMATION_DELETED: "automation:deleted",
|
||||
AUTOMATION_TESTED: "automation:tested",
|
||||
AUTOMATION_RUN: "automation:run",
|
||||
// AUTOMATION_RUN: "automation:run",
|
||||
AUTOMATION_STEP_CREATED: "automation:step:created",
|
||||
AUTOMATION_STEP_DELETED: "automation:step:deleted",
|
||||
AUTOMATION_TRIGGER_UPDATED: "automation:trigger:updated",
|
||||
|
||||
// LICENSING
|
||||
LICENSING_QUOTA_EXCEEDED: "licensing:quota:exceeded",
|
||||
|
|
|
@ -6,32 +6,33 @@ exports.created = () => {
|
|||
events.processEvent(Events.AUTOMATION_CREATED, properties)
|
||||
}
|
||||
|
||||
// TODO
|
||||
exports.deleted = () => {
|
||||
const properties = {}
|
||||
events.processEvent(Events.AUTOMATION_DELETED, properties)
|
||||
}
|
||||
|
||||
// TODO
|
||||
exports.tested = () => {
|
||||
const properties = {}
|
||||
events.processEvent(Events.AUTOMATION_TESTED, properties)
|
||||
}
|
||||
|
||||
// TODO
|
||||
exports.run = () => {
|
||||
const properties = {}
|
||||
events.processEvent(Events.AUTOMATION_RUN, properties)
|
||||
}
|
||||
// exports.run = () => {
|
||||
// const properties = {}
|
||||
// events.processEvent(Events.AUTOMATION_RUN, properties)
|
||||
// }
|
||||
|
||||
// TODO
|
||||
exports.stepCreated = () => {
|
||||
const properties = {}
|
||||
events.processEvent(Events.AUTOMATION_STEP_CREATED, properties)
|
||||
}
|
||||
|
||||
// TODO
|
||||
exports.stepDeleted = () => {
|
||||
const properties = {}
|
||||
events.processEvent(Events.AUTOMATION_STEP_DELETED, properties)
|
||||
}
|
||||
|
||||
exports.triggerUpdated = () => {
|
||||
const properties = {}
|
||||
events.processEvent(Events.AUTOMATION_TRIGGER_UPDATED, properties)
|
||||
}
|
||||
|
|
|
@ -26,6 +26,15 @@ jest.mock("../../../events", () => {
|
|||
SSOActivated: jest.fn(),
|
||||
SSODeactivated: jest.fn(),
|
||||
},
|
||||
automation: {
|
||||
created: jest.fn(),
|
||||
deleted: jest.fn(),
|
||||
tested: jest.fn(),
|
||||
// run: jest.fn(),
|
||||
stepCreated: jest.fn(),
|
||||
stepDeleted: jest.fn(),
|
||||
triggerUpdated: jest.fn(),
|
||||
},
|
||||
datasource: {
|
||||
created: jest.fn(),
|
||||
updated: jest.fn(),
|
||||
|
|
|
@ -10,6 +10,7 @@ const { deleteEntityMetadata } = require("../../utilities")
|
|||
const { MetadataTypes } = require("../../constants")
|
||||
const { setTestFlag, clearTestFlag } = require("../../utilities/redis")
|
||||
const { getAppDB } = require("@budibase/backend-core/context")
|
||||
const { events } = require("@budibase/backend-core")
|
||||
|
||||
const ACTION_DEFS = removeDeprecated(actions.ACTION_DEFINITIONS)
|
||||
const TRIGGER_DEFS = removeDeprecated(triggers.TRIGGER_DEFINITIONS)
|
||||
|
@ -70,6 +71,10 @@ exports.create = async function (ctx) {
|
|||
newAuto: automation,
|
||||
})
|
||||
const response = await db.put(automation)
|
||||
events.automation.created()
|
||||
for (let step of automation.definition.steps) {
|
||||
events.automation.stepCreated(step)
|
||||
}
|
||||
automation._rev = response.rev
|
||||
|
||||
ctx.status = 200
|
||||
|
@ -82,6 +87,29 @@ exports.create = async function (ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
const getNewSteps = (oldAutomation, automation) => {
|
||||
const oldStepIds = oldAutomation.definition.steps.map(s => s.id)
|
||||
return automation.definition.steps.filter(s => !oldStepIds.includes(s.id))
|
||||
}
|
||||
|
||||
const getDeletedSteps = (oldAutomation, automation) => {
|
||||
const stepIds = automation.definition.steps.map(s => s.id)
|
||||
return oldAutomation.definition.steps.filter(s => !stepIds.includes(s.id))
|
||||
}
|
||||
|
||||
const handleStepEvents = (oldAutomation, automation) => {
|
||||
// new steps
|
||||
const newSteps = getNewSteps(oldAutomation, automation)
|
||||
for (let step of newSteps) {
|
||||
events.automation.stepCreated(step)
|
||||
}
|
||||
|
||||
// old steps
|
||||
const deletedSteps = getDeletedSteps(oldAutomation, automation)
|
||||
for (let step of deletedSteps) {
|
||||
events.automation.stepDeleted(step)
|
||||
}
|
||||
}
|
||||
exports.update = async function (ctx) {
|
||||
const db = getAppDB()
|
||||
let automation = ctx.request.body
|
||||
|
@ -98,13 +126,14 @@ exports.update = async function (ctx) {
|
|||
const oldAutoTrigger =
|
||||
oldAutomation && oldAutomation.definition.trigger
|
||||
? oldAutomation.definition.trigger
|
||||
: {}
|
||||
: undefined
|
||||
const newAutoTrigger =
|
||||
automation && automation.definition.trigger
|
||||
? automation.definition.trigger
|
||||
: {}
|
||||
// trigger has been updated, remove the test inputs
|
||||
if (oldAutoTrigger.id !== newAutoTrigger.id) {
|
||||
if (oldAutoTrigger && oldAutoTrigger.id !== newAutoTrigger.id) {
|
||||
events.automation.triggerUpdated()
|
||||
await deleteEntityMetadata(
|
||||
ctx.appId,
|
||||
MetadataTypes.AUTOMATION_TEST_INPUT,
|
||||
|
@ -112,6 +141,8 @@ exports.update = async function (ctx) {
|
|||
)
|
||||
}
|
||||
|
||||
handleStepEvents(oldAutomation, automation)
|
||||
|
||||
ctx.status = 200
|
||||
ctx.body = {
|
||||
message: `Automation ${automation._id} updated successfully.`,
|
||||
|
@ -148,6 +179,7 @@ exports.destroy = async function (ctx) {
|
|||
// delete metadata first
|
||||
await cleanupAutomationMetadata(automationId)
|
||||
ctx.body = await db.remove(automationId, ctx.params.rev)
|
||||
events.automation.deleted()
|
||||
}
|
||||
|
||||
exports.getActionList = async function (ctx) {
|
||||
|
@ -215,4 +247,5 @@ exports.test = async function (ctx) {
|
|||
})
|
||||
await clearTestFlag(automation._id)
|
||||
ctx.body = response
|
||||
events.automation.tested()
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ const { mocks } = require("@budibase/backend-core/testUtils")
|
|||
mocks.date.mock()
|
||||
const MAX_RETRIES = 4
|
||||
const { TRIGGER_DEFINITIONS, ACTION_DEFINITIONS } = require("../../../automations")
|
||||
const { events } = require("@budibase/backend-core")
|
||||
|
||||
describe("/automations", () => {
|
||||
let request = setup.getRequest()
|
||||
|
@ -58,8 +59,9 @@ describe("/automations", () => {
|
|||
})
|
||||
|
||||
describe("create", () => {
|
||||
it("returns a success message when the automation is successfully created", async () => {
|
||||
it("creates an automation with no steps", async () => {
|
||||
const automation = newAutomation()
|
||||
automation.definition.steps = []
|
||||
|
||||
const res = await request
|
||||
.post(`/api/automations`)
|
||||
|
@ -71,6 +73,27 @@ describe("/automations", () => {
|
|||
expect(res.body.message).toEqual("Automation created successfully")
|
||||
expect(res.body.automation.name).toEqual("My Automation")
|
||||
expect(res.body.automation._id).not.toEqual(null)
|
||||
expect(events.automation.created).toBeCalledTimes(1)
|
||||
expect(events.automation.stepCreated).not.toBeCalled()
|
||||
})
|
||||
|
||||
it("creates an automation with steps", async () => {
|
||||
const automation = newAutomation()
|
||||
automation.definition.steps.push(automationStep())
|
||||
jest.clearAllMocks()
|
||||
|
||||
const res = await request
|
||||
.post(`/api/automations`)
|
||||
.set(config.defaultHeaders())
|
||||
.send(automation)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
|
||||
expect(res.body.message).toEqual("Automation created successfully")
|
||||
expect(res.body.automation.name).toEqual("My Automation")
|
||||
expect(res.body.automation._id).not.toEqual(null)
|
||||
expect(events.automation.created).toBeCalledTimes(1)
|
||||
expect(events.automation.stepCreated).toBeCalledTimes(2)
|
||||
})
|
||||
|
||||
it("should apply authorization to endpoint", async () => {
|
||||
|
@ -97,8 +120,8 @@ describe("/automations", () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe("trigger", () => {
|
||||
it("trigger the automation successfully", async () => {
|
||||
describe("test", () => {
|
||||
it("tests the automation successfully", async () => {
|
||||
let table = await config.createTable()
|
||||
let automation = newAutomation()
|
||||
automation.definition.trigger.inputs.tableId = table._id
|
||||
|
@ -113,6 +136,7 @@ describe("/automations", () => {
|
|||
automation = await config.createAutomation(automation)
|
||||
await setup.delay(500)
|
||||
const res = await testAutomation(config, automation)
|
||||
expect(events.automation.tested).toBeCalledTimes(1)
|
||||
// this looks a bit mad but we don't actually have a way to wait for a response from the automation to
|
||||
// know that it has finished all of its actions - this is currently the best way
|
||||
// also when this runs in CI it is very temper-mental so for now trying to make run stable by repeating until it works
|
||||
|
@ -134,53 +158,141 @@ describe("/automations", () => {
|
|||
})
|
||||
|
||||
describe("update", () => {
|
||||
it("updates a automations data", async () => {
|
||||
let automation = newAutomation()
|
||||
await config.createAutomation(automation)
|
||||
automation.name = "Updated Name"
|
||||
|
||||
const res = await request
|
||||
const update = async (automation) => {
|
||||
return request
|
||||
.put(`/api/automations`)
|
||||
.set(config.defaultHeaders())
|
||||
.send(automation)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
}
|
||||
|
||||
expect(res.body.message).toEqual(`Automation ${automation._id} updated successfully.`)
|
||||
expect(res.body.automation.name).toEqual("Updated Name")
|
||||
})
|
||||
|
||||
it("should be able to update an automation trigger", async () => {
|
||||
// create webhook automation
|
||||
const webhookTrigger = automationTrigger(TRIGGER_DEFINITIONS.WEBHOOK)
|
||||
let automation = newAutomation({ trigger: webhookTrigger })
|
||||
|
||||
let res = await request
|
||||
const updateWithPost = async (automation) => {
|
||||
return request
|
||||
.post(`/api/automations`)
|
||||
.set(config.defaultHeaders())
|
||||
.send(automation)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
}
|
||||
|
||||
automation = res.body.automation
|
||||
expect(automation._id).toBeDefined()
|
||||
expect(automation._rev).toBeDefined()
|
||||
it("updates a automations name", async () => {
|
||||
let automation = newAutomation()
|
||||
await config.createAutomation(automation)
|
||||
automation.name = "Updated Name"
|
||||
jest.clearAllMocks()
|
||||
|
||||
// change the trigger
|
||||
automation.trigger = automationTrigger(TRIGGER_DEFINITIONS.ROW_SAVED)
|
||||
|
||||
// check the post request honours updates with same id
|
||||
res = await request
|
||||
.post(`/api/automations`)
|
||||
.set(config.defaultHeaders())
|
||||
.send(automation)
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
const res = await update(automation)
|
||||
|
||||
const automationRes = res.body.automation
|
||||
const message = res.body.message
|
||||
|
||||
// doc attributes
|
||||
expect(automationRes._id).toEqual(automation._id)
|
||||
expect(automationRes._rev).toBeDefined()
|
||||
expect(automationRes._rev).not.toEqual(automation._rev)
|
||||
// content updates
|
||||
expect(automationRes.name).toEqual("Updated Name")
|
||||
expect(message).toEqual(`Automation ${automation._id} updated successfully.`)
|
||||
// events
|
||||
expect(events.automation.created).not.toBeCalled()
|
||||
expect(events.automation.stepCreated).not.toBeCalled()
|
||||
expect(events.automation.stepDeleted).not.toBeCalled()
|
||||
expect(events.automation.triggerUpdated).not.toBeCalled()
|
||||
})
|
||||
|
||||
|
||||
it("updates a automations name using POST request", async () => {
|
||||
let automation = newAutomation()
|
||||
await config.createAutomation(automation)
|
||||
automation.name = "Updated Name"
|
||||
jest.clearAllMocks()
|
||||
|
||||
// the POST request will defer to the update
|
||||
// when an id has been supplied.
|
||||
const res = await updateWithPost(automation)
|
||||
|
||||
const automationRes = res.body.automation
|
||||
const message = res.body.message
|
||||
// doc attributes
|
||||
expect(automationRes._id).toEqual(automation._id)
|
||||
expect(automationRes._rev).toBeDefined()
|
||||
expect(automationRes._rev).not.toEqual(automation._rev)
|
||||
// content updates
|
||||
expect(automationRes.name).toEqual("Updated Name")
|
||||
expect(message).toEqual(`Automation ${automation._id} updated successfully.`)
|
||||
// events
|
||||
expect(events.automation.created).not.toBeCalled()
|
||||
expect(events.automation.stepCreated).not.toBeCalled()
|
||||
expect(events.automation.stepDeleted).not.toBeCalled()
|
||||
expect(events.automation.triggerUpdated).not.toBeCalled()
|
||||
})
|
||||
|
||||
it("updates an automation trigger", async () => {
|
||||
let automation = newAutomation()
|
||||
automation = await config.createAutomation(automation)
|
||||
automation.definition.trigger = automationTrigger(TRIGGER_DEFINITIONS.WEBHOOK)
|
||||
jest.clearAllMocks()
|
||||
|
||||
await update(automation)
|
||||
|
||||
// events
|
||||
expect(events.automation.created).not.toBeCalled()
|
||||
expect(events.automation.stepCreated).not.toBeCalled()
|
||||
expect(events.automation.stepDeleted).not.toBeCalled()
|
||||
expect(events.automation.triggerUpdated).toBeCalledTimes(1)
|
||||
})
|
||||
|
||||
it("adds automation steps", async () => {
|
||||
let automation = newAutomation()
|
||||
automation = await config.createAutomation(automation)
|
||||
automation.definition.steps.push(automationStep())
|
||||
automation.definition.steps.push(automationStep())
|
||||
jest.clearAllMocks()
|
||||
|
||||
// check the post request honours updates with same id
|
||||
await update(automation)
|
||||
|
||||
// events
|
||||
expect(events.automation.stepCreated).toBeCalledTimes(2)
|
||||
expect(events.automation.created).not.toBeCalled()
|
||||
expect(events.automation.stepDeleted).not.toBeCalled()
|
||||
expect(events.automation.triggerUpdated).not.toBeCalled()
|
||||
})
|
||||
|
||||
|
||||
it("removes automation steps", async () => {
|
||||
let automation = newAutomation()
|
||||
automation.definition.steps.push(automationStep())
|
||||
automation = await config.createAutomation(automation)
|
||||
automation.definition.steps = []
|
||||
jest.clearAllMocks()
|
||||
|
||||
// check the post request honours updates with same id
|
||||
await update(automation)
|
||||
|
||||
// events
|
||||
expect(events.automation.stepDeleted).toBeCalledTimes(2)
|
||||
expect(events.automation.stepCreated).not.toBeCalled()
|
||||
expect(events.automation.created).not.toBeCalled()
|
||||
expect(events.automation.triggerUpdated).not.toBeCalled()
|
||||
})
|
||||
|
||||
it("adds and removes automation steps", async () => {
|
||||
let automation = newAutomation()
|
||||
automation = await config.createAutomation(automation)
|
||||
automation.definition.steps = [automationStep(), automationStep()]
|
||||
jest.clearAllMocks()
|
||||
|
||||
// check the post request honours updates with same id
|
||||
await update(automation)
|
||||
|
||||
// events
|
||||
expect(events.automation.stepCreated).toBeCalledTimes(2)
|
||||
expect(events.automation.stepDeleted).toBeCalledTimes(1)
|
||||
expect(events.automation.created).not.toBeCalled()
|
||||
expect(events.automation.triggerUpdated).not.toBeCalled()
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -216,7 +328,8 @@ describe("/automations", () => {
|
|||
.expect('Content-Type', /json/)
|
||||
.expect(200)
|
||||
|
||||
expect(res.body.id).toEqual(automation._id)
|
||||
expect(res.body.id).toEqual(automation._id)
|
||||
expect(events.automation.deleted).toBeCalledTimes(1)
|
||||
})
|
||||
|
||||
it("should apply authorization to endpoint", async () => {
|
||||
|
|
Loading…
Reference in a new issue