Server flaky tests fixes - improving tenancy config
This commit is contained in:
parent
2d993adec8
commit
4e1bebe897
|
@ -10,7 +10,6 @@ import {
|
||||||
isCloudAccount,
|
isCloudAccount,
|
||||||
isSSOAccount,
|
isSSOAccount,
|
||||||
TenantGroup,
|
TenantGroup,
|
||||||
SettingsConfig,
|
|
||||||
CloudAccount,
|
CloudAccount,
|
||||||
UserIdentity,
|
UserIdentity,
|
||||||
InstallationGroup,
|
InstallationGroup,
|
||||||
|
|
|
@ -58,7 +58,7 @@ export async function exportApps(ctx: Ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkHasBeenImported() {
|
async function checkHasBeenImported() {
|
||||||
if (!env.SELF_HOSTED || env.MULTI_TENANCY) {
|
if (!env.SELF_HOSTED) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
const apps = await dbCore.getAllApps({ all: true })
|
const apps = await dbCore.getAllApps({ all: true })
|
||||||
|
@ -72,7 +72,7 @@ export async function hasBeenImported(ctx: Ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function importApps(ctx: Ctx) {
|
export async function importApps(ctx: Ctx) {
|
||||||
if (!env.SELF_HOSTED || env.MULTI_TENANCY) {
|
if (!env.SELF_HOSTED) {
|
||||||
ctx.throw(400, "Importing only allowed in self hosted environments.")
|
ctx.throw(400, "Importing only allowed in self hosted environments.")
|
||||||
}
|
}
|
||||||
const beenImported = await checkHasBeenImported()
|
const beenImported = await checkHasBeenImported()
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { App } from "@budibase/types"
|
||||||
|
|
||||||
jest.setTimeout(30000)
|
jest.setTimeout(30000)
|
||||||
|
|
||||||
import { AppStatus } from "../../../db/utils"
|
import { AppStatus } from "../../../db/utils"
|
||||||
|
@ -5,6 +7,7 @@ import { AppStatus } from "../../../db/utils"
|
||||||
import * as setup from "./utilities"
|
import * as setup from "./utilities"
|
||||||
|
|
||||||
import { wipeDb } from "./utilities/TestFunctions"
|
import { wipeDb } from "./utilities/TestFunctions"
|
||||||
|
import { tenancy } from "@budibase/backend-core"
|
||||||
|
|
||||||
describe("/cloud", () => {
|
describe("/cloud", () => {
|
||||||
let request = setup.getRequest()!
|
let request = setup.getRequest()!
|
||||||
|
@ -12,18 +15,10 @@ describe("/cloud", () => {
|
||||||
|
|
||||||
afterAll(setup.afterAll)
|
afterAll(setup.afterAll)
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(async () => {
|
||||||
// Importing is only allowed in self hosted environments
|
// Importing is only allowed in self hosted environments
|
||||||
config.modeSelf()
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await config.init()
|
await config.init()
|
||||||
})
|
config.modeSelf()
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
// clear all mocks
|
|
||||||
jest.clearAllMocks()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("import", () => {
|
describe("import", () => {
|
||||||
|
@ -32,30 +27,28 @@ describe("/cloud", () => {
|
||||||
// import will not run
|
// import will not run
|
||||||
await wipeDb()
|
await wipeDb()
|
||||||
|
|
||||||
// get a count of apps before the import
|
|
||||||
const preImportApps = await request
|
|
||||||
.get(`/api/applications?status=${AppStatus.ALL}`)
|
|
||||||
.set(config.defaultHeaders())
|
|
||||||
.expect("Content-Type", /json/)
|
|
||||||
.expect(200)
|
|
||||||
|
|
||||||
// Perform the import
|
// Perform the import
|
||||||
const res = await request
|
const res = await request
|
||||||
.post(`/api/cloud/import`)
|
.post(`/api/cloud/import`)
|
||||||
|
.set(config.publicHeaders())
|
||||||
.attach("importFile", "src/api/routes/tests/data/export-test.tar.gz")
|
.attach("importFile", "src/api/routes/tests/data/export-test.tar.gz")
|
||||||
.set(config.defaultHeaders())
|
|
||||||
.expect(200)
|
.expect(200)
|
||||||
expect(res.body.message).toEqual("Apps successfully imported.")
|
expect(res.body.message).toEqual("Apps successfully imported.")
|
||||||
|
|
||||||
// get a count of apps after the import
|
// get a count of apps after the import
|
||||||
const postImportApps = await request
|
const postImportApps = await request
|
||||||
.get(`/api/applications?status=${AppStatus.ALL}`)
|
.get(`/api/applications?status=${AppStatus.ALL}`)
|
||||||
.set(config.defaultHeaders())
|
.set(config.publicHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
|
|
||||||
|
const apps = postImportApps.body as App[]
|
||||||
// There are two apps in the file that was imported so check for this
|
// There are two apps in the file that was imported so check for this
|
||||||
expect(postImportApps.body.length).toEqual(2)
|
expect(apps.length).toEqual(2)
|
||||||
|
// The new tenant id was assigned to the imported apps
|
||||||
|
expect(tenancy.getTenantIDFromAppID(apps[0].appId)).toBe(
|
||||||
|
config.getTenantId()
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
|
@ -2,7 +2,6 @@ import * as rowController from "../../../controllers/row"
|
||||||
import * as appController from "../../../controllers/application"
|
import * as appController from "../../../controllers/application"
|
||||||
import { AppStatus } from "../../../../db/utils"
|
import { AppStatus } from "../../../../db/utils"
|
||||||
import { roles, tenancy, context } from "@budibase/backend-core"
|
import { roles, tenancy, context } from "@budibase/backend-core"
|
||||||
import { TENANT_ID } from "../../../../tests/utilities/structures"
|
|
||||||
import env from "../../../../environment"
|
import env from "../../../../environment"
|
||||||
import { db } from "@budibase/backend-core"
|
import { db } from "@budibase/backend-core"
|
||||||
import Nano from "@budibase/nano"
|
import Nano from "@budibase/nano"
|
||||||
|
@ -33,7 +32,7 @@ export const getAllTableRows = async (config: any) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const clearAllApps = async (
|
export const clearAllApps = async (
|
||||||
tenantId = TENANT_ID,
|
tenantId: string,
|
||||||
exceptions: Array<string> = []
|
exceptions: Array<string> = []
|
||||||
) => {
|
) => {
|
||||||
await tenancy.doInTenant(tenantId, async () => {
|
await tenancy.doInTenant(tenantId, async () => {
|
||||||
|
|
|
@ -8,9 +8,8 @@ jest.mock("@budibase/backend-core", () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const { tenancy, db: dbCore } = require("@budibase/backend-core")
|
const { context, db: dbCore } = require("@budibase/backend-core")
|
||||||
const TestConfig = require("../../../tests/utilities/TestConfiguration")
|
const TestConfig = require("../../../tests/utilities/TestConfiguration")
|
||||||
const { TENANT_ID } = require("../../../tests/utilities/structures")
|
|
||||||
|
|
||||||
// mock email view creation
|
// mock email view creation
|
||||||
|
|
||||||
|
@ -26,8 +25,8 @@ describe("run", () => {
|
||||||
afterAll(config.end)
|
afterAll(config.end)
|
||||||
|
|
||||||
it("runs successfully", async () => {
|
it("runs successfully", async () => {
|
||||||
await tenancy.doInTenant(TENANT_ID, async () => {
|
await config.doInTenant(async () => {
|
||||||
const globalDb = tenancy.getGlobalDB()
|
const globalDb = context.getGlobalDB()
|
||||||
await migration.run(globalDb)
|
await migration.run(globalDb)
|
||||||
expect(dbCore.createNewUserEmailView).toHaveBeenCalledTimes(1)
|
expect(dbCore.createNewUserEmailView).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
|
@ -8,3 +8,4 @@ process.env.BUDIBASE_DIR = tmpdir("budibase-unittests")
|
||||||
process.env.LOG_LEVEL = process.env.LOG_LEVEL || "error"
|
process.env.LOG_LEVEL = process.env.LOG_LEVEL || "error"
|
||||||
process.env.ENABLE_4XX_HTTP_LOGGING = "0"
|
process.env.ENABLE_4XX_HTTP_LOGGING = "0"
|
||||||
process.env.MOCK_REDIS = "1"
|
process.env.MOCK_REDIS = "1"
|
||||||
|
process.env.PLATFORM_URL = "http://localhost:10000"
|
||||||
|
|
|
@ -21,7 +21,6 @@ import {
|
||||||
basicScreen,
|
basicScreen,
|
||||||
basicLayout,
|
basicLayout,
|
||||||
basicWebhook,
|
basicWebhook,
|
||||||
TENANT_ID,
|
|
||||||
} from "./structures"
|
} from "./structures"
|
||||||
import {
|
import {
|
||||||
constants,
|
constants,
|
||||||
|
@ -41,8 +40,8 @@ import { generateUserMetadataID } from "../../db/utils"
|
||||||
import { startup } from "../../startup"
|
import { startup } from "../../startup"
|
||||||
import supertest from "supertest"
|
import supertest from "supertest"
|
||||||
import {
|
import {
|
||||||
|
App,
|
||||||
AuthToken,
|
AuthToken,
|
||||||
Database,
|
|
||||||
Datasource,
|
Datasource,
|
||||||
Row,
|
Row,
|
||||||
SourceName,
|
SourceName,
|
||||||
|
@ -63,7 +62,7 @@ class TestConfiguration {
|
||||||
started: boolean
|
started: boolean
|
||||||
appId: string | null
|
appId: string | null
|
||||||
allApps: any[]
|
allApps: any[]
|
||||||
app: any
|
app?: App
|
||||||
prodApp: any
|
prodApp: any
|
||||||
prodAppId: any
|
prodAppId: any
|
||||||
user: any
|
user: any
|
||||||
|
@ -73,7 +72,7 @@ class TestConfiguration {
|
||||||
linkedTable: any
|
linkedTable: any
|
||||||
automation: any
|
automation: any
|
||||||
datasource: any
|
datasource: any
|
||||||
tenantId: string | null
|
tenantId?: string
|
||||||
defaultUserValues: DefaultUserValues
|
defaultUserValues: DefaultUserValues
|
||||||
|
|
||||||
constructor(openServer = true) {
|
constructor(openServer = true) {
|
||||||
|
@ -89,7 +88,6 @@ class TestConfiguration {
|
||||||
}
|
}
|
||||||
this.appId = null
|
this.appId = null
|
||||||
this.allApps = []
|
this.allApps = []
|
||||||
this.tenantId = null
|
|
||||||
this.defaultUserValues = this.populateDefaultUserValues()
|
this.defaultUserValues = this.populateDefaultUserValues()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,19 +152,10 @@ 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()) {
|
||||||
this.defaultUserValues = this.populateDefaultUserValues()
|
|
||||||
if (context.isMultiTenant()) {
|
|
||||||
this.tenantId = structures.tenant.id()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.started) {
|
if (!this.started) {
|
||||||
await startup()
|
await startup()
|
||||||
}
|
}
|
||||||
this.user = await this.globalUser()
|
return this.newTenant(appName)
|
||||||
this.globalUserId = this.user._id
|
|
||||||
this.userMetadataId = generateUserMetadataID(this.globalUserId)
|
|
||||||
|
|
||||||
return this.createApp(appName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
end() {
|
end() {
|
||||||
|
@ -182,24 +171,22 @@ class TestConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MODES
|
// MODES
|
||||||
#setMultiTenancy = (value: boolean) => {
|
setMultiTenancy = (value: boolean) => {
|
||||||
env._set("MULTI_TENANCY", value)
|
env._set("MULTI_TENANCY", value)
|
||||||
coreEnv._set("MULTI_TENANCY", value)
|
coreEnv._set("MULTI_TENANCY", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
#setSelfHosted = (value: boolean) => {
|
setSelfHosted = (value: boolean) => {
|
||||||
env._set("SELF_HOSTED", value)
|
env._set("SELF_HOSTED", value)
|
||||||
coreEnv._set("SELF_HOSTED", value)
|
coreEnv._set("SELF_HOSTED", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
modeCloud = () => {
|
modeCloud = () => {
|
||||||
this.#setSelfHosted(false)
|
this.setSelfHosted(false)
|
||||||
this.#setMultiTenancy(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
modeSelf = () => {
|
modeSelf = () => {
|
||||||
this.#setSelfHosted(true)
|
this.setSelfHosted(true)
|
||||||
this.#setMultiTenancy(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UTILS
|
// UTILS
|
||||||
|
@ -354,6 +341,8 @@ class TestConfiguration {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HEADERS
|
||||||
|
|
||||||
defaultHeaders(extras = {}) {
|
defaultHeaders(extras = {}) {
|
||||||
const tenantId = this.getTenantId()
|
const tenantId = this.getTenantId()
|
||||||
const authObj: AuthToken = {
|
const authObj: AuthToken = {
|
||||||
|
@ -374,6 +363,7 @@ class TestConfiguration {
|
||||||
`${constants.Cookie.CurrentApp}=${appToken}`,
|
`${constants.Cookie.CurrentApp}=${appToken}`,
|
||||||
],
|
],
|
||||||
[constants.Header.CSRF_TOKEN]: this.defaultUserValues.csrfToken,
|
[constants.Header.CSRF_TOKEN]: this.defaultUserValues.csrfToken,
|
||||||
|
Host: this.tenantHost(),
|
||||||
...extras,
|
...extras,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,10 +373,6 @@ class TestConfiguration {
|
||||||
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
|
||||||
|
|
||||||
|
@ -397,9 +383,7 @@ class TestConfiguration {
|
||||||
headers[constants.Header.APP_ID] = appId
|
headers[constants.Header.APP_ID] = appId
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.tenantId) {
|
headers[constants.Header.TENANT_ID] = this.getTenantId()
|
||||||
headers[constants.Header.TENANT_ID] = this.tenantId
|
|
||||||
}
|
|
||||||
|
|
||||||
return headers
|
return headers
|
||||||
}
|
}
|
||||||
|
@ -413,6 +397,34 @@ class TestConfiguration {
|
||||||
return this.login({ email, roleId, builder, prodApp })
|
return this.login({ email, roleId, builder, prodApp })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TENANCY
|
||||||
|
|
||||||
|
tenantHost() {
|
||||||
|
const tenantId = this.getTenantId()
|
||||||
|
const platformHost = new URL(coreEnv.PLATFORM_URL).host.split(":")[0]
|
||||||
|
return `${tenantId}.${platformHost}`
|
||||||
|
}
|
||||||
|
|
||||||
|
getTenantId() {
|
||||||
|
if (!this.tenantId) {
|
||||||
|
throw new Error("no test tenant id - init has not been called")
|
||||||
|
}
|
||||||
|
return this.tenantId
|
||||||
|
}
|
||||||
|
|
||||||
|
async newTenant(appName = newid()): Promise<App> {
|
||||||
|
this.defaultUserValues = this.populateDefaultUserValues()
|
||||||
|
this.tenantId = structures.tenant.id()
|
||||||
|
this.user = await this.globalUser()
|
||||||
|
this.globalUserId = this.user._id
|
||||||
|
this.userMetadataId = generateUserMetadataID(this.globalUserId)
|
||||||
|
return this.createApp(appName)
|
||||||
|
}
|
||||||
|
|
||||||
|
doInTenant(task: any) {
|
||||||
|
return context.doInTenant(this.getTenantId(), task)
|
||||||
|
}
|
||||||
|
|
||||||
// API
|
// API
|
||||||
|
|
||||||
async generateApiKey(userId = this.defaultUserValues.globalUserId) {
|
async generateApiKey(userId = this.defaultUserValues.globalUserId) {
|
||||||
|
@ -432,7 +444,7 @@ class TestConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
// APP
|
// APP
|
||||||
async createApp(appName: string) {
|
async createApp(appName: string): Promise<App> {
|
||||||
// create dev app
|
// create dev app
|
||||||
// clear any old app
|
// clear any old app
|
||||||
this.appId = null
|
this.appId = null
|
||||||
|
@ -442,7 +454,7 @@ class TestConfiguration {
|
||||||
null,
|
null,
|
||||||
controllers.app.create
|
controllers.app.create
|
||||||
)
|
)
|
||||||
this.appId = this.app.appId
|
this.appId = this.app?.appId!
|
||||||
})
|
})
|
||||||
return await context.doInAppContext(this.appId, async () => {
|
return await context.doInAppContext(this.appId, async () => {
|
||||||
// create production app
|
// create production app
|
||||||
|
|
|
@ -13,8 +13,6 @@ import {
|
||||||
|
|
||||||
const { v4: uuidv4 } = require("uuid")
|
const { v4: uuidv4 } = require("uuid")
|
||||||
|
|
||||||
export const TENANT_ID = "default"
|
|
||||||
|
|
||||||
export function basicTable() {
|
export function basicTable() {
|
||||||
return {
|
return {
|
||||||
name: "TestTable",
|
name: "TestTable",
|
||||||
|
|
Loading…
Reference in New Issue