From d5f8cc1023de5315e473958ecd8962451ef2dd1a Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 28 Jan 2022 15:43:51 +0000 Subject: [PATCH] Tests updating, all now passing, fixed some issues discovered by them. --- packages/backend-core/src/tenancy/context.js | 4 + .../query/import/tests/index.spec.js | 1 + .../server/src/api/controllers/routing.js | 2 +- .../src/api/routes/tests/automation.spec.js | 1 + .../src/api/routes/tests/routing.spec.js | 33 +++-- .../routes/tests/utilities/TestFunctions.js | 52 +++++--- packages/server/src/environment.js | 3 +- packages/server/src/middleware/currentapp.js | 95 +++++++------- .../src/middleware/tests/authorized.spec.js | 9 +- .../src/middleware/tests/currentapp.spec.js | 6 + .../src/tests/utilities/TestConfiguration.js | 116 ++++++++++-------- packages/server/src/utilities/global.js | 2 +- 12 files changed, 195 insertions(+), 129 deletions(-) diff --git a/packages/backend-core/src/tenancy/context.js b/packages/backend-core/src/tenancy/context.js index d54622f979..3d2c862d71 100644 --- a/packages/backend-core/src/tenancy/context.js +++ b/packages/backend-core/src/tenancy/context.js @@ -59,6 +59,10 @@ exports.updateTenantId = tenantId => { exports.updateAppId = appId => { try { cls.setOnContext(ContextKeys.APP_ID, appId) + cls.setOnContext(ContextKeys.PROD_DB, null) + cls.setOnContext(ContextKeys.DEV_DB, null) + cls.setOnContext(ContextKeys.CURRENT_DB, null) + cls.setOnContext(ContextKeys.DB_OPTS, null) } catch (err) { if (env.isTest()) { TEST_APP_ID = appId diff --git a/packages/server/src/api/controllers/query/import/tests/index.spec.js b/packages/server/src/api/controllers/query/import/tests/index.spec.js index 36227a4c55..8d074ea885 100644 --- a/packages/server/src/api/controllers/query/import/tests/index.spec.js +++ b/packages/server/src/api/controllers/query/import/tests/index.spec.js @@ -6,6 +6,7 @@ const db = jest.fn(() => { } }) jest.mock("../../../../../db", () => db) +require("@budibase/backend-core").init(require("../../../../../db")) const { RestImporter } = require("../index") diff --git a/packages/server/src/api/controllers/routing.js b/packages/server/src/api/controllers/routing.js index ca4dea2738..d6ba9d6ac2 100644 --- a/packages/server/src/api/controllers/routing.js +++ b/packages/server/src/api/controllers/routing.js @@ -60,7 +60,7 @@ exports.fetch = async ctx => { } exports.clientFetch = async ctx => { - const routing = await getRoutingStructure(ctx.appId) + const routing = await getRoutingStructure() let roleId = ctx.user.role._id const roleIds = await getUserRoleHierarchy(roleId) for (let topLevel of Object.values(routing.routes)) { diff --git a/packages/server/src/api/routes/tests/automation.spec.js b/packages/server/src/api/routes/tests/automation.spec.js index c412c34fdc..3e5725bb95 100644 --- a/packages/server/src/api/routes/tests/automation.spec.js +++ b/packages/server/src/api/routes/tests/automation.spec.js @@ -145,6 +145,7 @@ describe("/automations", () => { let table = await config.createTable() automation.definition.trigger.inputs.tableId = table._id automation.definition.steps[0].inputs.row.tableId = table._id + automation.appId = config.appId automation = await config.createAutomation(automation) await setup.delay(500) const res = await testAutomation(config, automation) diff --git a/packages/server/src/api/routes/tests/routing.spec.js b/packages/server/src/api/routes/tests/routing.spec.js index fdc414448c..d6d05c3322 100644 --- a/packages/server/src/api/routes/tests/routing.spec.js +++ b/packages/server/src/api/routes/tests/routing.spec.js @@ -1,10 +1,15 @@ const setup = require("./utilities") const { basicScreen } = setup.structures -const { checkBuilderEndpoint } = require("./utilities/TestFunctions") +const { checkBuilderEndpoint, runInProd } = require("./utilities/TestFunctions") const { BUILTIN_ROLE_IDS } = require("@budibase/backend-core/roles") +const { doInAppContext } = require("@budibase/backend-core/context") const route = "/test" +// there are checks which are disabled in test env, +// these checks need to be enabled for this test + + describe("/routing", () => { let request = setup.getRequest() let config = setup.getConfig() @@ -26,20 +31,24 @@ describe("/routing", () => { describe("fetch", () => { it("prevents a public user from accessing development app", async () => { - await request - .get(`/api/routing/client`) - .set(config.publicHeaders({ prodApp: false })) - .expect(302) + await runInProd(() => { + return request + .get(`/api/routing/client`) + .set(config.publicHeaders({ prodApp: false })) + .expect(302) + }) }) it("prevents a non builder from accessing development app", async () => { - await request - .get(`/api/routing/client`) - .set(await config.roleHeaders({ - roleId: BUILTIN_ROLE_IDS.BASIC, - prodApp: false - })) - .expect(302) + await runInProd(async () => { + return request + .get(`/api/routing/client`) + .set(await config.roleHeaders({ + roleId: BUILTIN_ROLE_IDS.BASIC, + prodApp: false + })) + .expect(302) + }) }) it("returns the correct routing for basic user", async () => { const res = await request diff --git a/packages/server/src/api/routes/tests/utilities/TestFunctions.js b/packages/server/src/api/routes/tests/utilities/TestFunctions.js index e9e15b7619..c752507d25 100644 --- a/packages/server/src/api/routes/tests/utilities/TestFunctions.js +++ b/packages/server/src/api/routes/tests/utilities/TestFunctions.js @@ -3,7 +3,8 @@ const appController = require("../../../controllers/application") const { AppStatus } = require("../../../../db/utils") const { BUILTIN_ROLE_IDS } = require("@budibase/backend-core/roles") const { TENANT_ID } = require("../../../../tests/utilities/structures") -const { getAppDB } = require("@budibase/backend-core/context") +const { getAppDB, doInAppContext } = require("@budibase/backend-core/context") +const env = require("../../../../environment") function Request(appId, params) { this.appId = appId @@ -11,9 +12,15 @@ function Request(appId, params) { this.request = {} } +function runRequest(appId, controlFunc, request) { + return doInAppContext(appId, async () => { + return controlFunc(request) + }) +} + exports.getAllTableRows = async config => { const req = new Request(config.appId, { tableId: config.table._id }) - await rowController.fetch(req) + await runRequest(config.appId, rowController.fetch, req) return req.body } @@ -26,14 +33,17 @@ exports.clearAllApps = async (tenantId = TENANT_ID) => { } for (let app of apps) { const { appId } = app - await appController.delete(new Request(null, { appId })) + const req = new Request(null, { appId }) + await runRequest(appId, appController.delete, req) } } exports.clearAllAutomations = async config => { const automations = await config.getAllAutomations() for (let auto of automations) { - await config.deleteAutomation(auto) + await doInAppContext(config.appId, async () => { + await config.deleteAutomation(auto) + }) } } @@ -101,15 +111,27 @@ exports.getDB = () => { } exports.testAutomation = async (config, automation) => { - return await config.request - .post(`/api/automations/${automation._id}/test`) - .send({ - row: { - name: "Test", - description: "TEST", - }, - }) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + return runRequest(automation.appId, async () => { + return await config.request + .post(`/api/automations/${automation._id}/test`) + .send({ + row: { + name: "Test", + description: "TEST", + }, + }) + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(200) + }) +} + +exports.runInProd = async func => { + const nodeEnv = env.NODE_ENV + const workerId = env.JEST_WORKER_ID + env._set("NODE_ENV", "PRODUCTION") + env._set("JEST_WORKER_ID", null) + await func() + env._set("NODE_ENV", nodeEnv) + env._set("JEST_WORKER_ID", workerId) } diff --git a/packages/server/src/environment.js b/packages/server/src/environment.js index 614f41a29f..05edb0a95e 100644 --- a/packages/server/src/environment.js +++ b/packages/server/src/environment.js @@ -2,7 +2,8 @@ function isTest() { return ( process.env.NODE_ENV === "jest" || process.env.NODE_ENV === "cypress" || - process.env.JEST_WORKER_ID != null + (process.env.JEST_WORKER_ID != null && + process.env.JEST_WORKER_ID !== "null") ) } diff --git a/packages/server/src/middleware/currentapp.js b/packages/server/src/middleware/currentapp.js index 43f5ed9d46..70dd1bf578 100644 --- a/packages/server/src/middleware/currentapp.js +++ b/packages/server/src/middleware/currentapp.js @@ -13,6 +13,7 @@ const { isUserInAppTenant } = require("@budibase/backend-core/tenancy") const { getCachedSelf } = require("../utilities/global") const env = require("../environment") const { isWebhookEndpoint } = require("./utils") +const { doInAppContext } = require("@budibase/backend-core/context") module.exports = async (ctx, next) => { // try to get the appID from the request @@ -40,13 +41,15 @@ module.exports = async (ctx, next) => { } // deny access to application preview - if ( - isDevAppID(requestAppId) && - !isWebhookEndpoint(ctx) && - (!ctx.user || !ctx.user.builder || !ctx.user.builder.global) - ) { - clearCookie(ctx, Cookies.CurrentApp) - return ctx.redirect("/") + if (!env.isTest()) { + if ( + isDevAppID(requestAppId) && + !isWebhookEndpoint(ctx) && + (!ctx.user || !ctx.user.builder || !ctx.user.builder.global) + ) { + clearCookie(ctx, Cookies.CurrentApp) + return ctx.redirect("/") + } } let appId, @@ -67,44 +70,46 @@ module.exports = async (ctx, next) => { return next() } - let noCookieSet = false - // if the user not in the right tenant then make sure they have no permissions - // need to judge this only based on the request app ID, - if ( - env.MULTI_TENANCY && - ctx.user && - requestAppId && - !isUserInAppTenant(requestAppId) - ) { - // don't error, simply remove the users rights (they are a public user) - delete ctx.user.builder - delete ctx.user.admin - delete ctx.user.roles - roleId = BUILTIN_ROLE_IDS.PUBLIC - noCookieSet = true - } - - ctx.appId = appId - if (roleId) { - ctx.roleId = roleId - const userId = ctx.user ? generateUserMetadataID(ctx.user._id) : null - ctx.user = { - ...ctx.user, - // override userID with metadata one - _id: userId, - userId, - roleId, - role: await getRole(appId, roleId), + return doInAppContext(appId, async () => { + let noCookieSet = false + // if the user not in the right tenant then make sure they have no permissions + // need to judge this only based on the request app ID, + if ( + env.MULTI_TENANCY && + ctx.user && + requestAppId && + !isUserInAppTenant(requestAppId) + ) { + // don't error, simply remove the users rights (they are a public user) + delete ctx.user.builder + delete ctx.user.admin + delete ctx.user.roles + roleId = BUILTIN_ROLE_IDS.PUBLIC + noCookieSet = true } - } - if ( - (requestAppId !== appId || - appCookie == null || - appCookie.appId !== requestAppId) && - !noCookieSet - ) { - setCookie(ctx, { appId }, Cookies.CurrentApp) - } - return next() + ctx.appId = appId + if (roleId) { + ctx.roleId = roleId + const userId = ctx.user ? generateUserMetadataID(ctx.user._id) : null + ctx.user = { + ...ctx.user, + // override userID with metadata one + _id: userId, + userId, + roleId, + role: await getRole(roleId), + } + } + if ( + (requestAppId !== appId || + appCookie == null || + appCookie.appId !== requestAppId) && + !noCookieSet + ) { + setCookie(ctx, { appId }, Cookies.CurrentApp) + } + + return next() + }) } diff --git a/packages/server/src/middleware/tests/authorized.spec.js b/packages/server/src/middleware/tests/authorized.spec.js index 9775965b5a..205d0b8d2c 100644 --- a/packages/server/src/middleware/tests/authorized.spec.js +++ b/packages/server/src/middleware/tests/authorized.spec.js @@ -11,6 +11,9 @@ const authorizedMiddleware = require("../authorized") const env = require("../../environment") const { PermissionTypes, PermissionLevels } = require("@budibase/backend-core/permissions") require("@budibase/backend-core").init(require("../../db")) +const { doInAppContext } = require("@budibase/backend-core/context") + +const APP_ID = "" class TestConfiguration { constructor(role) { @@ -22,7 +25,7 @@ class TestConfiguration { request: { url: "" }, - appId: "", + appId: APP_ID, auth: {}, next: this.next, throw: this.throw @@ -30,7 +33,9 @@ class TestConfiguration { } executeMiddleware() { - return this.middleware(this.ctx, this.next) + return doInAppContext(APP_ID, () => { + return this.middleware(this.ctx, this.next) + }) } setUser(user) { diff --git a/packages/server/src/middleware/tests/currentapp.spec.js b/packages/server/src/middleware/tests/currentapp.spec.js index 27c88f3b48..4e53a6a4c0 100644 --- a/packages/server/src/middleware/tests/currentapp.spec.js +++ b/packages/server/src/middleware/tests/currentapp.spec.js @@ -1,6 +1,11 @@ mockAuthWithNoCookie() mockWorker() +jest.mock("@budibase/backend-core/db", () => ({ + ...jest.requireActual("@budibase/backend-core/db"), + dbExists: () => true, +})) + function mockWorker() { jest.mock("../../utilities/workerRequests", () => ({ getGlobalSelf: () => { @@ -50,6 +55,7 @@ function mockAuthWithCookie() { return "app_test" }, setCookie: jest.fn(), + clearCookie: jest.fn(), getCookie: () => ({appId: "app_different", roleId: "PUBLIC"}), })) jest.mock("@budibase/backend-core/constants", () => ({ diff --git a/packages/server/src/tests/utilities/TestConfiguration.js b/packages/server/src/tests/utilities/TestConfiguration.js index 48c8a88410..f08067ea2e 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.js +++ b/packages/server/src/tests/utilities/TestConfiguration.js @@ -1,3 +1,6 @@ +const core = require("@budibase/backend-core") +const CouchDB = require("../../db") +core.init(CouchDB) const { BUILTIN_ROLE_IDS } = require("@budibase/backend-core/roles") const env = require("../../environment") const { @@ -17,14 +20,11 @@ const supertest = require("supertest") const { cleanup } = require("../../utilities/fileSystem") const { Cookies, Headers } = require("@budibase/backend-core/constants") const { jwt } = require("@budibase/backend-core/auth") -const core = require("@budibase/backend-core") const { getGlobalDB } = require("@budibase/backend-core/tenancy") const { createASession } = require("@budibase/backend-core/sessions") const { user: userCache } = require("@budibase/backend-core/cache") -const CouchDB = require("../../db") const newid = require("../../db/newid") const context = require("@budibase/backend-core/context") -core.init(CouchDB) const GLOBAL_USER_ID = "us_uuid1" const EMAIL = "babs@babs.com" @@ -51,7 +51,6 @@ class TestConfiguration { } async _req(config, params, controlFunc) { - context.updateAppId(this.appId) const request = {} // fake cookies, we don't need them request.cookies = { set: () => {}, get: () => {} } @@ -62,11 +61,21 @@ class TestConfiguration { request.request = { body: config, } - if (params) { - request.params = params + async function run() { + if (params) { + request.params = params + } + await controlFunc(request) + return request.body + } + // check if already in a context + if (context.getAppId() == null) { + return context.doInAppContext(this.appId, async () => { + return run() + }) + } else { + return run() } - await controlFunc(request) - return request.body } async globalUser({ @@ -182,12 +191,14 @@ class TestConfiguration { async deploy() { await this._req(null, null, controllers.deploy.deployApp) const prodAppId = this.getAppId().replace("_dev", "") - const appPackage = await this._req( - null, - { appId: prodAppId }, - controllers.app.fetchAppPackage - ) - return appPackage.application + return context.doInAppContext(prodAppId, async () => { + const appPackage = await this._req( + null, + { appId: prodAppId }, + controllers.app.fetchAppPackage + ) + return appPackage.application + }) } async updateTable(config = null) { @@ -416,46 +427,47 @@ class TestConfiguration { async login({ roleId, userId, builder, prodApp = false } = {}) { const appId = prodApp ? this.prodAppId : this.appId - - userId = !userId ? `us_uuid1` : userId - if (!this.request) { - throw "Server has not been opened, cannot login." - } - // make sure the user exists in the global DB - if (roleId !== BUILTIN_ROLE_IDS.PUBLIC) { - await this.globalUser({ - userId, - builder, - roles: { [this.prodAppId]: roleId }, + return context.doInAppContext(appId, async () => { + userId = !userId ? `us_uuid1` : userId + if (!this.request) { + throw "Server has not been opened, cannot login." + } + // make sure the user exists in the global DB + if (roleId !== BUILTIN_ROLE_IDS.PUBLIC) { + await this.globalUser({ + id: userId, + builder, + roles: { [this.prodAppId]: roleId }, + }) + } + await createASession(userId, { + sessionId: "sessionid", + tenantId: TENANT_ID, }) - } - await createASession(userId, { - sessionId: "sessionid", - tenantId: TENANT_ID, - }) - // have to fake this - const auth = { - userId, - sessionId: "sessionid", - tenantId: TENANT_ID, - } - const app = { - roleId: roleId, - appId, - } - const authToken = jwt.sign(auth, env.JWT_SECRET) - const appToken = jwt.sign(app, env.JWT_SECRET) + // have to fake this + const auth = { + userId, + sessionId: "sessionid", + tenantId: TENANT_ID, + } + const app = { + roleId: roleId, + appId, + } + const authToken = jwt.sign(auth, env.JWT_SECRET) + const appToken = jwt.sign(app, env.JWT_SECRET) - // returning necessary request headers - await userCache.invalidateUser(userId) - return { - Accept: "application/json", - Cookie: [ - `${Cookies.Auth}=${authToken}`, - `${Cookies.CurrentApp}=${appToken}`, - ], - [Headers.APP_ID]: appId, - } + // returning necessary request headers + await userCache.invalidateUser(userId) + return { + Accept: "application/json", + Cookie: [ + `${Cookies.Auth}=${authToken}`, + `${Cookies.CurrentApp}=${appToken}`, + ], + [Headers.APP_ID]: appId, + } + }) } } diff --git a/packages/server/src/utilities/global.js b/packages/server/src/utilities/global.js index 959eb59932..317d80689a 100644 --- a/packages/server/src/utilities/global.js +++ b/packages/server/src/utilities/global.js @@ -48,7 +48,7 @@ exports.getCachedSelf = async (ctx, appId) => { // this has to be tenant aware, can't depend on the context to find it out // running some middlewares before the tenancy causes context to break const user = await userCache.getUser(ctx.user._id) - return processUser(user, appId) + return processUser(user, { appId }) } exports.getRawGlobalUser = async userId => {