Fixing up tests, need to mock most of the worker functionality so that worker doesn't need to run during tests.

This commit is contained in:
mike12345567 2021-04-13 20:25:43 +01:00
parent 105e1cc16f
commit c7c158dd84
8 changed files with 126 additions and 112 deletions

View File

@ -7,7 +7,7 @@ const { generateUserMetadataID } = require("../../db/utils")
const { setCookie } = require("../../utilities") const { setCookie } = require("../../utilities")
const { outputProcessing } = require("../../utilities/rowProcessor") const { outputProcessing } = require("../../utilities/rowProcessor")
const { InternalTables } = require("../../db/utils") const { InternalTables } = require("../../db/utils")
const { UserStatus, StaticDatabases } = require("@budibase/auth") const { UserStatus } = require("@budibase/auth")
const { getFullUser } = require("../../utilities/users") const { getFullUser } = require("../../utilities/users")
const INVALID_ERR = "Invalid Credentials" const INVALID_ERR = "Invalid Credentials"

View File

@ -35,13 +35,12 @@ function cleanAutomationInputs(automation) {
/** /**
* This function handles checking if any webhooks need to be created or deleted for automations. * This function handles checking if any webhooks need to be created or deleted for automations.
* @param {string} appId The ID of the app in which we are checking for webhooks * @param {string} appId The ID of the app in which we are checking for webhooks
* @param {object} user The user object, including all auth info
* @param {object|undefined} oldAuto The old automation object if updating/deleting * @param {object|undefined} oldAuto The old automation object if updating/deleting
* @param {object|undefined} newAuto The new automation object if creating/updating * @param {object|undefined} newAuto The new automation object if creating/updating
* @returns {Promise<object|undefined>} After this is complete the new automation object may have been updated and should be * @returns {Promise<object|undefined>} After this is complete the new automation object may have been updated and should be
* written to DB (this does not write to DB as it would be wasteful to repeat). * written to DB (this does not write to DB as it would be wasteful to repeat).
*/ */
async function checkForWebhooks({ appId, user, oldAuto, newAuto }) { async function checkForWebhooks({ appId, oldAuto, newAuto }) {
const oldTrigger = oldAuto ? oldAuto.definition.trigger : null const oldTrigger = oldAuto ? oldAuto.definition.trigger : null
const newTrigger = newAuto ? newAuto.definition.trigger : null const newTrigger = newAuto ? newAuto.definition.trigger : null
function isWebhookTrigger(auto) { function isWebhookTrigger(auto) {
@ -61,7 +60,7 @@ async function checkForWebhooks({ appId, user, oldAuto, newAuto }) {
// need to get the webhook to get the rev // need to get the webhook to get the rev
const webhook = await db.get(oldTrigger.webhookId) const webhook = await db.get(oldTrigger.webhookId)
const ctx = { const ctx = {
user, appId,
params: { id: webhook._id, rev: webhook._rev }, params: { id: webhook._id, rev: webhook._rev },
} }
// might be updating - reset the inputs to remove the URLs // might be updating - reset the inputs to remove the URLs
@ -74,7 +73,7 @@ async function checkForWebhooks({ appId, user, oldAuto, newAuto }) {
// need to create webhook // need to create webhook
else if (!isWebhookTrigger(oldAuto) && isWebhookTrigger(newAuto)) { else if (!isWebhookTrigger(oldAuto) && isWebhookTrigger(newAuto)) {
const ctx = { const ctx = {
user, appId,
request: { request: {
body: new webhooks.Webhook( body: new webhooks.Webhook(
"Automation webhook", "Automation webhook",
@ -110,7 +109,6 @@ exports.create = async function(ctx) {
automation = cleanAutomationInputs(automation) automation = cleanAutomationInputs(automation)
automation = await checkForWebhooks({ automation = await checkForWebhooks({
appId: ctx.appId, appId: ctx.appId,
user: ctx.user,
newAuto: automation, newAuto: automation,
}) })
const response = await db.put(automation) const response = await db.put(automation)
@ -134,7 +132,6 @@ exports.update = async function(ctx) {
automation = cleanAutomationInputs(automation) automation = cleanAutomationInputs(automation)
automation = await checkForWebhooks({ automation = await checkForWebhooks({
appId: ctx.appId, appId: ctx.appId,
user: ctx.user,
oldAuto: oldAutomation, oldAuto: oldAutomation,
newAuto: automation, newAuto: automation,
}) })
@ -172,7 +169,6 @@ exports.destroy = async function(ctx) {
const oldAutomation = await db.get(ctx.params.id) const oldAutomation = await db.get(ctx.params.id)
await checkForWebhooks({ await checkForWebhooks({
appId: ctx.appId, appId: ctx.appId,
user: ctx.user,
oldAuto: oldAutomation, oldAuto: oldAutomation,
}) })
ctx.body = await db.remove(ctx.params.id, ctx.params.rev) ctx.body = await db.remove(ctx.params.id, ctx.params.rev)

View File

@ -44,6 +44,10 @@ exports.createMetadata = async function(ctx) {
const db = new CouchDB(appId) const db = new CouchDB(appId)
const { email, roleId } = ctx.request.body const { email, roleId } = ctx.request.body
if (!email) {
ctx.throw(400, "Require email to manage user")
}
// check role valid // check role valid
const role = await getRole(appId, roleId) const role = await getRole(appId, roleId)
if (!role) ctx.throw(400, "Invalid Role") if (!role) ctx.throw(400, "Invalid Role")
@ -73,9 +77,11 @@ exports.updateMetadata = async function(ctx) {
const user = ctx.request.body const user = ctx.request.body
let email = user.email || getEmailFromUserMetadataID(user._id) let email = user.email || getEmailFromUserMetadataID(user._id)
const metadata = await saveGlobalUser(ctx, appId, email, ctx.request.body) const metadata = await saveGlobalUser(ctx, appId, email, ctx.request.body)
if (!metadata._id) { if (!metadata._id) {
user._id = generateUserMetadataID(email) metadata._id = generateUserMetadataID(email)
}
if (!metadata._rev) {
metadata._rev = ctx.request.body._rev
} }
ctx.body = await db.put({ ctx.body = await db.put({
...metadata, ...metadata,

View File

@ -1,5 +1,15 @@
const setup = require("./utilities") const setup = require("./utilities")
require("../../../utilities/workerRequests")
jest.mock("../../../utilities/workerRequests", () => ({
getGlobalUsers: jest.fn(() => {
return {
email: "test@test.com",
}
}),
saveGlobalUser: jest.fn(),
}))
describe("/authenticate", () => { describe("/authenticate", () => {
let request = setup.getRequest() let request = setup.getRequest()
let config = setup.getConfig() let config = setup.getConfig()
@ -10,88 +20,8 @@ describe("/authenticate", () => {
await config.init() await config.init()
}) })
describe("authenticate", () => {
it("should be able to create a layout", async () => {
await config.createUser("test@test.com", "p4ssw0rd")
const res = await request
.post(`/api/authenticate`)
.send({
email: "test@test.com",
password: "p4ssw0rd",
})
.set(config.publicHeaders())
.expect("Content-Type", /json/)
.expect(200)
expect(res.body.token).toBeDefined()
expect(res.body.email).toEqual("test@test.com")
expect(res.body.password).toBeUndefined()
})
it("should error if no app specified", async () => {
await request
.post(`/api/authenticate`)
.expect(400)
})
it("should error if no email specified", async () => {
await request
.post(`/api/authenticate`)
.send({
password: "test",
})
.set(config.publicHeaders())
.expect(400)
})
it("should error if no password specified", async () => {
await request
.post(`/api/authenticate`)
.send({
email: "test",
})
.set(config.publicHeaders())
.expect(400)
})
it("should error if invalid user specified", async () => {
await request
.post(`/api/authenticate`)
.send({
email: "test",
password: "test",
})
.set(config.publicHeaders())
.expect(401)
})
it("should throw same error if wrong password specified", async () => {
await config.createUser("test@test.com", "password")
await request
.post(`/api/authenticate`)
.send({
email: "test@test.com",
password: "test",
})
.set(config.publicHeaders())
.expect(401)
})
it("should throw an error for inactive users", async () => {
await config.createUser("test@test.com", "password")
await config.makeUserInactive("test@test.com")
await request
.post(`/api/authenticate`)
.send({
email: "test@test.com",
password: "password",
})
.set(config.publicHeaders())
.expect(401)
})
})
describe("fetch self", () => { describe("fetch self", () => {
it("should be able to delete the layout", async () => { it("should be able to fetch self", async () => {
await config.createUser("test@test.com", "p4ssw0rd") await config.createUser("test@test.com", "p4ssw0rd")
const headers = await config.login("test@test.com", "p4ssw0rd") const headers = await config.login("test@test.com", "p4ssw0rd")
const res = await request const res = await request

View File

@ -2,6 +2,12 @@ const setup = require("./utilities")
const { basicScreen } = setup.structures const { basicScreen } = setup.structures
const { checkBuilderEndpoint } = require("./utilities/TestFunctions") const { checkBuilderEndpoint } = require("./utilities/TestFunctions")
const { BUILTIN_ROLE_IDS } = require("../../../utilities/security/roles") const { BUILTIN_ROLE_IDS } = require("../../../utilities/security/roles")
const workerRequests = require("../../../utilities/workerRequests")
jest.mock("../../../utilities/workerRequests", () => ({
getGlobalUsers: jest.fn(),
saveGlobalUser: jest.fn(),
}))
const route = "/test" const route = "/test"
@ -25,6 +31,13 @@ describe("/routing", () => {
describe("fetch", () => { describe("fetch", () => {
it("returns the correct routing for basic user", async () => { it("returns the correct routing for basic user", async () => {
workerRequests.getGlobalUsers.mockImplementationOnce((ctx, appId) => {
return {
roles: {
[appId]: BUILTIN_ROLE_IDS.BASIC,
}
}
})
const res = await request const res = await request
.get(`/api/routing/client`) .get(`/api/routing/client`)
.set(await config.roleHeaders("basic@test.com", BUILTIN_ROLE_IDS.BASIC)) .set(await config.roleHeaders("basic@test.com", BUILTIN_ROLE_IDS.BASIC))
@ -42,6 +55,13 @@ describe("/routing", () => {
}) })
it("returns the correct routing for power user", async () => { it("returns the correct routing for power user", async () => {
workerRequests.getGlobalUsers.mockImplementationOnce((ctx, appId) => {
return {
roles: {
[appId]: BUILTIN_ROLE_IDS.POWER,
}
}
})
const res = await request const res = await request
.get(`/api/routing/client`) .get(`/api/routing/client`)
.set(await config.roleHeaders("basic@test.com", BUILTIN_ROLE_IDS.POWER)) .set(await config.roleHeaders("basic@test.com", BUILTIN_ROLE_IDS.POWER))

View File

@ -2,6 +2,15 @@ const { BUILTIN_ROLE_IDS } = require("../../../utilities/security/roles")
const { checkPermissionsEndpoint } = require("./utilities/TestFunctions") const { checkPermissionsEndpoint } = require("./utilities/TestFunctions")
const setup = require("./utilities") const setup = require("./utilities")
const { basicUser } = setup.structures const { basicUser } = setup.structures
const workerRequests = require("../../../utilities/workerRequests")
jest.mock("../../../utilities/workerRequests", () => ({
getGlobalUsers: jest.fn(),
saveGlobalUser: jest.fn(() => {
return {}
}),
deleteGlobalUser: jest.fn(),
}))
describe("/users", () => { describe("/users", () => {
let request = setup.getRequest() let request = setup.getRequest()
@ -14,11 +23,23 @@ describe("/users", () => {
}) })
describe("fetch", () => { describe("fetch", () => {
beforeEach(() => {
workerRequests.getGlobalUsers.mockImplementationOnce(() => ([
{
email: "brenda@brenda.com"
},
{
email: "pam@pam.com"
}
]
))
})
it("returns a list of users from an instance db", async () => { it("returns a list of users from an instance db", async () => {
await config.createUser("brenda@brenda.com", "brendas_password") await config.createUser("brenda@brenda.com", "brendas_password")
await config.createUser("pam@pam.com", "pam_password") await config.createUser("pam@pam.com", "pam_password")
const res = await request const res = await request
.get(`/api/users`) .get(`/api/users/metadata`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200)
@ -34,7 +55,7 @@ describe("/users", () => {
config, config,
request, request,
method: "GET", method: "GET",
url: `/api/users`, url: `/api/users/metadata`,
passRole: BUILTIN_ROLE_IDS.ADMIN, passRole: BUILTIN_ROLE_IDS.ADMIN,
failRole: BUILTIN_ROLE_IDS.PUBLIC, failRole: BUILTIN_ROLE_IDS.PUBLIC,
}) })
@ -42,9 +63,21 @@ describe("/users", () => {
}) })
describe("create", () => { describe("create", () => {
beforeEach(() => {
workerRequests.getGlobalUsers.mockImplementationOnce(() => ([
{
email: "bill@budibase.com"
},
{
email: "brandNewUser@user.com"
}
]
))
})
async function create(user, status = 200) { async function create(user, status = 200) {
return request return request
.post(`/api/users`) .post(`/api/users/metadata`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.send(user) .send(user)
.expect(status) .expect(status)
@ -56,8 +89,8 @@ describe("/users", () => {
body.email = "bill@budibase.com" body.email = "bill@budibase.com"
const res = await create(body) const res = await create(body)
expect(res.res.statusMessage).toEqual("User created successfully.") expect(res.res.statusMessage).toEqual("OK")
expect(res.body._id).toBeUndefined() expect(res.body._id).toBeDefined()
}) })
it("should apply authorization to endpoint", async () => { it("should apply authorization to endpoint", async () => {
@ -67,7 +100,7 @@ describe("/users", () => {
config, config,
method: "POST", method: "POST",
body, body,
url: `/api/users`, url: `/api/users/metadata`,
passRole: BUILTIN_ROLE_IDS.ADMIN, passRole: BUILTIN_ROLE_IDS.ADMIN,
failRole: BUILTIN_ROLE_IDS.PUBLIC, failRole: BUILTIN_ROLE_IDS.PUBLIC,
}) })
@ -88,16 +121,22 @@ describe("/users", () => {
await config.createUser("test@test.com") await config.createUser("test@test.com")
const user = basicUser(BUILTIN_ROLE_IDS.POWER) const user = basicUser(BUILTIN_ROLE_IDS.POWER)
user.email = "test@test.com" user.email = "test@test.com"
await create(user, 400) await create(user, 409)
}) })
}) })
describe("update", () => { describe("update", () => {
beforeEach(() => {
workerRequests.saveGlobalUser.mockImplementationOnce(() => ({
_id: "us_test@test.com"
}))
})
it("should be able to update the user", async () => { it("should be able to update the user", async () => {
const user = await config.createUser() const user = await config.createUser()
user.roleId = BUILTIN_ROLE_IDS.BASIC user.roleId = BUILTIN_ROLE_IDS.BASIC
const res = await request const res = await request
.put(`/api/users`) .put(`/api/users/metadata`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.send(user) .send(user)
.expect(200) .expect(200)
@ -111,20 +150,29 @@ describe("/users", () => {
const email = "test@test.com" const email = "test@test.com"
await config.createUser(email) await config.createUser(email)
const res = await request const res = await request
.delete(`/api/users/${email}`) .delete(`/api/users/metadata/${email}`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect(200) .expect(200)
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
expect(res.body.message).toBeDefined() expect(res.body.message).toBeDefined()
expect(workerRequests.deleteGlobalUser).toHaveBeenCalled()
}) })
}) })
describe("find", () => { describe("find", () => {
beforeEach(() => {
jest.resetAllMocks()
workerRequests.getGlobalUsers.mockImplementationOnce(() => ({
email: "test@test.com",
roleId: BUILTIN_ROLE_IDS.POWER,
}))
})
it("should be able to find the user", async () => { it("should be able to find the user", async () => {
const email = "test@test.com" const email = "test@test.com"
await config.createUser(email) await config.createUser(email)
const res = await request const res = await request
.get(`/api/users/${email}`) .get(`/api/users/metadata/${email}`)
.set(config.defaultHeaders()) .set(config.defaultHeaders())
.expect(200) .expect(200)
.expect("Content-Type", /json/) .expect("Content-Type", /json/)

View File

@ -3,7 +3,7 @@ const appController = require("../../../controllers/application")
const CouchDB = require("../../../../db") const CouchDB = require("../../../../db")
function Request(appId, params) { function Request(appId, params) {
this.user = { appId } this.appId = appId
this.params = params this.params = params
} }
@ -63,7 +63,11 @@ exports.checkPermissionsEndpoint = async ({
}) => { }) => {
const password = "PASSWORD" const password = "PASSWORD"
await config.createUser("passUser@budibase.com", password, passRole) await config.createUser("passUser@budibase.com", password, passRole)
const passHeader = await config.login("passUser@budibase.com", password) const passHeader = await config.login(
"passUser@budibase.com",
password,
passRole
)
await exports await exports
.createRequest(config.request, method, url, body) .createRequest(config.request, method, url, body)
@ -71,7 +75,11 @@ exports.checkPermissionsEndpoint = async ({
.expect(200) .expect(200)
await config.createUser("failUser@budibase.com", password, failRole) await config.createUser("failUser@budibase.com", password, failRole)
const failHeader = await config.login("failUser@budibase.com", password) const failHeader = await config.login(
"failUser@budibase.com",
password,
failRole
)
await exports await exports
.createRequest(config.request, method, url, body) .createRequest(config.request, method, url, body)

View File

@ -72,7 +72,6 @@ class TestConfiguration {
const user = { const user = {
userId: "us_test@test.com", userId: "us_test@test.com",
email: "test@test.com", email: "test@test.com",
roleId: BUILTIN_ROLE_IDS.BUILDER,
builder: { builder: {
global: true, global: true,
}, },
@ -112,7 +111,7 @@ class TestConfiguration {
} catch (err) { } catch (err) {
// allow errors here // allow errors here
} }
return this.login(email, PASSWORD) return this.login(email, PASSWORD, roleId)
} }
async createApp(appName) { async createApp(appName) {
@ -312,7 +311,7 @@ class TestConfiguration {
) )
} }
async login(email, password) { async login(email, password, roleId = BUILTIN_ROLE_IDS.BUILDER) {
if (!this.request) { if (!this.request) {
throw "Server has not been opened, cannot login." throw "Server has not been opened, cannot login."
} }
@ -320,16 +319,23 @@ class TestConfiguration {
await this.createUser() await this.createUser()
} }
const user = { const user = {
userId: "us_test@test.com", userId: `us_${email || EMAIL}`,
email: EMAIL, email: email || EMAIL,
roleId: BUILTIN_ROLE_IDS.BASIC,
} }
const token = jwt.sign(user, env.JWT_SECRET) const app = {
roleId: roleId,
appId: this.appId,
}
const authToken = jwt.sign(user, env.JWT_SECRET)
const appToken = jwt.sign(app, env.JWT_SECRET)
// returning necessary request headers // returning necessary request headers
return { return {
Accept: "application/json", Accept: "application/json",
Cookie: [`${Cookies.Auth}=${token}`], Cookie: [
`${Cookies.Auth}=${authToken}`,
`${Cookies.CurrentApp}=${appToken}`,
],
"x-budibase-app-id": this.appId, "x-budibase-app-id": this.appId,
} }
} }