Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove jest testcontainers #13350

Merged
merged 19 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/budibase_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ jobs:
docker pull postgres:16.1-bullseye
docker pull mongo:7.0-jammy
docker pull mariadb:lts
docker pull testcontainers/ryuk:0.3.0
docker pull testcontainers/ryuk:0.5.1
docker pull budibase/couchdb

- run: yarn --frozen-lockfile
Expand Down
16 changes: 0 additions & 16 deletions jestTestcontainersConfigGenerator.js

This file was deleted.

8 changes: 0 additions & 8 deletions packages/backend-core/jest-testcontainers-config.js

This file was deleted.

3 changes: 2 additions & 1 deletion packages/backend-core/jest.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Config } from "@jest/types"

const baseConfig: Config.InitialProjectOptions = {
preset: "@trendyol/jest-testcontainers",
setupFiles: ["./tests/jestEnv.ts"],
globalSetup: "./src/tests/globalSetup.ts",
globalTeardown: "./src/tests/globalTeardown.ts",
setupFilesAfterEnv: ["./tests/jestSetup.ts"],
transform: {
"^.+\\.ts?$": "@swc/jest",
Expand Down
1 change: 0 additions & 1 deletion packages/backend-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@
"@shopify/jest-koa-mocks": "5.1.1",
"@swc/core": "1.3.71",
"@swc/jest": "0.2.27",
"@trendyol/jest-testcontainers": "^2.1.1",
"@types/chance": "1.1.3",
"@types/cookies": "0.7.8",
"@types/jest": "29.5.5",
Expand Down
2 changes: 1 addition & 1 deletion packages/backend-core/src/db/Replication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class Replication {
return resolve(info)
})
.on("error", function (err) {
throw new Error(`Replication Error: ${err}`)
throw err
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This caused an error in a test while I was working on this change, and I moved to throwing the raw error in order to see the full stack trace. Decided to leave it as is because I feel this is more useful.

})
})
}
Expand Down
26 changes: 26 additions & 0 deletions packages/backend-core/src/tests/globalSetup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { GenericContainer, Wait } from "testcontainers"

export default async function setup() {
const container = await new GenericContainer("budibase/couchdb")
.withExposedPorts(5984)
.withEnvironment({
COUCHDB_PASSWORD: "budibase",
COUCHDB_USER: "budibase",
})
.withCopyFilesToContainer([
{
source: "./src/tests/test-couchdb.ini",
target: "/opt/couchdb/etc/local.d/test-couchdb.ini",
},
])
.withWaitStrategy(
Wait.forSuccessfulCommand(
"curl http://budibase:budibase@localhost:5984/_up"
).withStartupTimeout(20000)
)
.start()

// @ts-expect-error
// eslint-disable-next-line no-undef
globalThis.__COUCHDB_CONTAINER_ID__ = container.getId()
}
12 changes: 12 additions & 0 deletions packages/backend-core/src/tests/globalTeardown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { getContainerRuntimeClient } from "testcontainers"

export default async function teardown() {
const client = await getContainerRuntimeClient()

// @ts-expect-error
// eslint-disable-next-line no-undef
const containerId = globalThis.__COUCHDB_CONTAINER_ID__
const container = client.container.getById(containerId)
await client.container.stop(container)
mike12345567 marked this conversation as resolved.
Show resolved Hide resolved
await client.container.remove(container)
}
111 changes: 46 additions & 65 deletions packages/backend-core/tests/core/utilities/testContainerUtils.ts
Original file line number Diff line number Diff line change
@@ -1,85 +1,66 @@
import { DatabaseImpl } from "../../../src/db"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed how this file works because when I moved away from jest-testcontainers, this code started crafting invalid CouchDB URLs.

The new code uses docker ps --format json to make parsing the output easier, and it also makes sure to always return testcontainers containers by looking for the org.testcontainers=true label.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a nice improvement, I didn't even know you could get JSON out here, very handy!

import { execSync } from "child_process"

let dockerPsResult: string | undefined

function formatDockerPsResult(serverName: string, port: number) {
const lines = dockerPsResult?.split("\n")
let first = true
if (!lines) {
return null
}
for (let line of lines) {
if (first) {
first = false
continue
}
let toLookFor = serverName.split("-service")[0]
if (!line.includes(toLookFor)) {
continue
}
const regex = new RegExp(`0.0.0.0:([0-9]*)->${port}`, "g")
const found = line.match(regex)
if (found) {
return found[0].split(":")[1].split("->")[0]
}
}
return null
interface ContainerInfo {
Command: string
CreatedAt: string
ID: string
Image: string
Labels: string
LocalVolumes: string
Mounts: string
Names: string
Networks: string
Ports: string
RunningFor: string
Size: string
State: string
Status: string
}

function getTestContainerSettings(
serverName: string,
key: string
): string | null {
const entry = Object.entries(global).find(
([k]) =>
k.includes(`${serverName.toUpperCase()}`) &&
k.includes(`${key.toUpperCase()}`)
)
if (!entry) {
return null
}
return entry[1]
function getTestcontainers(): ContainerInfo[] {
return execSync("docker ps --format json")
.toString()
.split("\n")
.filter(x => x.length > 0)
.map(x => JSON.parse(x) as ContainerInfo)
.filter(x => x.Labels.includes("org.testcontainers=true"))
}

function getContainerInfo(containerName: string, port: number) {
let assignedPort = getTestContainerSettings(
containerName.toUpperCase(),
`PORT_${port}`
)
if (!dockerPsResult) {
try {
const outputBuffer = execSync("docker ps")
dockerPsResult = outputBuffer.toString("utf8")
} catch (err) {
//no-op
}
}
const possiblePort = formatDockerPsResult(containerName, port)
if (possiblePort) {
assignedPort = possiblePort
}
const host = getTestContainerSettings(containerName.toUpperCase(), "IP")
return {
port: assignedPort,
host,
url: host && assignedPort && `http://${host}:${assignedPort}`,
}
function getContainerByImage(image: string) {
return getTestcontainers().find(x => x.Image.startsWith(image))
}

function getCouchConfig() {
return getContainerInfo("couchdb", 5984)
function getExposedPort(container: ContainerInfo, port: number) {
const match = container.Ports.match(new RegExp(`0.0.0.0:(\\d+)->${port}/tcp`))
if (!match) {
return undefined
}
return parseInt(match[1])
}

export function setupEnv(...envs: any[]) {
const couch = getCouchConfig()
const couch = getContainerByImage("budibase/couchdb")
if (!couch) {
throw new Error("CouchDB container not found")
}

const couchPort = getExposedPort(couch, 5984)
if (!couchPort) {
throw new Error("CouchDB port not found")
}

const configs = [
{ key: "COUCH_DB_PORT", value: couch.port },
{ key: "COUCH_DB_URL", value: couch.url },
{ key: "COUCH_DB_PORT", value: `${couchPort}` },
{ key: "COUCH_DB_URL", value: `http://localhost:${couchPort}` },
]

for (const config of configs.filter(x => !!x.value)) {
for (const env of envs) {
env._set(config.key, config.value)
}
}

// @ts-expect-error
DatabaseImpl.nano = undefined
}
2 changes: 2 additions & 0 deletions packages/backend-core/tests/jestEnv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ process.env.NODE_ENV = "jest"
process.env.MOCK_REDIS = "1"
process.env.LOG_LEVEL = process.env.LOG_LEVEL || "error"
process.env.REDIS_PASSWORD = "budibase"
process.env.COUCH_DB_PASSWORD = "budibase"
process.env.COUCH_DB_USER = "budibase"
2 changes: 1 addition & 1 deletion packages/pro
Submodule pro updated from dd748e to 7c4287
8 changes: 0 additions & 8 deletions packages/server/jest-testcontainers-config.js

This file was deleted.

3 changes: 2 additions & 1 deletion packages/server/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import * as fs from "fs"
import { join } from "path"

const baseConfig: Config.InitialProjectOptions = {
preset: "@trendyol/jest-testcontainers",
setupFiles: ["./src/tests/jestEnv.ts"],
moduleFileExtensions: [
"js",
Expand All @@ -18,6 +17,8 @@ const baseConfig: Config.InitialProjectOptions = {
"svelte",
],
setupFilesAfterEnv: ["./src/tests/jestSetup.ts"],
globalSetup: "./src/tests/globalSetup.ts",
globalTeardown: "./src/tests/globalTeardown.ts",
transform: {
"^.+\\.ts?$": "@swc/jest",
"^.+\\.js?$": "@swc/jest",
Expand Down
1 change: 0 additions & 1 deletion packages/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@
"@babel/preset-env": "7.16.11",
"@swc/core": "1.3.71",
"@swc/jest": "0.2.27",
"@trendyol/jest-testcontainers": "2.1.1",
"@types/global-agent": "2.1.1",
"@types/google-spreadsheet": "3.1.5",
"@types/jest": "29.5.5",
Expand Down
26 changes: 26 additions & 0 deletions packages/server/src/tests/globalSetup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { GenericContainer, Wait } from "testcontainers"

export default async function setup() {
samwho marked this conversation as resolved.
Show resolved Hide resolved
const container = await new GenericContainer("budibase/couchdb")
.withExposedPorts(5984)
.withEnvironment({
COUCHDB_PASSWORD: "budibase",
adrinr marked this conversation as resolved.
Show resolved Hide resolved
COUCHDB_USER: "budibase",
})
.withCopyFilesToContainer([
{
source: "./src/tests/test-couchdb.ini",
target: "/opt/couchdb/etc/local.d/test-couchdb.ini",
},
])
.withWaitStrategy(
Wait.forSuccessfulCommand(
"curl http://budibase:budibase@localhost:5984/_up"
).withStartupTimeout(20000)
)
.start()

// @ts-expect-error
// eslint-disable-next-line no-undef
globalThis.__COUCHDB_CONTAINER_ID__ = container.getId()
}
12 changes: 12 additions & 0 deletions packages/server/src/tests/globalTeardown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { getContainerRuntimeClient } from "testcontainers"

export default async function teardown() {
const client = await getContainerRuntimeClient()

// @ts-expect-error
// eslint-disable-next-line no-undef
const containerId = globalThis.__COUCHDB_CONTAINER_ID__
const container = client.container.getById(containerId)
await client.container.stop(container)
await client.container.remove(container)
}
3 changes: 3 additions & 0 deletions packages/server/src/tests/jestEnv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ process.env.PLATFORM_URL = "http://localhost:10000"
process.env.REDIS_PASSWORD = "budibase"
process.env.BUDIBASE_VERSION = "0.0.0+jest"
process.env.WORKER_URL = "http://localhost:10000"
process.env.COUCH_DB_PASSWORD = "budibase"
process.env.COUCH_DB_USER = "budibase"
process.env.JWT_SECRET = "jwtsecret"
2 changes: 2 additions & 0 deletions packages/server/src/tests/test-couchdb.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[log]
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've taken the opportunity here to calm the CouchDB logs down. By default they log every single HTTP request, which is an unbelievable amount of logging. This made DEBUG=testcontainers* unusable, whereas with level = warn the output is a little less huge and more useful.

level = warn
8 changes: 0 additions & 8 deletions packages/worker/jest-testcontainers-config.js

This file was deleted.

3 changes: 2 additions & 1 deletion packages/worker/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { Config } from "@jest/types"
import * as fs from "fs"

const config: Config.InitialOptions = {
preset: "@trendyol/jest-testcontainers",
globalSetup: "./src/tests/globalSetup.ts",
globalTeardown: "./src/tests/globalTeardown.ts",
setupFiles: ["./src/tests/jestEnv.ts"],
setupFilesAfterEnv: ["./src/tests/jestSetup.ts"],
collectCoverageFrom: ["src/**/*.{js,ts}", "../backend-core/src/**/*.{js,ts}"],
Expand Down
1 change: 0 additions & 1 deletion packages/worker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@
"devDependencies": {
"@swc/core": "1.3.71",
"@swc/jest": "0.2.27",
"@trendyol/jest-testcontainers": "2.1.1",
"@types/jest": "29.5.5",
"@types/jsonwebtoken": "9.0.3",
"@types/koa": "2.13.4",
Expand Down
26 changes: 26 additions & 0 deletions packages/worker/src/tests/globalSetup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { GenericContainer, Wait } from "testcontainers"

export default async function setup() {
const container = await new GenericContainer("budibase/couchdb")
.withExposedPorts(5984)
.withEnvironment({
COUCHDB_PASSWORD: "budibase",
COUCHDB_USER: "budibase",
})
.withCopyFilesToContainer([
{
source: "./src/tests/test-couchdb.ini",
target: "/opt/couchdb/etc/local.d/test-couchdb.ini",
},
])
.withWaitStrategy(
Wait.forSuccessfulCommand(
"curl http://budibase:budibase@localhost:5984/_up"
).withStartupTimeout(20000)
)
.start()

// @ts-expect-error
// eslint-disable-next-line no-undef
globalThis.__COUCHDB_CONTAINER_ID__ = container.getId()
}
12 changes: 12 additions & 0 deletions packages/worker/src/tests/globalTeardown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { getContainerRuntimeClient } from "testcontainers"

export default async function teardown() {
const client = await getContainerRuntimeClient()

// @ts-expect-error
// eslint-disable-next-line no-undef
const containerId = globalThis.__COUCHDB_CONTAINER_ID__
const container = client.container.getById(containerId)
await client.container.stop(container)
await client.container.remove(container)
}
Loading
Loading