1
0
Fork 0
mirror of synced 2024-09-10 22:46:09 +12:00

Use multitenancy for tests

This commit is contained in:
Adria Navarro Redo 2023-01-25 17:11:37 +00:00 committed by adrinr
parent 13af7aa730
commit 067462f458
4 changed files with 73 additions and 53 deletions

View file

@ -122,10 +122,11 @@
"@babel/core": "7.17.4", "@babel/core": "7.17.4",
"@babel/preset-env": "7.16.11", "@babel/preset-env": "7.16.11",
"@budibase/standard-components": "^0.9.139", "@budibase/standard-components": "^0.9.139",
"@faker-js/faker": "^7.6.0",
"@jest/test-sequencer": "24.9.0", "@jest/test-sequencer": "24.9.0",
"@trendyol/jest-testcontainers": "^2.1.1",
"@swc/core": "^1.3.25", "@swc/core": "^1.3.25",
"@swc/jest": "^0.2.24", "@swc/jest": "^0.2.24",
"@trendyol/jest-testcontainers": "^2.1.1",
"@types/apidoc": "0.50.0", "@types/apidoc": "0.50.0",
"@types/bson": "4.2.0", "@types/bson": "4.2.0",
"@types/global-agent": "2.1.1", "@types/global-agent": "2.1.1",

View file

@ -3,6 +3,7 @@ import { tmpdir } from "os"
env._set("SELF_HOSTED", "1") env._set("SELF_HOSTED", "1")
env._set("NODE_ENV", "jest") env._set("NODE_ENV", "jest")
env._set("MULTI_TENANCY", "1")
// @ts-ignore // @ts-ignore
env._set("BUDIBASE_DIR", tmpdir("budibase-unittests")) env._set("BUDIBASE_DIR", tmpdir("budibase-unittests"))
env._set("LOG_LEVEL", "silent") env._set("LOG_LEVEL", "silent")

View file

@ -1,3 +1,4 @@
import { faker } from "@faker-js/faker"
import { mocks } from "@budibase/backend-core/tests" import { mocks } from "@budibase/backend-core/tests"
// init the licensing mock // init the licensing mock
@ -40,14 +41,9 @@ import { generateUserMetadataID } from "../../db/utils"
import { startup } from "../../startup" import { startup } from "../../startup"
import { db } from "@budibase/backend-core" import { db } from "@budibase/backend-core"
import Nano from "@budibase/nano" import Nano from "@budibase/nano"
import { AuthToken } from "@budibase/types"
const supertest = require("supertest") const supertest = require("supertest")
const GLOBAL_USER_ID = "us_uuid1"
const EMAIL = "babs@babs.com"
const FIRSTNAME = "Barbara"
const LASTNAME = "Barbington"
const CSRF_TOKEN = "e3727778-7af0-4226-b5eb-f43cbe60a306"
class TestConfiguration { class TestConfiguration {
server: any server: any
request: any request: any
@ -64,6 +60,14 @@ class TestConfiguration {
linkedTable: any linkedTable: any
automation: any automation: any
datasource: any datasource: any
tenantId: string | null
defaultValues: {
globalUserId: string
email: string
firstName: string
lastName: string
csrfToken: string
}
constructor(openServer = true) { constructor(openServer = true) {
if (openServer) { if (openServer) {
@ -78,6 +82,18 @@ class TestConfiguration {
} }
this.appId = null this.appId = null
this.allApps = [] this.allApps = []
this.tenantId = null
this.defaultValues = this.populateDefaultValues()
}
populateDefaultValues() {
return {
globalUserId: faker.datatype.uuid(),
email: faker.internet.email(),
firstName: faker.name.firstName(),
lastName: faker.name.lastName(),
csrfToken: faker.datatype.uuid(),
}
} }
getRequest() { getRequest() {
@ -102,10 +118,10 @@ class TestConfiguration {
getUserDetails() { getUserDetails() {
return { return {
globalId: GLOBAL_USER_ID, globalId: this.defaultValues.globalUserId,
email: EMAIL, email: this.defaultValues.email,
firstName: FIRSTNAME, firstName: this.defaultValues.firstName,
lastName: LASTNAME, lastName: this.defaultValues.lastName,
} }
} }
@ -113,7 +129,9 @@ class TestConfiguration {
if (!appId) { if (!appId) {
appId = this.appId appId = this.appId
} }
return tenancy.doInTenant(TENANT_ID, () => {
const tenant = this.getTenantId()
return tenancy.doInTenant(tenant, () => {
// check if already in a context // check if already in a context
if (context.getAppId() == null && appId !== null) { if (context.getAppId() == null && appId !== null) {
return context.doInAppContext(appId, async () => { return context.doInAppContext(appId, async () => {
@ -129,7 +147,12 @@ class TestConfiguration {
// use a new id as the name to avoid name collisions // use a new id as the name to avoid name collisions
async init(appName = newid()) { async init(appName = newid()) {
await this.cleanAllDbs() this.defaultValues = this.populateDefaultValues()
if (context.isMultiTenant()) {
this.tenantId = `tenant-${newid()}`
context.updateTenantId(this.tenantId)
}
if (!this.started) { if (!this.started) {
await startup() await startup()
} }
@ -140,24 +163,6 @@ class TestConfiguration {
return this.createApp(appName) return this.createApp(appName)
} }
async cleanAllDbs() {
const couchInfo = db.getCouchInfo()
const nano = Nano({
url: couchInfo.url,
requestDefaults: {
headers: {
Authorization: couchInfo.cookie,
},
},
parseUrl: false,
})
let dbs
do {
dbs = await nano.db.list()
await Promise.all(dbs.map(x => nano.db.destroy(x)))
} while (dbs.length)
}
end() { end() {
if (!this) { if (!this) {
return return
@ -180,7 +185,7 @@ class TestConfiguration {
// fake cookies, we don't need them // fake cookies, we don't need them
request.cookies = { set: () => {}, get: () => {} } request.cookies = { set: () => {}, get: () => {} }
request.config = { jwtSecret: env.JWT_SECRET } request.config = { jwtSecret: env.JWT_SECRET }
request.user = { appId, tenantId: TENANT_ID } request.user = { appId, tenantId: this.getTenantId() }
request.query = {} request.query = {}
request.request = { request.request = {
body, body,
@ -196,15 +201,15 @@ class TestConfiguration {
// USER / AUTH // USER / AUTH
async globalUser({ async globalUser({
id = GLOBAL_USER_ID, id = this.defaultValues.globalUserId,
firstName = FIRSTNAME, firstName = this.defaultValues.firstName,
lastName = LASTNAME, lastName = this.defaultValues.lastName,
builder = true, builder = true,
admin = false, admin = false,
email = EMAIL, email = this.defaultValues.email,
roles, roles,
}: any = {}) { }: any = {}) {
return tenancy.doWithGlobalDB(TENANT_ID, async (db: any) => { return tenancy.doWithGlobalDB(this.getTenantId(), async (db: any) => {
let existing let existing
try { try {
existing = await db.get(id) existing = await db.get(id)
@ -215,14 +220,14 @@ class TestConfiguration {
_id: id, _id: id,
...existing, ...existing,
roles: roles || {}, roles: roles || {},
tenantId: TENANT_ID, tenantId: this.getTenantId(),
firstName, firstName,
lastName, lastName,
} }
await sessions.createASession(id, { await sessions.createASession(id, {
sessionId: "sessionid", sessionId: "sessionid",
tenantId: TENANT_ID, tenantId: this.getTenantId(),
csrfToken: CSRF_TOKEN, csrfToken: this.defaultValues.csrfToken,
}) })
if (builder) { if (builder) {
user.builder = { global: true } user.builder = { global: true }
@ -244,9 +249,9 @@ class TestConfiguration {
async createUser( async createUser(
id = null, id = null,
firstName = FIRSTNAME, firstName = this.defaultValues.firstName,
lastName = LASTNAME, lastName = this.defaultValues.lastName,
email = EMAIL, email = this.defaultValues.email,
builder = true, builder = true,
admin = false, admin = false,
roles = {} roles = {}
@ -285,13 +290,13 @@ class TestConfiguration {
} }
await sessions.createASession(userId, { await sessions.createASession(userId, {
sessionId: "sessionid", sessionId: "sessionid",
tenantId: TENANT_ID, tenantId: this.getTenantId(),
}) })
// have to fake this // have to fake this
const authObj = { const authObj = {
userId, userId,
sessionId: "sessionid", sessionId: "sessionid",
tenantId: TENANT_ID, tenantId: this.getTenantId(),
} }
const app = { const app = {
roleId: roleId, roleId: roleId,
@ -314,10 +319,11 @@ class TestConfiguration {
} }
defaultHeaders(extras = {}) { defaultHeaders(extras = {}) {
const authObj = { const tenantId = this.getTenantId()
userId: GLOBAL_USER_ID, const authObj: AuthToken = {
userId: this.defaultValues.globalUserId,
sessionId: "sessionid", sessionId: "sessionid",
tenantId: TENANT_ID, tenantId,
} }
const app = { const app = {
roleId: roles.BUILTIN_ROLE_IDS.ADMIN, roleId: roles.BUILTIN_ROLE_IDS.ADMIN,
@ -331,15 +337,22 @@ class TestConfiguration {
`${constants.Cookie.Auth}=${authToken}`, `${constants.Cookie.Auth}=${authToken}`,
`${constants.Cookie.CurrentApp}=${appToken}`, `${constants.Cookie.CurrentApp}=${appToken}`,
], ],
[constants.Header.CSRF_TOKEN]: CSRF_TOKEN, [constants.Header.CSRF_TOKEN]: this.defaultValues.csrfToken,
...extras, ...extras,
} }
if (this.appId) { if (this.appId) {
headers[constants.Header.APP_ID] = this.appId headers[constants.Header.APP_ID] = this.appId
} }
if (this.tenantId) {
headers[constants.Header.TENANT_ID] = this.tenantId
}
return headers return headers
} }
getTenantId() {
return this.tenantId || TENANT_ID
}
publicHeaders({ prodApp = true } = {}) { publicHeaders({ prodApp = true } = {}) {
const appId = prodApp ? this.prodAppId : this.appId const appId = prodApp ? this.prodAppId : this.appId
@ -353,7 +366,7 @@ class TestConfiguration {
} }
async roleHeaders({ async roleHeaders({
email = EMAIL, email = this.defaultValues.email,
roleId = roles.BUILTIN_ROLE_IDS.ADMIN, roleId = roles.BUILTIN_ROLE_IDS.ADMIN,
builder = false, builder = false,
prodApp = true, prodApp = true,
@ -363,8 +376,8 @@ class TestConfiguration {
// API // API
async generateApiKey(userId = GLOBAL_USER_ID) { async generateApiKey(userId = this.defaultValues.globalUserId) {
return tenancy.doWithGlobalDB(TENANT_ID, async (db: any) => { return tenancy.doWithGlobalDB(this.getTenantId(), async (db: any) => {
const id = dbCore.generateDevInfoID(userId) const id = dbCore.generateDevInfoID(userId)
let devInfo let devInfo
try { try {
@ -373,7 +386,7 @@ class TestConfiguration {
devInfo = { _id: id, userId } devInfo = { _id: id, userId }
} }
devInfo.apiKey = encryption.encrypt( devInfo.apiKey = encryption.encrypt(
`${TENANT_ID}${dbCore.SEPARATOR}${newid()}` `${this.getTenantId()}${dbCore.SEPARATOR}${newid()}`
) )
await db.put(devInfo) await db.put(devInfo)
return devInfo.apiKey return devInfo.apiKey

View file

@ -1527,6 +1527,11 @@
pump "^3.0.0" pump "^3.0.0"
secure-json-parse "^2.1.0" secure-json-parse "^2.1.0"
"@faker-js/faker@^7.6.0":
version "7.6.0"
resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-7.6.0.tgz#9ea331766084288634a9247fcd8b84f16ff4ba07"
integrity sha512-XK6BTq1NDMo9Xqw/YkYyGjSsg44fbNwYRx7QK2CuoQgyy+f1rrTDHoExVM5PsyXCtfl2vs2vVJ0MN0yN6LppRw==
"@google-cloud/firestore@5.0.2": "@google-cloud/firestore@5.0.2":
version "5.0.2" version "5.0.2"
resolved "https://registry.yarnpkg.com/@google-cloud/firestore/-/firestore-5.0.2.tgz#36923fde45987f928a220d347f341c5602f9e340" resolved "https://registry.yarnpkg.com/@google-cloud/firestore/-/firestore-5.0.2.tgz#36923fde45987f928a220d347f341c5602f9e340"