From c7c158dd846ba7b517df77ce8483f0943ff51f4d Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 13 Apr 2021 20:25:43 +0100 Subject: [PATCH] Fixing up tests, need to mock most of the worker functionality so that worker doesn't need to run during tests. --- packages/server/src/api/controllers/auth.js | 2 +- .../server/src/api/controllers/automation.js | 10 +- packages/server/src/api/controllers/user.js | 10 +- .../server/src/api/routes/tests/auth.spec.js | 92 +++---------------- .../src/api/routes/tests/routing.spec.js | 20 ++++ .../server/src/api/routes/tests/user.spec.js | 68 ++++++++++++-- .../routes/tests/utilities/TestFunctions.js | 14 ++- .../src/tests/utilities/TestConfiguration.js | 22 +++-- 8 files changed, 126 insertions(+), 112 deletions(-) diff --git a/packages/server/src/api/controllers/auth.js b/packages/server/src/api/controllers/auth.js index a500598305..64f4bf7bcb 100644 --- a/packages/server/src/api/controllers/auth.js +++ b/packages/server/src/api/controllers/auth.js @@ -7,7 +7,7 @@ const { generateUserMetadataID } = require("../../db/utils") const { setCookie } = require("../../utilities") const { outputProcessing } = require("../../utilities/rowProcessor") const { InternalTables } = require("../../db/utils") -const { UserStatus, StaticDatabases } = require("@budibase/auth") +const { UserStatus } = require("@budibase/auth") const { getFullUser } = require("../../utilities/users") const INVALID_ERR = "Invalid Credentials" diff --git a/packages/server/src/api/controllers/automation.js b/packages/server/src/api/controllers/automation.js index d3ed836bc9..0f210f633c 100644 --- a/packages/server/src/api/controllers/automation.js +++ b/packages/server/src/api/controllers/automation.js @@ -35,13 +35,12 @@ function cleanAutomationInputs(automation) { /** * 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 {object} user The user object, including all auth info * @param {object|undefined} oldAuto The old automation object if updating/deleting * @param {object|undefined} newAuto The new automation object if creating/updating * @returns {Promise} 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). */ -async function checkForWebhooks({ appId, user, oldAuto, newAuto }) { +async function checkForWebhooks({ appId, oldAuto, newAuto }) { const oldTrigger = oldAuto ? oldAuto.definition.trigger : null const newTrigger = newAuto ? newAuto.definition.trigger : null function isWebhookTrigger(auto) { @@ -61,7 +60,7 @@ async function checkForWebhooks({ appId, user, oldAuto, newAuto }) { // need to get the webhook to get the rev const webhook = await db.get(oldTrigger.webhookId) const ctx = { - user, + appId, params: { id: webhook._id, rev: webhook._rev }, } // 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 else if (!isWebhookTrigger(oldAuto) && isWebhookTrigger(newAuto)) { const ctx = { - user, + appId, request: { body: new webhooks.Webhook( "Automation webhook", @@ -110,7 +109,6 @@ exports.create = async function(ctx) { automation = cleanAutomationInputs(automation) automation = await checkForWebhooks({ appId: ctx.appId, - user: ctx.user, newAuto: automation, }) const response = await db.put(automation) @@ -134,7 +132,6 @@ exports.update = async function(ctx) { automation = cleanAutomationInputs(automation) automation = await checkForWebhooks({ appId: ctx.appId, - user: ctx.user, oldAuto: oldAutomation, newAuto: automation, }) @@ -172,7 +169,6 @@ exports.destroy = async function(ctx) { const oldAutomation = await db.get(ctx.params.id) await checkForWebhooks({ appId: ctx.appId, - user: ctx.user, oldAuto: oldAutomation, }) ctx.body = await db.remove(ctx.params.id, ctx.params.rev) diff --git a/packages/server/src/api/controllers/user.js b/packages/server/src/api/controllers/user.js index f800a54ace..ab112ccd01 100644 --- a/packages/server/src/api/controllers/user.js +++ b/packages/server/src/api/controllers/user.js @@ -44,6 +44,10 @@ exports.createMetadata = async function(ctx) { const db = new CouchDB(appId) const { email, roleId } = ctx.request.body + if (!email) { + ctx.throw(400, "Require email to manage user") + } + // check role valid const role = await getRole(appId, roleId) if (!role) ctx.throw(400, "Invalid Role") @@ -73,9 +77,11 @@ exports.updateMetadata = async function(ctx) { const user = ctx.request.body let email = user.email || getEmailFromUserMetadataID(user._id) const metadata = await saveGlobalUser(ctx, appId, email, ctx.request.body) - 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({ ...metadata, diff --git a/packages/server/src/api/routes/tests/auth.spec.js b/packages/server/src/api/routes/tests/auth.spec.js index 13695d596d..ec38003c1d 100644 --- a/packages/server/src/api/routes/tests/auth.spec.js +++ b/packages/server/src/api/routes/tests/auth.spec.js @@ -1,5 +1,15 @@ const setup = require("./utilities") +require("../../../utilities/workerRequests") +jest.mock("../../../utilities/workerRequests", () => ({ + getGlobalUsers: jest.fn(() => { + return { + email: "test@test.com", + } + }), + saveGlobalUser: jest.fn(), +})) + describe("/authenticate", () => { let request = setup.getRequest() let config = setup.getConfig() @@ -10,88 +20,8 @@ describe("/authenticate", () => { 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", () => { - it("should be able to delete the layout", async () => { + it("should be able to fetch self", async () => { await config.createUser("test@test.com", "p4ssw0rd") const headers = await config.login("test@test.com", "p4ssw0rd") const res = await request diff --git a/packages/server/src/api/routes/tests/routing.spec.js b/packages/server/src/api/routes/tests/routing.spec.js index beb1659b2a..79b28e82dd 100644 --- a/packages/server/src/api/routes/tests/routing.spec.js +++ b/packages/server/src/api/routes/tests/routing.spec.js @@ -2,6 +2,12 @@ const setup = require("./utilities") const { basicScreen } = setup.structures const { checkBuilderEndpoint } = require("./utilities/TestFunctions") 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" @@ -25,6 +31,13 @@ describe("/routing", () => { describe("fetch", () => { 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 .get(`/api/routing/client`) .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 () => { + workerRequests.getGlobalUsers.mockImplementationOnce((ctx, appId) => { + return { + roles: { + [appId]: BUILTIN_ROLE_IDS.POWER, + } + } + }) const res = await request .get(`/api/routing/client`) .set(await config.roleHeaders("basic@test.com", BUILTIN_ROLE_IDS.POWER)) diff --git a/packages/server/src/api/routes/tests/user.spec.js b/packages/server/src/api/routes/tests/user.spec.js index 808f1a2622..afdedef512 100644 --- a/packages/server/src/api/routes/tests/user.spec.js +++ b/packages/server/src/api/routes/tests/user.spec.js @@ -2,6 +2,15 @@ const { BUILTIN_ROLE_IDS } = require("../../../utilities/security/roles") const { checkPermissionsEndpoint } = require("./utilities/TestFunctions") const setup = require("./utilities") 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", () => { let request = setup.getRequest() @@ -14,11 +23,23 @@ describe("/users", () => { }) 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 () => { await config.createUser("brenda@brenda.com", "brendas_password") await config.createUser("pam@pam.com", "pam_password") const res = await request - .get(`/api/users`) + .get(`/api/users/metadata`) .set(config.defaultHeaders()) .expect("Content-Type", /json/) .expect(200) @@ -34,7 +55,7 @@ describe("/users", () => { config, request, method: "GET", - url: `/api/users`, + url: `/api/users/metadata`, passRole: BUILTIN_ROLE_IDS.ADMIN, failRole: BUILTIN_ROLE_IDS.PUBLIC, }) @@ -42,9 +63,21 @@ describe("/users", () => { }) describe("create", () => { + beforeEach(() => { + workerRequests.getGlobalUsers.mockImplementationOnce(() => ([ + { + email: "bill@budibase.com" + }, + { + email: "brandNewUser@user.com" + } + ] + )) + }) + async function create(user, status = 200) { return request - .post(`/api/users`) + .post(`/api/users/metadata`) .set(config.defaultHeaders()) .send(user) .expect(status) @@ -56,8 +89,8 @@ describe("/users", () => { body.email = "bill@budibase.com" const res = await create(body) - expect(res.res.statusMessage).toEqual("User created successfully.") - expect(res.body._id).toBeUndefined() + expect(res.res.statusMessage).toEqual("OK") + expect(res.body._id).toBeDefined() }) it("should apply authorization to endpoint", async () => { @@ -67,7 +100,7 @@ describe("/users", () => { config, method: "POST", body, - url: `/api/users`, + url: `/api/users/metadata`, passRole: BUILTIN_ROLE_IDS.ADMIN, failRole: BUILTIN_ROLE_IDS.PUBLIC, }) @@ -88,16 +121,22 @@ describe("/users", () => { await config.createUser("test@test.com") const user = basicUser(BUILTIN_ROLE_IDS.POWER) user.email = "test@test.com" - await create(user, 400) + await create(user, 409) }) }) describe("update", () => { + beforeEach(() => { + workerRequests.saveGlobalUser.mockImplementationOnce(() => ({ + _id: "us_test@test.com" + })) + }) + it("should be able to update the user", async () => { const user = await config.createUser() user.roleId = BUILTIN_ROLE_IDS.BASIC const res = await request - .put(`/api/users`) + .put(`/api/users/metadata`) .set(config.defaultHeaders()) .send(user) .expect(200) @@ -111,20 +150,29 @@ describe("/users", () => { const email = "test@test.com" await config.createUser(email) const res = await request - .delete(`/api/users/${email}`) + .delete(`/api/users/metadata/${email}`) .set(config.defaultHeaders()) .expect(200) .expect("Content-Type", /json/) expect(res.body.message).toBeDefined() + expect(workerRequests.deleteGlobalUser).toHaveBeenCalled() }) }) 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 () => { const email = "test@test.com" await config.createUser(email) const res = await request - .get(`/api/users/${email}`) + .get(`/api/users/metadata/${email}`) .set(config.defaultHeaders()) .expect(200) .expect("Content-Type", /json/) diff --git a/packages/server/src/api/routes/tests/utilities/TestFunctions.js b/packages/server/src/api/routes/tests/utilities/TestFunctions.js index 313b9e63a8..0bcb4512a7 100644 --- a/packages/server/src/api/routes/tests/utilities/TestFunctions.js +++ b/packages/server/src/api/routes/tests/utilities/TestFunctions.js @@ -3,7 +3,7 @@ const appController = require("../../../controllers/application") const CouchDB = require("../../../../db") function Request(appId, params) { - this.user = { appId } + this.appId = appId this.params = params } @@ -63,7 +63,11 @@ exports.checkPermissionsEndpoint = async ({ }) => { const password = "PASSWORD" 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 .createRequest(config.request, method, url, body) @@ -71,7 +75,11 @@ exports.checkPermissionsEndpoint = async ({ .expect(200) 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 .createRequest(config.request, method, url, body) diff --git a/packages/server/src/tests/utilities/TestConfiguration.js b/packages/server/src/tests/utilities/TestConfiguration.js index 3e148970b1..42ff603139 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.js +++ b/packages/server/src/tests/utilities/TestConfiguration.js @@ -72,7 +72,6 @@ class TestConfiguration { const user = { userId: "us_test@test.com", email: "test@test.com", - roleId: BUILTIN_ROLE_IDS.BUILDER, builder: { global: true, }, @@ -112,7 +111,7 @@ class TestConfiguration { } catch (err) { // allow errors here } - return this.login(email, PASSWORD) + return this.login(email, PASSWORD, roleId) } 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) { throw "Server has not been opened, cannot login." } @@ -320,16 +319,23 @@ class TestConfiguration { await this.createUser() } const user = { - userId: "us_test@test.com", - email: EMAIL, - roleId: BUILTIN_ROLE_IDS.BASIC, + userId: `us_${email || EMAIL}`, + email: email || EMAIL, } - 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 return { Accept: "application/json", - Cookie: [`${Cookies.Auth}=${token}`], + Cookie: [ + `${Cookies.Auth}=${authToken}`, + `${Cookies.CurrentApp}=${appToken}`, + ], "x-budibase-app-id": this.appId, } }