Skip to content

Commit

Permalink
AB#139 fix: adjust setup to run integration tests in isolated dbs
Browse files Browse the repository at this point in the history
  • Loading branch information
giovannibaratta committed Feb 15, 2024
1 parent fa39d12 commit 4bd0a13
Show file tree
Hide file tree
Showing 17 changed files with 154 additions and 18 deletions.
1 change: 1 addition & 0 deletions service/.env.local
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DATABASE_URL=postgresql://developer:Safe1!@localhost:5432/terraapprove?schema=public
1 change: 1 addition & 0 deletions service/.env.test
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DATABASE_URL=postgresql://developer:Safe1!@localhost:5433/terraapprove?schema=public
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Directory in the Docker container where the changelog files are located
searchPath: /liquibase/changelog
# Assume that a DB is running on the same host as the Liquibase container
url: jdbc:postgresql://localhost:5433/terraapprove
changeLogFile: root-changelog.yaml
username: developer
password: Safe1!
2 changes: 2 additions & 0 deletions service/db-migrations/v1/root-v1.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
databaseChangeLog:
- include:
file: v1/set-db-as-template.yaml
- include:
file: v1/create-source-code-table.yaml
- include:
Expand Down
9 changes: 9 additions & 0 deletions service/db-migrations/v1/set-db-as-template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
databaseChangeLog:
- changeSet:
id: 6db0ccdc-c96c-474a-a549-d4df7c848207
author: Giovanni Baratta
comment: Set database as tempalte
changes:
- sql:
dbms: "postgresql"
sql: ALTER DATABASE terraapprove WITH is_template TRUE
12 changes: 12 additions & 0 deletions service/dev-external-deps/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,15 @@ services:
POSTGRES_DB: terraapprove
ports:
- 5432:5432

integration-test-db:
image: postgres:16.1
# These tweaks are not safe to use in production, but they can speed up local development
# Apply some performance improvements to pg as these guarantees are not needed while running locally
command: "postgres -c 'shared_buffers=128MB' -c 'fsync=off' -c 'synchronous_commit=off' -c 'full_page_writes=off' -c 'max_connections=100' -c 'client_min_messages=warning'"
environment:
POSTGRES_USER: developer
POSTGRES_PASSWORD: Safe1!
POSTGRES_DB: terraapprove
ports:
- 5433:5432
19 changes: 19 additions & 0 deletions service/libs/external/src/config/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {Injectable} from "@nestjs/common"

@Injectable()
export class Config {
private dbConnectionUrl: string

constructor() {
const connectionUrl = process.env.DATABASE_URL

if (connectionUrl === undefined)
throw new Error("DATABASE_URL is not defined")

this.dbConnectionUrl = connectionUrl
}

getDbConnectionUrl(): string {
return this.dbConnectionUrl
}
}
11 changes: 9 additions & 2 deletions service/libs/external/src/db/database-client.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import {Injectable, OnModuleInit} from "@nestjs/common"
import {PrismaClient} from "@prisma/client"
import {Config} from "../config/config"

@Injectable()
export class DatabaseClient extends PrismaClient implements OnModuleInit {
constructor() {
super()
constructor(readonly config: Config) {
super({
datasources: {
db: {
url: config.getDbConnectionUrl()
}
}
})
}

onModuleInit() {
Expand Down
3 changes: 2 additions & 1 deletion service/libs/external/src/external.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {SOURCE_CODE_REPOSITORY_TOKEN} from "@libs/service/interfaces/source-code
import {SourceCodeDbRepository} from "./db/source-code.repository"
import {PLAN_REPOSITORY_TOKEN} from "@libs/service/interfaces/plan.interfaces"
import {PlanDbRepository} from "./db/plan.repository"
import {Config} from "./config/config"

const sourceCodeRepository = {
provide: SOURCE_CODE_REPOSITORY_TOKEN,
Expand All @@ -17,7 +18,7 @@ const planRepository = {

@Module({
imports: [],
providers: [sourceCodeRepository, planRepository, DatabaseClient],
providers: [sourceCodeRepository, planRepository, DatabaseClient, Config],
exports: [sourceCodeRepository, planRepository]
})
export class ExternalModule {}
26 changes: 26 additions & 0 deletions service/libs/testing/src/database.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,30 @@
import {PrismaClient} from "@prisma/client"
import {randomUUID} from "crypto"

/** Create a duplicated database using the reference database as teamplte
* @returns the connection string to the new database
*/
export async function prepareDatabase(): Promise<string> {
const referenceDb = process.env.DATABASE_URL
// Create a client connected to the reference database
const prismaClient = new PrismaClient({
datasources: {
db: {
url: referenceDb
}
}
})

// Generate a unique database name to isolate test runs
const databaseName = `integration_test_${randomUUID().replace(/-/g, "")}`

await prismaClient.$executeRawUnsafe(
`CREATE DATABASE ${databaseName} TEMPLATE terraapprove;`
)
await prismaClient.$disconnect()

return `postgresql://developer:Safe1!@localhost:5433/${databaseName}?schema=public`
}

export async function cleanDatabase(client: PrismaClient): Promise<void> {
await client.sourceCode.deleteMany()
Expand Down
18 changes: 14 additions & 4 deletions service/main/test/controller/plan.controller.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,31 @@ import {Test, TestingModule} from "@nestjs/testing"
import {AppModule} from "@app/app.module"
import {PrismaClient} from "@prisma/client"
import {CreatePlanRefRequestBody} from "@app/controller/plan-models"
import {cleanDatabase} from "@libs/testing/database"
import {cleanDatabase, prepareDatabase} from "@libs/testing/database"
import {Config} from "@libs/external/config/config"
import {DatabaseClient} from "@libs/external/db/database-client"

describe("POST /plan-refs", () => {
let app: NestApplication
const endpoint = "/plan-refs"
const prisma = new PrismaClient()
let prisma: PrismaClient

beforeAll(async () => {
const isolatedDb = await prepareDatabase()

const module: TestingModule = await Test.createTestingModule({
imports: [AppModule]
}).compile()
})
.overrideProvider(Config)
.useValue({
getDbConnectionUrl: () => isolatedDb
})
.compile()

app = module.createNestApplication()
await app.init()
await prisma.$connect()

prisma = module.get(DatabaseClient)
})

beforeEach(async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,39 @@
// eslint-disable-next-line node/no-unpublished-import
import * as request from "supertest"

import {NestApplication} from "@nestjs/core"
// eslint-disable-next-line node/no-unpublished-import
import {Test, TestingModule} from "@nestjs/testing"
import {AppModule} from "@app/app.module"
import {operations} from "@apis/apis"
import {PrismaClient} from "@prisma/client"
import {cleanDatabase, prepareDatabase} from "@libs/testing/database"
import {Config} from "@libs/external/config/config"
import {DatabaseClient} from "@libs/external/db/database-client"

describe("POST /source-code-refs", () => {
let app: NestApplication

const prisma = new PrismaClient()
let prisma: PrismaClient

beforeAll(async () => {
const isolatedDb = await prepareDatabase()

const module: TestingModule = await Test.createTestingModule({
imports: [AppModule]
}).compile()
})
.overrideProvider(Config)
.useValue({
getDbConnectionUrl: () => isolatedDb
})
.compile()

app = module.createNestApplication()
await app.init()
await prisma.$connect()

prisma = module.get(DatabaseClient)
})

beforeEach(async () => {
await prisma.sourceCode.deleteMany()
await cleanDatabase(prisma)
})

it("should create a record in the SourceCode table and return the uuid", async () => {
Expand Down Expand Up @@ -103,7 +112,7 @@ describe("POST /source-code-refs", () => {
})

afterAll(async () => {
await prisma.sourceCode.deleteMany()
await cleanDatabase(prisma)
await prisma.$disconnect()
await app.close()
})
Expand Down
11 changes: 7 additions & 4 deletions service/package.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
{
"scripts": {
"start": "nest start",
"start:dev": "nest start --watch --debug",
"start": "dotenv -e .env.local -- nest start",
"start:dev": "dotenv -e .env.local -- nest start --watch --debug",
"deps:db:start": "docker-compose -f dev-external-deps/docker-compose.yaml up -d",
"deps:db:stop": "docker-compose -f dev-external-deps/docker-compose.yaml stop",
"deps:db:down": "docker-compose -f dev-external-deps/docker-compose.yaml down",
"deps:db:update-schema": "yarn deps:db:start && yarn prisma:pull && yarn prisma:generate",
"deps:db:migrate": "yarn deps:db:start && yarn liquibase:update",
"liquibase:update": "docker run --network host --rm -v ./db-migrations:/liquibase/changelog liquibase/liquibase --defaultsFile=/liquibase/changelog/liquibase.docker.properties update",
"liquibase:update": "yarn liquibase:update:dev && yarn liquibase:update:test",
"liquibase:update:dev": "docker run --network host --rm -v ./db-migrations:/liquibase/changelog liquibase/liquibase --defaultsFile=/liquibase/changelog/liquibase.docker.properties update",
"liquibase:update:test": "docker run --network host --rm -v ./db-migrations:/liquibase/changelog liquibase/liquibase --defaultsFile=/liquibase/changelog/integration-test.liquibase.docker.properties update",
"lint": "yarn eslint --cache --fix .",
"format:prettier": "yarn prettier --config .prettierrc . --write",
"compile": "nest build",
"prisma:pull": "yarn prisma db pull",
"prisma:generate": "yarn prisma generate",
"openapi": "yarn openapi-typescript openapi/terraapprove.yaml -o generated/interfaces/terraapprove-apis/apis.ts --immutable-types",
"generate:interfaces": "yarn openapi && yarn prisma:generate",
"test": "yarn jest {libs/**/*.test.ts,main/**/*.test.ts}"
"test": "dotenv -e .env.test -- yarn jest {libs/**/*.test.ts,main/**/*.test.ts}"
},
"name": "terraapprove-backend",
"version": "0.0.1",
Expand Down Expand Up @@ -46,6 +48,7 @@
"@types/supertest": "6.0.2",
"@typescript-eslint/eslint-plugin": "6.10.0",
"@typescript-eslint/parser": "6.10.0",
"dotenv-cli": "7.3.0",
"eslint": "8.53.0",
"eslint-config-prettier": "8.10.0",
"eslint-plugin-jest": "27.6.0",
Expand Down
29 changes: 29 additions & 0 deletions service/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2957,6 +2957,34 @@ __metadata:
languageName: node
linkType: hard

"dotenv-cli@npm:7.3.0":
version: 7.3.0
resolution: "dotenv-cli@npm:7.3.0"
dependencies:
cross-spawn: "npm:^7.0.3"
dotenv: "npm:^16.3.0"
dotenv-expand: "npm:^10.0.0"
minimist: "npm:^1.2.6"
bin:
dotenv: cli.js
checksum: bc48e9872ed451aa7633cfde0079f5e4b40837d49dca4eab947682c80f524bd1e63ec31ff69b7cf955ff969185a05a343dd5d754dd5569e4ae31f8e9a790ab1b
languageName: node
linkType: hard

"dotenv-expand@npm:^10.0.0":
version: 10.0.0
resolution: "dotenv-expand@npm:10.0.0"
checksum: b41eb278bc96b92cbf3037ca5f3d21e8845bf165dc06b6f9a0a03d278c2bd5a01c0cfbb3528ae3a60301ba1a8a9cace30e748c54b460753bc00d4c014b675597
languageName: node
linkType: hard

"dotenv@npm:^16.3.0":
version: 16.4.4
resolution: "dotenv@npm:16.4.4"
checksum: ddf43ede209d5f54c9da688e93326162eb0fc367ad1869909568cb15571ab8c87a0fab4e1d4af9860be0571c707a8b4aefa060a4f1b0bb14298a81e0ccf0017d
languageName: node
linkType: hard

"eastasianwidth@npm:^0.2.0":
version: 0.2.0
resolution: "eastasianwidth@npm:0.2.0"
Expand Down Expand Up @@ -6685,6 +6713,7 @@ __metadata:
"@types/supertest": "npm:6.0.2"
"@typescript-eslint/eslint-plugin": "npm:6.10.0"
"@typescript-eslint/parser": "npm:6.10.0"
dotenv-cli: "npm:7.3.0"
eslint: "npm:8.53.0"
eslint-config-prettier: "npm:8.10.0"
eslint-plugin-jest: "npm:27.6.0"
Expand Down

0 comments on commit 4bd0a13

Please sign in to comment.