diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 0fb0350367..8377d7f559 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -68,6 +68,7 @@ "@types/semver": "7.3.7", "@types/tar-fs": "2.0.1", "@types/uuid": "8.3.4", + "@types/lodash": "4.14.180", "ioredis-mock": "5.8.0", "jest": "27.5.1", "koa": "2.7.0", @@ -78,4 +79,4 @@ "typescript": "4.7.3" }, "gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc" -} +} \ No newline at end of file diff --git a/packages/backend-core/src/context/index.js b/packages/backend-core/src/context/index.ts similarity index 60% rename from packages/backend-core/src/context/index.js rename to packages/backend-core/src/context/index.ts index a69a381f0f..a38a2e0709 100644 --- a/packages/backend-core/src/context/index.js +++ b/packages/backend-core/src/context/index.ts @@ -1,33 +1,49 @@ -const env = require("../environment") -const { SEPARATOR, DocumentTypes } = require("../db/constants") -const { DEFAULT_TENANT_ID } = require("../constants") -const cls = require("./FunctionContext") -const { dangerousGetDB, closeDB } = require("../db") -const { getProdAppID, getDevelopmentAppID } = require("../db/conversions") -const { baseGlobalDBName } = require("../tenancy/utils") -const { isEqual } = require("lodash") +import env from "../environment" +import { SEPARATOR, DocumentTypes } from "../db/constants" +import cls from "./FunctionContext" +import { dangerousGetDB, closeDB } from "../db" +import { getProdAppID, getDevelopmentAppID } from "../db/conversions" +import { baseGlobalDBName } from "../tenancy/utils" +import { IdentityContext } from "@budibase/types" +import { isEqual } from "lodash" +import { DEFAULT_TENANT_ID as _DEFAULT_TENANT_ID } from "../constants" + +export const DEFAULT_TENANT_ID = _DEFAULT_TENANT_ID // some test cases call functions directly, need to // store an app ID to pretend there is a context -let TEST_APP_ID = null +let TEST_APP_ID: string | null = null -const ContextKeys = { - TENANT_ID: "tenantId", - GLOBAL_DB: "globalDb", - APP_ID: "appId", - IDENTITY: "identity", +enum ContextKeys { + TENANT_ID = "tenantId", + GLOBAL_DB = "globalDb", + APP_ID = "appId", + IDENTITY = "identity", // whatever the request app DB was - CURRENT_DB: "currentDb", + CURRENT_DB = "currentDb", // get the prod app DB from the request - PROD_DB: "prodDb", + PROD_DB = "prodDb", // get the dev app DB from the request - DEV_DB: "devDb", - DB_OPTS: "dbOpts", + DEV_DB = "devDb", + DB_OPTS = "dbOpts", // check if something else is using the context, don't close DB - IN_USE: "inUse", + TENANCY_IN_USE = "tenancyInUse", + APP_IN_USE = "appInUse", + IDENTITY_IN_USE = "identityInUse", } -exports.DEFAULT_TENANT_ID = DEFAULT_TENANT_ID +let openAppCount = 0 +let closeAppCount = 0 +let openTenancyCount = 0 +let closeTenancyCount = 0 + +setInterval(function () { + console.log("openAppCount: " + openAppCount) + console.log("closeAppCount: " + closeAppCount) + console.log("openTenancyCount: " + openTenancyCount) + console.log("closeTenancyCount: " + closeTenancyCount) + console.log("------------------ ") +}, 5000) // this function makes sure the PouchDB objects are closed and // fully deleted when finished - this protects against memory leaks @@ -42,6 +58,7 @@ async function closeAppDBs() { if (!db) { continue } + closeAppCount++ await closeDB(db) // clear the DB from context, incase someone tries to use it again cls.setOnContext(dbKey, null) @@ -55,67 +72,29 @@ async function closeAppDBs() { } } -exports.closeTenancy = async () => { +export const closeTenancy = async () => { + closeTenancyCount++ if (env.USE_COUCH) { - await closeDB(exports.getGlobalDB()) + await closeDB(getGlobalDB()) } // clear from context now that database is closed/task is finished cls.setOnContext(ContextKeys.TENANT_ID, null) cls.setOnContext(ContextKeys.GLOBAL_DB, null) } -exports.isDefaultTenant = () => { - return exports.getTenantId() === exports.DEFAULT_TENANT_ID -} +// export const isDefaultTenant = () => { +// return getTenantId() === DEFAULT_TENANT_ID +// } -exports.isMultiTenant = () => { +export const isMultiTenant = () => { return env.MULTI_TENANCY } -// used for automations, API endpoints should always be in context already -exports.doInTenant = (tenantId, task, { forceNew } = {}) => { - // the internal function is so that we can re-use an existing - // context - don't want to close DB on a parent context - async function internal(opts = { existing: false }) { - // set the tenant id - if (!opts.existing) { - exports.updateTenantId(tenantId) - } - - try { - // invoke the task - return await task() - } finally { - const using = cls.getFromContext(ContextKeys.IN_USE) - if (!using || using <= 1) { - await exports.closeTenancy() - } else { - cls.setOnContext(using - 1) - } - } - } - - const using = cls.getFromContext(ContextKeys.IN_USE) - if ( - !forceNew && - using && - cls.getFromContext(ContextKeys.TENANT_ID) === tenantId - ) { - cls.setOnContext(ContextKeys.IN_USE, using + 1) - return internal({ existing: true }) - } else { - return cls.run(async () => { - cls.setOnContext(ContextKeys.IN_USE, 1) - return internal() - }) - } -} - /** * Given an app ID this will attempt to retrieve the tenant ID from it. * @return {null|string} The tenant ID found within the app ID. */ -exports.getTenantIDFromAppID = appId => { +export const getTenantIDFromAppID = (appId: string) => { if (!appId) { return null } @@ -131,18 +110,54 @@ exports.getTenantIDFromAppID = appId => { } } -const setAppTenantId = appId => { - const appTenantId = - exports.getTenantIDFromAppID(appId) || exports.DEFAULT_TENANT_ID - exports.updateTenantId(appTenantId) +const setAppTenantId = (appId: string) => { + const appTenantId = getTenantIDFromAppID(appId) || DEFAULT_TENANT_ID + updateTenantId(appTenantId) } -exports.doInAppContext = (appId, task, { forceNew } = {}) => { +// used for automations, API endpoints should always be in context already +export const doInTenant = (tenantId: string | null, task: any) => { + // the internal function is so that we can re-use an existing + // context - don't want to close DB on a parent context + async function internal(opts = { existing: false }) { + // set the tenant id + global db if this is a new context + if (!opts.existing) { + updateTenantId(tenantId) + } + + try { + // invoke the task + return await task() + } finally { + const using = cls.getFromContext(ContextKeys.TENANCY_IN_USE) + if (!using || using <= 1) { + await closeTenancy() + } else { + cls.setOnContext(using - 1) + } + } + } + + const using = cls.getFromContext(ContextKeys.TENANCY_IN_USE) + if (using && cls.getFromContext(ContextKeys.TENANT_ID) === tenantId) { + // the tenant id of the current context matches the one we want to use + // don't create a new context, just use the existing one + cls.setOnContext(ContextKeys.TENANCY_IN_USE, using + 1) + return internal({ existing: true }) + } else { + return cls.run(async () => { + cls.setOnContext(ContextKeys.TENANCY_IN_USE, 1) + return internal() + }) + } +} + +export const doInAppContext = (appId: string, task: any) => { if (!appId) { throw new Error("appId is required") } - const identity = exports.getIdentity() + const identity = getIdentity() // the internal function is so that we can re-use an existing // context - don't want to close DB on a parent context @@ -153,33 +168,38 @@ exports.doInAppContext = (appId, task, { forceNew } = {}) => { } // set the app ID cls.setOnContext(ContextKeys.APP_ID, appId) + setAppTenantId(appId) + // preserve the identity - exports.setIdentity(identity) + if (identity) { + setIdentity(identity) + } try { // invoke the task return await task() } finally { - const using = cls.getFromContext(ContextKeys.IN_USE) + const using = cls.getFromContext(ContextKeys.APP_IN_USE) if (!using || using <= 1) { await closeAppDBs() + await closeTenancy() } else { cls.setOnContext(using - 1) } } } - const using = cls.getFromContext(ContextKeys.IN_USE) - if (!forceNew && using && cls.getFromContext(ContextKeys.APP_ID) === appId) { - cls.setOnContext(ContextKeys.IN_USE, using + 1) + const using = cls.getFromContext(ContextKeys.APP_IN_USE) + if (using && cls.getFromContext(ContextKeys.APP_ID) === appId) { + cls.setOnContext(ContextKeys.APP_IN_USE, using + 1) return internal({ existing: true }) } else { return cls.run(async () => { - cls.setOnContext(ContextKeys.IN_USE, 1) + cls.setOnContext(ContextKeys.APP_IN_USE, 1) return internal() }) } } -exports.doInIdentityContext = (identity, task) => { +export const doInIdentityContext = (identity: IdentityContext, task: any) => { if (!identity) { throw new Error("identity is required") } @@ -189,7 +209,7 @@ exports.doInIdentityContext = (identity, task) => { cls.setOnContext(ContextKeys.IDENTITY, identity) // set the tenant so that doInTenant will preserve identity if (identity.tenantId) { - exports.updateTenantId(identity.tenantId) + updateTenantId(identity.tenantId) } } @@ -197,9 +217,10 @@ exports.doInIdentityContext = (identity, task) => { // invoke the task return await task() } finally { - const using = cls.getFromContext(ContextKeys.IN_USE) + const using = cls.getFromContext(ContextKeys.IDENTITY_IN_USE) if (!using || using <= 1) { - exports.setIdentity(null) + setIdentity(null) + await closeTenancy() } else { cls.setOnContext(using - 1) } @@ -207,23 +228,23 @@ exports.doInIdentityContext = (identity, task) => { } const existing = cls.getFromContext(ContextKeys.IDENTITY) - const using = cls.getFromContext(ContextKeys.IN_USE) + const using = cls.getFromContext(ContextKeys.IDENTITY_IN_USE) if (using && existing && existing._id === identity._id) { - cls.setOnContext(ContextKeys.IN_USE, using + 1) + cls.setOnContext(ContextKeys.IDENTITY_IN_USE, using + 1) return internal({ existing: true }) } else { return cls.run(async () => { - cls.setOnContext(ContextKeys.IN_USE, 1) + cls.setOnContext(ContextKeys.IDENTITY_IN_USE, 1) return internal({ existing: false }) }) } } -exports.setIdentity = identity => { +const setIdentity = (identity: IdentityContext | null) => { cls.setOnContext(ContextKeys.IDENTITY, identity) } -exports.getIdentity = () => { +export const getIdentity = (): IdentityContext | undefined => { try { return cls.getFromContext(ContextKeys.IDENTITY) } catch (e) { @@ -231,14 +252,14 @@ exports.getIdentity = () => { } } -exports.updateTenantId = tenantId => { +export const updateTenantId = (tenantId: string | null) => { cls.setOnContext(ContextKeys.TENANT_ID, tenantId) if (env.USE_COUCH) { - exports.setGlobalDB(tenantId) + setGlobalDB(tenantId) } } -exports.updateAppId = async appId => { +export const updateAppId = async (appId: string) => { try { // have to close first, before removing the databases from context await closeAppDBs() @@ -252,14 +273,15 @@ exports.updateAppId = async appId => { } } -exports.setGlobalDB = tenantId => { +export const setGlobalDB = (tenantId: string | null) => { const dbName = baseGlobalDBName(tenantId) + openTenancyCount++ const db = dangerousGetDB(dbName) cls.setOnContext(ContextKeys.GLOBAL_DB, db) return db } -exports.getGlobalDB = () => { +export const getGlobalDB = () => { const db = cls.getFromContext(ContextKeys.GLOBAL_DB) if (!db) { throw new Error("Global DB not found") @@ -267,14 +289,14 @@ exports.getGlobalDB = () => { return db } -exports.isTenantIdSet = () => { +export const isTenantIdSet = () => { const tenantId = cls.getFromContext(ContextKeys.TENANT_ID) return !!tenantId } -exports.getTenantId = () => { - if (!exports.isMultiTenant()) { - return exports.DEFAULT_TENANT_ID +export const getTenantId = () => { + if (!isMultiTenant()) { + return DEFAULT_TENANT_ID } const tenantId = cls.getFromContext(ContextKeys.TENANT_ID) if (!tenantId) { @@ -283,7 +305,7 @@ exports.getTenantId = () => { return tenantId } -exports.getAppId = () => { +export const getAppId = () => { const foundId = cls.getFromContext(ContextKeys.APP_ID) if (!foundId && env.isTest() && TEST_APP_ID) { return TEST_APP_ID @@ -292,7 +314,7 @@ exports.getAppId = () => { } } -function getContextDB(key, opts) { +function getContextDB(key: string, opts: any) { const dbOptsKey = `${key}${ContextKeys.DB_OPTS}` let storedOpts = cls.getFromContext(dbOptsKey) let db = cls.getFromContext(key) @@ -300,7 +322,7 @@ function getContextDB(key, opts) { return db } - const appId = exports.getAppId() + const appId = getAppId() let toUseAppId switch (key) { @@ -314,6 +336,7 @@ function getContextDB(key, opts) { toUseAppId = getDevelopmentAppID(appId) break } + openAppCount++ db = dangerousGetDB(toUseAppId, opts) try { cls.setOnContext(key, db) @@ -332,7 +355,7 @@ function getContextDB(key, opts) { * Opens the app database based on whatever the request * contained, dev or prod. */ -exports.getAppDB = (opts = null) => { +export const getAppDB = (opts?: any) => { return getContextDB(ContextKeys.CURRENT_DB, opts) } @@ -340,7 +363,7 @@ exports.getAppDB = (opts = null) => { * This specifically gets the prod app ID, if the request * contained a development app ID, this will open the prod one. */ -exports.getProdAppDB = (opts = null) => { +export const getProdAppDB = (opts?: any) => { return getContextDB(ContextKeys.PROD_DB, opts) } @@ -348,6 +371,6 @@ exports.getProdAppDB = (opts = null) => { * This specifically gets the dev app ID, if the request * contained a prod app ID, this will open the dev one. */ -exports.getDevAppDB = (opts = null) => { +export const getDevAppDB = (opts?: any) => { return getContextDB(ContextKeys.DEV_DB, opts) } diff --git a/packages/backend-core/src/context/tests/index.spec.ts b/packages/backend-core/src/context/tests/index.spec.ts new file mode 100644 index 0000000000..55ecd333a3 --- /dev/null +++ b/packages/backend-core/src/context/tests/index.spec.ts @@ -0,0 +1,148 @@ +import "../../../tests/utilities/TestConfiguration" +import * as context from ".." +import { DEFAULT_TENANT_ID } from "../../constants" +import env from "../../environment" + +// must use require to spy index file exports due to known issue in jest +const dbUtils = require("../../db") +jest.spyOn(dbUtils, "closeDB") +jest.spyOn(dbUtils, "dangerousGetDB") + +describe("context", () => { + beforeEach(() => { + jest.clearAllMocks() + }) + + describe("doInTenant", () => { + describe("single-tenancy", () => { + it("defaults to the default tenant", () => { + const tenantId = context.getTenantId() + expect(tenantId).toBe(DEFAULT_TENANT_ID) + }) + + it("defaults to the default tenant db", async () => { + await context.doInTenant(DEFAULT_TENANT_ID, () => { + const db = context.getGlobalDB() + expect(db.name).toBe("global-db") + }) + expect(dbUtils.dangerousGetDB).toHaveBeenCalledTimes(1) + expect(dbUtils.closeDB).toHaveBeenCalledTimes(1) + }) + }) + + describe("multi-tenancy", () => { + beforeEach(() => { + env._set("MULTI_TENANCY", 1) + }) + + it("fails when no tenant id is set", () => { + const test = () => { + let error + try { + context.getTenantId() + } catch (e: any) { + error = e + } + expect(error.message).toBe("Tenant id not found") + } + + // test under no tenancy + test() + + // test after tenancy has been accessed to ensure cleanup + context.doInTenant("test", () => {}) + test() + }) + + it("fails when no tenant db is set", () => { + const test = () => { + let error + try { + context.getGlobalDB() + } catch (e: any) { + error = e + } + expect(error.message).toBe("Global DB not found") + } + + // test under no tenancy + test() + + // test after tenancy has been accessed to ensure cleanup + context.doInTenant("test", () => {}) + test() + }) + + it("sets tenant id", () => { + context.doInTenant("test", () => { + const tenantId = context.getTenantId() + expect(tenantId).toBe("test") + }) + }) + + it("initialises the tenant db", async () => { + await context.doInTenant("test", () => { + const db = context.getGlobalDB() + expect(db.name).toBe("test_global-db") + }) + expect(dbUtils.dangerousGetDB).toHaveBeenCalledTimes(1) + expect(dbUtils.closeDB).toHaveBeenCalledTimes(1) + }) + + it("sets the tenant id when nested with same tenant id", async () => { + await context.doInTenant("test", async () => { + const tenantId = context.getTenantId() + expect(tenantId).toBe("test") + + await context.doInTenant("test", async () => { + const tenantId = context.getTenantId() + expect(tenantId).toBe("test") + + await context.doInTenant("test", () => { + const tenantId = context.getTenantId() + expect(tenantId).toBe("test") + }) + }) + }) + }) + + it("initialises the tenant db when nested with same tenant id", async () => { + await context.doInTenant("test", async () => { + const db = context.getGlobalDB() + expect(db.name).toBe("test_global-db") + + await context.doInTenant("test", async () => { + const db = context.getGlobalDB() + expect(db.name).toBe("test_global-db") + + await context.doInTenant("test", () => { + const db = context.getGlobalDB() + expect(db.name).toBe("test_global-db") + }) + }) + }) + + // only 1 db is opened and closed + expect(dbUtils.dangerousGetDB).toHaveBeenCalledTimes(1) + expect(dbUtils.closeDB).toHaveBeenCalledTimes(1) + }) + + it("sets different tenant id inside another context", () => { + context.doInTenant("test", () => { + const tenantId = context.getTenantId() + expect(tenantId).toBe("test") + + context.doInTenant("nested", () => { + const tenantId = context.getTenantId() + expect(tenantId).toBe("nested") + + context.doInTenant("double-nested", () => { + const tenantId = context.getTenantId() + expect(tenantId).toBe("double-nested") + }) + }) + }) + }) + }) + }) +}) diff --git a/packages/backend-core/src/events/processors/PosthogProcessor.ts b/packages/backend-core/src/events/processors/PosthogProcessor.ts index 67407fdd5c..eb12db1dc4 100644 --- a/packages/backend-core/src/events/processors/PosthogProcessor.ts +++ b/packages/backend-core/src/events/processors/PosthogProcessor.ts @@ -2,7 +2,7 @@ import PostHog from "posthog-node" import { Event, Identity, Group, BaseEvent } from "@budibase/types" import { EventProcessor } from "./types" import env from "../../environment" -import context from "../../context" +import * as context from "../../context" const pkg = require("../../../package.json") export default class PosthogProcessor implements EventProcessor { diff --git a/packages/backend-core/src/migrations/migrations.ts b/packages/backend-core/src/migrations/migrations.ts index b926334317..2e4ef0da76 100644 --- a/packages/backend-core/src/migrations/migrations.ts +++ b/packages/backend-core/src/migrations/migrations.ts @@ -9,7 +9,7 @@ import { getGlobalDBName, getTenantId, } from "../tenancy" -import context from "../context" +import * as context from "../context" import { DEFINITIONS } from "." import { Migration, diff --git a/packages/backend-core/yarn.lock b/packages/backend-core/yarn.lock index e40cddc468..4d6e4b2003 100644 --- a/packages/backend-core/yarn.lock +++ b/packages/backend-core/yarn.lock @@ -764,6 +764,11 @@ "@types/koa-compose" "*" "@types/node" "*" +"@types/lodash@4.14.180": + version "4.14.180" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.180.tgz#4ab7c9ddfc92ec4a887886483bc14c79fb380670" + integrity sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g== + "@types/mime@^1": version "1.3.2" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" diff --git a/packages/server/src/api/controllers/application.ts b/packages/server/src/api/controllers/application.ts index 9736ebaba5..fa2d2d00ab 100644 --- a/packages/server/src/api/controllers/application.ts +++ b/packages/server/src/api/controllers/application.ts @@ -45,11 +45,7 @@ const { getTenantId, isMultiTenant } = require("@budibase/backend-core/tenancy") import { syncGlobalUsers } from "./user" const { app: appCache } = require("@budibase/backend-core/cache") import { cleanupAutomations } from "../../automations/utils" -const { - getAppDB, - getProdAppDB, - updateAppId, -} = require("@budibase/backend-core/context") +import { context } from "@budibase/backend-core" import { getUniqueRows } from "../../utilities/usageQuota/rows" import { quotas } from "@budibase/pro" import { errors, events, migrations } from "@budibase/backend-core" @@ -59,7 +55,7 @@ const URL_REGEX_SLASH = /\/|\\/g // utility function, need to do away with this async function getLayouts() { - const db = getAppDB() + const db = context.getAppDB() return ( await db.allDocs( getLayoutParams(null, { @@ -70,7 +66,7 @@ async function getLayouts() { } async function getScreens() { - const db = getAppDB() + const db = context.getAppDB() return ( await db.allDocs( getScreenParams(null, { @@ -133,9 +129,9 @@ async function createInstance(template: any) { const tenantId = isMultiTenant() ? getTenantId() : null const baseAppId = generateAppID(tenantId) const appId = generateDevAppID(baseAppId) - await updateAppId(appId) + await context.updateAppId(appId) - const db = getAppDB() + const db = context.getAppDB() await db.put({ _id: "_design/database", // view collation information, read before writing any complex views: @@ -211,7 +207,7 @@ export const fetchAppDefinition = async (ctx: any) => { } export const fetchAppPackage = async (ctx: any) => { - const db = getAppDB() + const db = context.getAppDB() const application = await db.get(DocumentTypes.APP_METADATA) const layouts = await getLayouts() let screens = await getScreens() @@ -254,7 +250,7 @@ const performAppCreate = async (ctx: any) => { const instance = await createInstance(instanceConfig) const appId = instance._id - const db = getAppDB() + const db = context.getAppDB() let _rev try { // if template there will be an existing doc @@ -382,7 +378,7 @@ export const update = async (ctx: any) => { export const updateClient = async (ctx: any) => { // Get current app version - const db = getAppDB() + const db = context.getAppDB() const application = await db.get(DocumentTypes.APP_METADATA) const currentVersion = application.version @@ -406,7 +402,7 @@ export const updateClient = async (ctx: any) => { export const revertClient = async (ctx: any) => { // Check app can be reverted - const db = getAppDB() + const db = context.getAppDB() const application = await db.get(DocumentTypes.APP_METADATA) if (!application.revertableVersion) { ctx.throw(400, "There is no version to revert to") @@ -438,7 +434,7 @@ const destroyApp = async (ctx: any) => { appId = getProdAppID(appId) } - const db = isUnpublish ? getProdAppDB() : getAppDB() + const db = isUnpublish ? context.getProdAppDB() : context.getAppDB() const app = await db.get(DocumentTypes.APP_METADATA) const result = await db.destroy() @@ -506,7 +502,7 @@ export const sync = async (ctx: any, next: any) => { try { // specific case, want to make sure setup is skipped - const prodDb = getProdAppDB({ skip_setup: true }) + const prodDb = context.getProdAppDB({ skip_setup: true }) const info = await prodDb.info() if (info.error) throw info.error } catch (err) { @@ -548,7 +544,7 @@ export const sync = async (ctx: any, next: any) => { } const updateAppPackage = async (appPackage: any, appId: any) => { - const db = getAppDB() + const db = context.getAppDB() const application = await db.get(DocumentTypes.APP_METADATA) const newAppPackage = { ...application, ...appPackage } @@ -567,7 +563,7 @@ const updateAppPackage = async (appPackage: any, appId: any) => { } const createEmptyAppPackage = async (ctx: any, app: any) => { - const db = getAppDB() + const db = context.getAppDB() let screensAndLayouts = [] for (let layout of BASE_LAYOUTS) { diff --git a/packages/server/src/tests/utilities/TestConfiguration.js b/packages/server/src/tests/utilities/TestConfiguration.js index fc4d302c63..298bdd247d 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.js +++ b/packages/server/src/tests/utilities/TestConfiguration.js @@ -95,21 +95,31 @@ class TestConfiguration { // UTILS - async _req(config, params, controlFunc) { + async _req(body, params, controlFunc, opts = { prodApp: false }) { + // create a fake request ctx const request = {} + + // set the app id + let appId + if (opts.prodApp) { + appId = this.prodAppId + } else { + appId = this.appId + } + request.appId = appId + // fake cookies, we don't need them request.cookies = { set: () => {}, get: () => {} } request.config = { jwtSecret: env.JWT_SECRET } - request.appId = this.appId - request.user = { appId: this.appId, tenantId: TENANT_ID } + request.user = { appId, tenantId: TENANT_ID } request.query = {} request.request = { - body: config, + body, } - return this.doInContext(this.appId, async () => { - if (params) { - request.params = params - } + if (params) { + request.params = params + } + return this.doInContext(appId, async () => { await controlFunc(request) return request.body }) @@ -304,7 +314,6 @@ class TestConfiguration { // create production app this.prodApp = await this.deploy() - this.prodAppId = this.prodApp.appId this.allApps.push(this.prodApp) this.allApps.push(this.app) @@ -315,11 +324,13 @@ class TestConfiguration { async deploy() { await this._req(null, null, controllers.deploy.deployApp) const prodAppId = this.getAppId().replace("_dev", "") + this.prodAppId = prodAppId return context.doInAppContext(prodAppId, async () => { const appPackage = await this._req( null, { appId: prodAppId }, - controllers.app.fetchAppPackage + controllers.app.fetchAppPackage, + { prodApp: true } ) return appPackage.application }) diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index f6816aa880..5e1653ea41 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1028,10 +1028,10 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@1.0.216": - version "1.0.216" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.0.216.tgz#f97caefffcc5b5bfa23740178b3f7efc945ef226" - integrity sha512-mGbevDtnyCJu/M1U3mnu8Ynxx0hMAlZg1RUX71eizvENuBRWFA7mEXlN0ay1uC0xiROllJCWI0zucYXkTxuu0w== +"@budibase/backend-core@1.0.218": + version "1.0.218" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.0.218.tgz#be101c8baf220fa3fc55d63071bb38fc6c8cf4d8" + integrity sha512-v9+bvQ2+OsK7eGyDHzMuPawTu2LovRCsuArFeMnaG/AbexkqnbB74w+h3vh/2npuHzrnk8RZkM2c4pp/ycqfKw== dependencies: "@techpass/passport-openidconnect" "0.3.2" aws-sdk "2.1030.0" @@ -1109,12 +1109,12 @@ svelte-flatpickr "^3.2.3" svelte-portal "^1.0.0" -"@budibase/pro@1.0.216": - version "1.0.216" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.0.216.tgz#bf4b2851d8bff3ada05deb0ec3e2ae3eadf998a2" - integrity sha512-YL9fpZCMBrwpJEk86slwegGEtrX2isW77E2A0Z9ZPKQehghdEBcOp2HIZJPhKXmo0TePbW8SHblC8LnrSbaMdg== +"@budibase/pro@1.0.218": + version "1.0.218" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.0.218.tgz#b9e5bb95cca996dc1f7f783a3a02e51cbbf3df55" + integrity sha512-LJpV4rYPP9DzMNkL2Y0euZplkubBKBE+gc5JBTMt1l9Fwn2Sri/Y5bQ+U8fjczjmHxYnZLrFwH+o6LCnk/QJow== dependencies: - "@budibase/backend-core" "1.0.216" + "@budibase/backend-core" "1.0.218" node-fetch "^2.6.1" "@budibase/standard-components@^0.9.139": diff --git a/packages/types/src/sdk/context.ts b/packages/types/src/sdk/context.ts index 0500b31faa..940ac5a0c3 100644 --- a/packages/types/src/sdk/context.ts +++ b/packages/types/src/sdk/context.ts @@ -4,6 +4,7 @@ import { IdentityType } from "./events/identification" export interface BaseContext { _id: string type: IdentityType + tenantId?: string } export interface AccountUserContext extends BaseContext { @@ -13,6 +14,7 @@ export interface AccountUserContext extends BaseContext { export interface UserContext extends BaseContext, User { _id: string + tenantId: string account?: Account } diff --git a/packages/worker/package.json b/packages/worker/package.json index 0f3651beb5..d5a210c783 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -17,6 +17,7 @@ "postbuild": "copyfiles -u 1 src/**/*.hbs dist/", "build:dev": "yarn prebuild && tsc --build --watch --preserveWatchOutput", "run:docker": "node dist/index.js", + "debug": "yarn build && node --expose-gc --inspect=9223 dist/index.js", "run:docker:cluster": "pm2-runtime start pm2.config.js", "build:docker": "docker build . -t worker-service --label version=$BUDIBASE_RELEASE_VERSION", "dev:stack:init": "node ./scripts/dev/manage.js init", @@ -101,4 +102,4 @@ ] }, "gitHead": "d1836a898cab3f8ab80ee6d8f42be1a9eed7dcdc" -} +} \ No newline at end of file diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 5c14652012..3fdd861c30 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -291,10 +291,10 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@1.0.216": - version "1.0.216" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.0.216.tgz#f97caefffcc5b5bfa23740178b3f7efc945ef226" - integrity sha512-mGbevDtnyCJu/M1U3mnu8Ynxx0hMAlZg1RUX71eizvENuBRWFA7mEXlN0ay1uC0xiROllJCWI0zucYXkTxuu0w== +"@budibase/backend-core@1.0.218": + version "1.0.218" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-1.0.218.tgz#be101c8baf220fa3fc55d63071bb38fc6c8cf4d8" + integrity sha512-v9+bvQ2+OsK7eGyDHzMuPawTu2LovRCsuArFeMnaG/AbexkqnbB74w+h3vh/2npuHzrnk8RZkM2c4pp/ycqfKw== dependencies: "@techpass/passport-openidconnect" "0.3.2" aws-sdk "2.1030.0" @@ -322,12 +322,12 @@ uuid "8.3.2" zlib "1.0.5" -"@budibase/pro@1.0.216": - version "1.0.216" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.0.216.tgz#bf4b2851d8bff3ada05deb0ec3e2ae3eadf998a2" - integrity sha512-YL9fpZCMBrwpJEk86slwegGEtrX2isW77E2A0Z9ZPKQehghdEBcOp2HIZJPhKXmo0TePbW8SHblC8LnrSbaMdg== +"@budibase/pro@1.0.218": + version "1.0.218" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-1.0.218.tgz#b9e5bb95cca996dc1f7f783a3a02e51cbbf3df55" + integrity sha512-LJpV4rYPP9DzMNkL2Y0euZplkubBKBE+gc5JBTMt1l9Fwn2Sri/Y5bQ+U8fjczjmHxYnZLrFwH+o6LCnk/QJow== dependencies: - "@budibase/backend-core" "1.0.216" + "@budibase/backend-core" "1.0.218" node-fetch "^2.6.1" "@cspotcode/source-map-consumer@0.8.0":