Use multitenancy for tests
This commit is contained in:
parent
13af7aa730
commit
067462f458
4 changed files with 73 additions and 53 deletions
|
@ -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",
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in a new issue