Adding some basic test cases for the metadata API, testing that automation tests do store history.

This commit is contained in:
mike12345567 2021-09-10 13:52:41 +01:00
parent da9d78d1fb
commit 84cdec5907
9 changed files with 147 additions and 24 deletions

View File

@ -3,9 +3,10 @@ const actions = require("../../automations/actions")
const logic = require("../../automations/logic") const logic = require("../../automations/logic")
const triggers = require("../../automations/triggers") const triggers = require("../../automations/triggers")
const { getAutomationParams, generateAutomationID } = require("../../db/utils") const { getAutomationParams, generateAutomationID } = require("../../db/utils")
const { saveEntityMetadata } = require("../../utilities") const {
const { MetadataTypes } = require("../../constants") checkForWebhooks,
const { checkForWebhooks } = require("../../automations/utils") updateTestHistory,
} = require("../../automations/utils")
/************************* /*************************
* * * *
@ -171,11 +172,9 @@ exports.test = async function (ctx) {
{ getResponses: true } { getResponses: true }
) )
// save a test history run // save a test history run
await saveEntityMetadata( await updateTestHistory(ctx.appId, automation, {
ctx.appId, ...ctx.request.body,
MetadataTypes.AUTOMATION_TEST_HISTORY, occurredAt: new Date().toISOString(),
automation._id, })
ctx.request.body
)
ctx.body = response ctx.body = response
} }

View File

@ -14,7 +14,12 @@ exports.saveMetadata = async ctx => {
if (type === MetadataTypes.AUTOMATION_TEST_HISTORY) { if (type === MetadataTypes.AUTOMATION_TEST_HISTORY) {
ctx.throw(400, "Cannot save automation history type") ctx.throw(400, "Cannot save automation history type")
} }
await saveEntityMetadata(ctx.appId, type, entityId, ctx.request.body) ctx.body = await saveEntityMetadata(
ctx.appId,
type,
entityId,
ctx.request.body
)
} }
exports.deleteMetadata = async ctx => { exports.deleteMetadata = async ctx => {
@ -34,7 +39,7 @@ exports.deleteMetadata = async ctx => {
await db.remove(id, rev) await db.remove(id, rev)
} }
ctx.body = { ctx.body = {
message: "Metadata deleted successfully.", message: "Metadata deleted successfully",
} }
} }
@ -42,5 +47,13 @@ exports.getMetadata = async ctx => {
const { type, entityId } = ctx.params const { type, entityId } = ctx.params
const db = new CouchDB(ctx.appId) const db = new CouchDB(ctx.appId)
const id = generateMetadataID(type, entityId) const id = generateMetadataID(type, entityId)
ctx.body = await db.get(id) try {
ctx.body = await db.get(id)
} catch (err) {
if (err.status === 404) {
ctx.body = {}
} else {
ctx.throw(err.status, err)
}
}
} }

View File

@ -22,6 +22,7 @@ const datasourceRoutes = require("./datasource")
const queryRoutes = require("./query") const queryRoutes = require("./query")
const hostingRoutes = require("./hosting") const hostingRoutes = require("./hosting")
const backupRoutes = require("./backup") const backupRoutes = require("./backup")
const metadataRoutes = require("./metadata")
const devRoutes = require("./dev") const devRoutes = require("./dev")
exports.mainRoutes = [ exports.mainRoutes = [
@ -46,6 +47,7 @@ exports.mainRoutes = [
queryRoutes, queryRoutes,
hostingRoutes, hostingRoutes,
backupRoutes, backupRoutes,
metadataRoutes,
devRoutes, devRoutes,
// these need to be handled last as they still use /api/:tableId // these need to be handled last as they still use /api/:tableId
// this could be breaking as koa may recognise other routes as this // this could be breaking as koa may recognise other routes as this

View File

@ -4,27 +4,33 @@ const {
middleware: appInfoMiddleware, middleware: appInfoMiddleware,
AppType, AppType,
} = require("../../middleware/appInfo") } = require("../../middleware/appInfo")
const authorized = require("../../middleware/authorized")
const { BUILDER } = require("@budibase/auth/permissions")
const router = Router() const router = Router()
router router
.post( .post(
"/api/metadata/:type/:entityId", "/api/metadata/:type/:entityId",
authorized(BUILDER),
appInfoMiddleware({ appType: AppType.DEV }), appInfoMiddleware({ appType: AppType.DEV }),
controller.saveMetadata controller.saveMetadata
) )
.delete( .delete(
"/api/metadata/:type/:entityId", "/api/metadata/:type/:entityId",
authorized(BUILDER),
appInfoMiddleware({ appType: AppType.DEV }), appInfoMiddleware({ appType: AppType.DEV }),
controller.deleteMetadata controller.deleteMetadata
) )
.get( .get(
"/api/metadata/type", "/api/metadata/type",
authorized(BUILDER),
appInfoMiddleware({ appType: AppType.DEV }), appInfoMiddleware({ appType: AppType.DEV }),
controller.getTypes controller.getTypes
) )
.get( .get(
"/api/metadata/:type/:entityId", "/api/metadata/:type/:entityId",
authorized(BUILDER),
appInfoMiddleware({ appType: AppType.DEV }), appInfoMiddleware({ appType: AppType.DEV }),
controller.getMetadata controller.getMetadata
) )

View File

@ -2,6 +2,7 @@ const {
checkBuilderEndpoint, checkBuilderEndpoint,
getAllTableRows, getAllTableRows,
clearAllAutomations, clearAllAutomations,
triggerAutomation,
} = require("./utilities/TestFunctions") } = require("./utilities/TestFunctions")
const setup = require("./utilities") const setup = require("./utilities")
const { basicAutomation } = setup.structures const { basicAutomation } = setup.structures
@ -23,15 +24,6 @@ describe("/automations", () => {
await config.init() await config.init()
}) })
const triggerWorkflow = async automation => {
return await request
.post(`/api/automations/${automation._id}/trigger`)
.send({ name: "Test", description: "TEST" })
.set(config.defaultHeaders())
.expect('Content-Type', /json/)
.expect(200)
}
describe("get definitions", () => { describe("get definitions", () => {
it("returns a list of definitions for actions", async () => { it("returns a list of definitions for actions", async () => {
const res = await request const res = await request
@ -168,7 +160,7 @@ 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 triggerWorkflow(automation) const res = await triggerAutomation(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

View File

@ -0,0 +1,64 @@
const { testAutomation } = require("./utilities/TestFunctions")
const setup = require("./utilities")
const { MetadataTypes } = require("../../../constants")
describe("/metadata", () => {
let request = setup.getRequest()
let config = setup.getConfig()
let automation
afterAll(setup.afterAll)
beforeEach(async () => {
await config.init()
automation = await config.createAutomation()
})
async function createMetadata(data, type = MetadataTypes.AUTOMATION_TEST_INPUT) {
const res = await request
.post(`/api/metadata/${type}/${automation._id}`)
.send(data)
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(res.body._rev).toBeDefined()
}
async function getMetadata(type) {
const res = await request
.get(`/api/metadata/${type}/${automation._id}`)
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
return res.body
}
describe("save", () => {
it("should be able to save some metadata", async () => {
await createMetadata({ test: "a" })
const testInput = await getMetadata(MetadataTypes.AUTOMATION_TEST_INPUT)
expect(testInput.test).toBe("a")
})
it("should save history metadata on automation run", async () => {
// this should have created some history
await testAutomation(config, automation)
const metadata = await getMetadata(MetadataTypes.AUTOMATION_TEST_HISTORY)
expect(metadata).toBeDefined()
expect(metadata.history.length).toBe(1)
})
})
describe("destroy", () => {
it("should be able to delete some test inputs", async () => {
const res = await request
.delete(`/api/metadata/${MetadataTypes.AUTOMATION_TEST_INPUT}/${automation._id}`)
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(res.body.message).toBeDefined()
const metadata = await getMetadata(MetadataTypes.AUTOMATION_TEST_INPUT)
expect(metadata.test).toBeUndefined()
})
})
})

View File

@ -101,3 +101,21 @@ exports.checkPermissionsEndpoint = async ({
exports.getDB = config => { 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) => {
return await config.request
.post(`/api/automations/${automation._id}/test`)
.send({ name: "Test", description: "TEST" })
.set(config.defaultHeaders())
.expect("Content-Type", /json/)
.expect(200)
}

View File

@ -7,6 +7,8 @@ const webhooks = require("../api/controllers/webhook")
const CouchDB = require("../db") const CouchDB = require("../db")
const { queue } = require("./bullboard") const { queue } = require("./bullboard")
const newid = require("../db/newid") const newid = require("../db/newid")
const { updateEntityMetadata } = require("../utilities")
const { MetadataTypes } = require("../constants")
const WH_STEP_ID = definitions.WEBHOOK.stepId const WH_STEP_ID = definitions.WEBHOOK.stepId
const CRON_STEP_ID = definitions.CRON.stepId const CRON_STEP_ID = definitions.CRON.stepId
@ -63,6 +65,24 @@ exports.processEvent = async job => {
} }
} }
exports.updateTestHistory = async (appId, automation, history) => {
return updateEntityMetadata(
appId,
MetadataTypes.AUTOMATION_TEST_HISTORY,
automation._id,
metadata => {
if (metadata && Array.isArray(metadata.history)) {
metadata.history.push(history)
} else {
metadata = {
history: [history],
}
}
return metadata
}
)
}
// end the repetition and the job itself // end the repetition and the job itself
exports.disableAllCrons = async appId => { exports.disableAllCrons = async appId => {
const promises = [] const promises = []

View File

@ -58,16 +58,19 @@ exports.attachmentsRelativeURL = attachmentKey => {
) )
} }
exports.saveEntityMetadata = async (appId, type, entityId, metadata) => { exports.updateEntityMetadata = async (appId, type, entityId, updateFn) => {
const db = new CouchDB(appId) const db = new CouchDB(appId)
const id = generateMetadataID(type, entityId) const id = generateMetadataID(type, entityId)
// read it to see if it exists, we'll overwrite it no matter what // read it to see if it exists, we'll overwrite it no matter what
let rev let rev,
metadata = {}
try { try {
const oldMetadata = await db.get(id) const oldMetadata = await db.get(id)
rev = oldMetadata._rev rev = oldMetadata._rev
metadata = updateFn(oldMetadata)
} catch (err) { } catch (err) {
rev = null rev = null
metadata = updateFn({})
} }
metadata._id = id metadata._id = id
if (rev) { if (rev) {
@ -80,3 +83,9 @@ exports.saveEntityMetadata = async (appId, type, entityId, metadata) => {
_rev: response.rev, _rev: response.rev,
} }
} }
exports.saveEntityMetadata = async (appId, type, entityId, metadata) => {
return exports.updateEntityMetadata(appId, type, entityId, () => {
return metadata
})
}