Changing tactic to relying on stable container names to prevent duplication.

This commit is contained in:
Sam Rose 2024-06-11 17:41:48 +01:00
parent 6a54b58303
commit 85c59c0350
No known key found for this signature in database
4 changed files with 39 additions and 19 deletions

View File

@ -9,6 +9,7 @@ import { testContainerUtils } from "@budibase/backend-core/tests"
import lockfile from "proper-lockfile" import lockfile from "proper-lockfile"
import path from "path" import path from "path"
import fs from "fs" import fs from "fs"
import _ from "lodash"
export type DatasourceProvider = () => Promise<Datasource> export type DatasourceProvider = () => Promise<Datasource>
@ -68,28 +69,38 @@ export async function rawQuery(ds: Datasource, sql: string): Promise<any> {
} }
export async function startContainer(container: GenericContainer) { export async function startContainer(container: GenericContainer) {
container = container.withReuse().withLabels({ "com.budibase": "true" })
// If two tests try to spin up the same container at the same time, there's a
// possibility that two containers of the same type will be started. To avoid
// this, we use a filesystem lock to ensure that only one container of a given
// type is started at a time.
const imageName = (container as any).imageName.string as string const imageName = (container as any).imageName.string as string
const lockPath = path.resolve( const key = imageName.replaceAll("/", "-").replaceAll(":", "-")
__dirname,
`${imageName.replaceAll("/", "-")}.lock`
)
const unlock = await lockfile.lock(lockPath, { container = container
retries: 10, .withReuse()
realpath: false, .withLabels({ "com.budibase": "true" })
}) .withName(key)
let startedContainer: StartedTestContainer let startedContainer: StartedTestContainer | undefined = undefined
try { let lastError = undefined
startedContainer = await container.start() for (let i = 0; i < 10; i++) {
} finally { try {
await unlock() // container.start() is not an idempotent operation, calling `start`
// modifies the internal state of a GenericContainer instance such that
// the hash it uses to determine reuse changes. We need to clone the
// container before calling start to ensure that we're using the same
// reuse hash every time.
const containerCopy = _.cloneDeep(container)
startedContainer = await containerCopy.start()
lastError = undefined
break
} catch (e: any) {
lastError = e
await new Promise(resolve => setTimeout(resolve, 1000))
}
}
if (!startedContainer) {
if (lastError) {
throw lastError
}
throw new Error(`failed to start container: ${imageName}`)
} }
const info = testContainerUtils.getContainerById(startedContainer.getId()) const info = testContainerUtils.getContainerById(startedContainer.getId())

View File

@ -29,6 +29,9 @@ export async function getDatasource(): Promise<Datasource> {
} }
const port = (await ports).find(x => x.container === 1433)?.host const port = (await ports).find(x => x.container === 1433)?.host
if (!port) {
throw new Error("SQL Server port not found")
}
const datasource: Datasource = { const datasource: Datasource = {
type: "datasource_plus", type: "datasource_plus",

View File

@ -38,6 +38,9 @@ export async function getDatasource(): Promise<Datasource> {
} }
const port = (await ports).find(x => x.container === 3306)?.host const port = (await ports).find(x => x.container === 3306)?.host
if (!port) {
throw new Error("MySQL port not found")
}
const datasource: Datasource = { const datasource: Datasource = {
type: "datasource_plus", type: "datasource_plus",

View File

@ -21,6 +21,9 @@ export async function getDatasource(): Promise<Datasource> {
} }
const port = (await ports).find(x => x.container === 5432)?.host const port = (await ports).find(x => x.container === 5432)?.host
if (!port) {
throw new Error("Postgres port not found")
}
const datasource: Datasource = { const datasource: Datasource = {
type: "datasource_plus", type: "datasource_plus",