Introducing the concept of flagging an automation as 'in test' which means it can run with triggers and everything as it normally would in development.
This commit is contained in:
parent
84cdec5907
commit
3eeb7c27b8
|
@ -13,6 +13,7 @@ exports.Databases = {
|
||||||
DEBOUNCE: "debounce",
|
DEBOUNCE: "debounce",
|
||||||
SESSIONS: "session",
|
SESSIONS: "session",
|
||||||
USER_CACHE: "users",
|
USER_CACHE: "users",
|
||||||
|
FLAGS: "flags",
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.SEPARATOR = SEPARATOR
|
exports.SEPARATOR = SEPARATOR
|
||||||
|
|
|
@ -7,6 +7,7 @@ const {
|
||||||
checkForWebhooks,
|
checkForWebhooks,
|
||||||
updateTestHistory,
|
updateTestHistory,
|
||||||
} = require("../../automations/utils")
|
} = require("../../automations/utils")
|
||||||
|
const { setTestFlag, clearTestFlag } = require("../../utilities/redis")
|
||||||
|
|
||||||
/*************************
|
/*************************
|
||||||
* *
|
* *
|
||||||
|
@ -163,6 +164,7 @@ exports.test = async function (ctx) {
|
||||||
const appId = ctx.appId
|
const appId = ctx.appId
|
||||||
const db = new CouchDB(appId)
|
const db = new CouchDB(appId)
|
||||||
let automation = await db.get(ctx.params.id)
|
let automation = await db.get(ctx.params.id)
|
||||||
|
await setTestFlag(automation._id)
|
||||||
const response = await triggers.externalTrigger(
|
const response = await triggers.externalTrigger(
|
||||||
automation,
|
automation,
|
||||||
{
|
{
|
||||||
|
@ -176,5 +178,6 @@ exports.test = async function (ctx) {
|
||||||
...ctx.request.body,
|
...ctx.request.body,
|
||||||
occurredAt: new Date().toISOString(),
|
occurredAt: new Date().toISOString(),
|
||||||
})
|
})
|
||||||
|
await clearTestFlag(automation._id)
|
||||||
ctx.body = response
|
ctx.body = response
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ const {
|
||||||
checkBuilderEndpoint,
|
checkBuilderEndpoint,
|
||||||
getAllTableRows,
|
getAllTableRows,
|
||||||
clearAllAutomations,
|
clearAllAutomations,
|
||||||
triggerAutomation,
|
testAutomation,
|
||||||
} = require("./utilities/TestFunctions")
|
} = require("./utilities/TestFunctions")
|
||||||
const setup = require("./utilities")
|
const setup = require("./utilities")
|
||||||
const { basicAutomation } = setup.structures
|
const { basicAutomation } = setup.structures
|
||||||
|
@ -160,14 +160,13 @@ describe("/automations", () => {
|
||||||
automation.definition.steps[0].inputs.row.tableId = table._id
|
automation.definition.steps[0].inputs.row.tableId = table._id
|
||||||
automation = await config.createAutomation(automation)
|
automation = await config.createAutomation(automation)
|
||||||
await setup.delay(500)
|
await setup.delay(500)
|
||||||
const res = await triggerAutomation(config, automation)
|
const res = await testAutomation(config, automation)
|
||||||
// this looks a bit mad but we don't actually have a way to wait for a response from the automation to
|
// 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
|
// 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
|
// also when this runs in CI it is very temper-mental so for now trying to make run stable by repeating until it works
|
||||||
// TODO: update when workflow logs are a thing
|
// TODO: update when workflow logs are a thing
|
||||||
for (let tries = 0; tries < MAX_RETRIES; tries++) {
|
for (let tries = 0; tries < MAX_RETRIES; tries++) {
|
||||||
expect(res.body.message).toEqual(`Automation ${automation._id} has been triggered.`)
|
expect(res.body).toBeDefined()
|
||||||
expect(res.body.automation.name).toEqual(automation.name)
|
|
||||||
await setup.delay(500)
|
await setup.delay(500)
|
||||||
let elements = await getAllTableRows(config)
|
let elements = await getAllTableRows(config)
|
||||||
// don't test it unless there are values to test
|
// don't test it unless there are values to test
|
||||||
|
|
|
@ -102,19 +102,15 @@ exports.getDB = config => {
|
||||||
return new CouchDB(config.getAppId())
|
return new CouchDB(config.getAppId())
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.triggerAutomation = async (config, automation) => {
|
|
||||||
return await config.request
|
|
||||||
.post(`/api/automations/${automation._id}/trigger`)
|
|
||||||
.send({ name: "Test", description: "TEST" })
|
|
||||||
.set(config.defaultHeaders())
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(200)
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.testAutomation = async (config, automation) => {
|
exports.testAutomation = async (config, automation) => {
|
||||||
return await config.request
|
return await config.request
|
||||||
.post(`/api/automations/${automation._id}/test`)
|
.post(`/api/automations/${automation._id}/test`)
|
||||||
.send({ name: "Test", description: "TEST" })
|
.send({
|
||||||
|
row: {
|
||||||
|
name: "Test",
|
||||||
|
description: "TEST",
|
||||||
|
},
|
||||||
|
})
|
||||||
.set(config.defaultHeaders())
|
.set(config.defaultHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
|
@ -7,6 +7,7 @@ const { isDevAppID } = require("../db/utils")
|
||||||
// need this to call directly, so we can get a response
|
// need this to call directly, so we can get a response
|
||||||
const { processEvent } = require("./utils")
|
const { processEvent } = require("./utils")
|
||||||
const { queue } = require("./bullboard")
|
const { queue } = require("./bullboard")
|
||||||
|
const { checkTestFlag } = require("../utilities/redis")
|
||||||
|
|
||||||
const TRIGGER_DEFINITIONS = definitions
|
const TRIGGER_DEFINITIONS = definitions
|
||||||
|
|
||||||
|
@ -14,11 +15,7 @@ async function queueRelevantRowAutomations(event, eventType) {
|
||||||
if (event.appId == null) {
|
if (event.appId == null) {
|
||||||
throw `No appId specified for ${eventType} - check event emitters.`
|
throw `No appId specified for ${eventType} - check event emitters.`
|
||||||
}
|
}
|
||||||
// don't queue events which are for dev apps, only way to test automations is
|
|
||||||
// running tests on them
|
|
||||||
if (isDevAppID(event.appId)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const db = new CouchDB(event.appId)
|
const db = new CouchDB(event.appId)
|
||||||
let automations = await db.allDocs(
|
let automations = await db.allDocs(
|
||||||
getAutomationParams(null, { include_docs: true })
|
getAutomationParams(null, { include_docs: true })
|
||||||
|
@ -33,6 +30,12 @@ async function queueRelevantRowAutomations(event, eventType) {
|
||||||
})
|
})
|
||||||
|
|
||||||
for (let automation of automations) {
|
for (let automation of automations) {
|
||||||
|
// don't queue events which are for dev apps, only way to test automations is
|
||||||
|
// running tests on them
|
||||||
|
// in production the test flag will never be checked due to lazy evaluation (first always false)
|
||||||
|
if (isDevAppID(event.appId) && !(await checkTestFlag(automation._id))) {
|
||||||
|
return
|
||||||
|
}
|
||||||
let automationDef = automation.definition
|
let automationDef = automation.definition
|
||||||
let automationTrigger = automationDef ? automationDef.trigger : {}
|
let automationTrigger = automationDef ? automationDef.trigger : {}
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -2,20 +2,24 @@ const { Client, utils } = require("@budibase/auth/redis")
|
||||||
const { getGlobalIDFromUserMetadataID } = require("../db/utils")
|
const { getGlobalIDFromUserMetadataID } = require("../db/utils")
|
||||||
|
|
||||||
const APP_DEV_LOCK_SECONDS = 600
|
const APP_DEV_LOCK_SECONDS = 600
|
||||||
let devAppClient, debounceClient
|
const AUTOMATION_TEST_FLAG_SECONDS = 60
|
||||||
|
let devAppClient, debounceClient, flagClient
|
||||||
|
|
||||||
// we init this as we want to keep the connection open all the time
|
// we init this as we want to keep the connection open all the time
|
||||||
// reduces the performance hit
|
// reduces the performance hit
|
||||||
exports.init = async () => {
|
exports.init = async () => {
|
||||||
devAppClient = new Client(utils.Databases.DEV_LOCKS)
|
devAppClient = new Client(utils.Databases.DEV_LOCKS)
|
||||||
debounceClient = new Client(utils.Databases.DEBOUNCE)
|
debounceClient = new Client(utils.Databases.DEBOUNCE)
|
||||||
|
flagClient = new Client(utils.Databases.FLAGS)
|
||||||
await devAppClient.init()
|
await devAppClient.init()
|
||||||
await debounceClient.init()
|
await debounceClient.init()
|
||||||
|
await flagClient.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.shutdown = async () => {
|
exports.shutdown = async () => {
|
||||||
if (devAppClient) await devAppClient.finish()
|
if (devAppClient) await devAppClient.finish()
|
||||||
if (debounceClient) await debounceClient.finish()
|
if (debounceClient) await debounceClient.finish()
|
||||||
|
if (flagClient) await flagClient.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.doesUserHaveLock = async (devAppId, user) => {
|
exports.doesUserHaveLock = async (devAppId, user) => {
|
||||||
|
@ -67,3 +71,16 @@ exports.checkDebounce = async id => {
|
||||||
exports.setDebounce = async (id, seconds) => {
|
exports.setDebounce = async (id, seconds) => {
|
||||||
await debounceClient.store(id, "debouncing", seconds)
|
await debounceClient.store(id, "debouncing", seconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.setTestFlag = async id => {
|
||||||
|
await flagClient.store(id, { testing: true }, AUTOMATION_TEST_FLAG_SECONDS)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.checkTestFlag = async id => {
|
||||||
|
const flag = await flagClient.get(id)
|
||||||
|
return !!(flag && flag.testing)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.clearTestFlag = async id => {
|
||||||
|
await devAppClient.delete(id)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue