Skip to content

Commit

Permalink
test(seed): split out seed tests, test in parallel to main tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ThatOneBro committed Apr 23, 2024
1 parent 9ded4bf commit 000a017
Show file tree
Hide file tree
Showing 16 changed files with 254 additions and 27 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,19 @@ jobs:
--health-retries 5
ports:
- 5432/tcp
postgres-seed:
image: postgres:${{ matrix.pg-version }}
env:
POSTGRES_DB: medplum_test
POSTGRES_USER: medplum
POSTGRES_PASSWORD: medplum
options: >-
--health-cmd pg_isready
--health-retries 5
--health-interval 10s
--health-timeout 5s
ports:
- 5433/tcp:5432/tcp
redis:
image: redis:${{ matrix.redis-version }}
options: >-
Expand Down Expand Up @@ -225,6 +238,7 @@ jobs:
env:
POSTGRES_HOST: localhost
POSTGRES_PORT: ${{ job.services.postgres.ports[5432] }}
POSTGRES_SEED_PORT: ${{ job.services.postgres.ports[5433] }}
REDIS_PASSWORD_DISABLED_IN_TESTS: 1
- name: Upload code coverage
if: ${{ matrix.node-version == 20 && matrix.pg-version == 14 && matrix.redis-version == 7 }}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ packages/react/build-storybook.log

# Jest code coverage
coverage/
packages/server/coverage-seed/

# TypeScript incremental build
tsconfig.tsbuildinfo
Expand Down
15 changes: 15 additions & 0 deletions docker-compose.seed.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
version: '3.7'
services:
postgres-seed:
image: postgres:12
restart: always
environment:
- POSTGRES_USER=medplum
- POSTGRES_PASSWORD=medplum

volumes:
- ./postgres/postgres.conf:/usr/local/etc/postgres/postgres.conf
- ./postgres/:/docker-entrypoint-initdb.d/
command: postgres -c config_file=/usr/local/etc/postgres/postgres.conf
ports:
- '5433:5432'
13 changes: 13 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@ services:
command: postgres -c config_file=/usr/local/etc/postgres/postgres.conf
ports:
- '5432:5432'
postgres-seed:
image: postgres:12
restart: always
environment:
- POSTGRES_USER=medplum
- POSTGRES_PASSWORD=medplum

volumes:
- ./postgres/postgres.conf:/usr/local/etc/postgres/postgres.conf
- ./postgres/:/docker-entrypoint-initdb.d/
command: postgres -c config_file=/usr/local/etc/postgres/postgres.conf
ports:
- '5433:5432'
redis:
image: redis:7
restart: always
Expand Down
102 changes: 102 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"@types/node": "20.12.7",
"babel-jest": "29.7.0",
"babel-preset-vite": "1.1.3",
"concurrently": "8.2.2",
"cross-env": "7.0.3",
"danger": "11.3.1",
"esbuild": "0.20.2",
Expand Down
13 changes: 0 additions & 13 deletions packages/server/jest.config.json

This file was deleted.

15 changes: 15 additions & 0 deletions packages/server/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { Config } from 'jest';

export default {
testEnvironment: 'node',
testTimeout: 600000,
testSequencer: '<rootDir>/jest.sequencer.js',
transform: {
'^.+\\.(js|jsx|ts|tsx)$': 'babel-jest',
},
testMatch: ['<rootDir>/src/**/*.test.ts'],
moduleFileExtensions: ['ts', 'js', 'json', 'node'],
coverageDirectory: 'coverage',
coverageReporters: ['json', 'text'],
collectCoverageFrom: ['**/src/**/*', '!**/src/__mocks__/**/*.ts', '!**/src/migrations/**/*.ts'],
} satisfies Config;
8 changes: 8 additions & 0 deletions packages/server/jest.seed.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { Config } from 'jest';
import defaultConfig from './jest.config';

export default {
...defaultConfig,
testMatch: ['<rootDir>/seed-tests/**/*.test.ts'],
collectCoverageFrom: ['<rootDir>/seed-tests/**/*'],
} satisfies Config;
4 changes: 3 additions & 1 deletion packages/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
"clean": "rimraf dist",
"dev": "ts-node-dev --poll --respawn --transpile-only --require ./src/otel/instrumentation.ts src/index.ts",
"start": "node --require ./dist/otel/instrumentation.js dist/index.js",
"test": "jest"
"test:seed:serial": "jest seed-serial.test.ts --config jest.seed.config.ts --coverageDirectory \"<rootDir>/coverage-seed/serial\"",
"test:seed:parallel": "jest seed.test.ts --config jest.seed.config.ts --coverageDirectory \"<rootDir>/coverage-seed/parallel\"",
"test": "docker-compose -f ../../docker-compose.seed.yml up -d && npm run test:seed:parallel && jest"
},
"dependencies": {
"@aws-sdk/client-cloudwatch-logs": "3.554.0",
Expand Down
42 changes: 42 additions & 0 deletions packages/server/seed-tests/seed-serial.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Project } from '@medplum/fhirtypes';
import { initAppServices, shutdownApp } from '../src/app';
import { loadTestConfig } from '../src/config';
import { getDatabasePool } from '../src/database';
import { SelectQuery } from '../src/fhir/sql';
import { seedDatabase } from '../src/seed';
import { withTestContext } from '../src/test.setup';

describe('Seed', () => {
beforeAll(async () => {
console.log = jest.fn();

const config = await loadTestConfig();
config.database.port = process.env['POSTGRES_SEED_PORT']
? Number.parseInt(process.env['POSTGRES_SEED_PORT'], 10)
: 5433;
return withTestContext(() => initAppServices(config));
});

afterAll(async () => {
await shutdownApp();
});

test('Seeder completes successfully -- serial version', async () => {
// First time, seeder should run
await seedDatabase({ parallel: false });

// Make sure the first project is a super admin
const rows = await new SelectQuery('Project')
.column('content')
.where('name', '=', 'Super Admin')
.execute(getDatabasePool());
expect(rows.length).toBe(1);

const project = JSON.parse(rows[0].content) as Project;
expect(project.superAdmin).toBe(true);
expect(project.strictMode).toBe(true);

// Second time, seeder should silently ignore
await seedDatabase({ parallel: false });
}, 240000);
});
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Project } from '@medplum/fhirtypes';
import { initAppServices, shutdownApp } from './app';
import { loadTestConfig } from './config';
import { getDatabasePool } from './database';
import { SelectQuery } from './fhir/sql';
import { seedDatabase } from './seed';
import { withTestContext } from './test.setup';
import { initAppServices, shutdownApp } from '../src/app';
import { loadTestConfig } from '../src/config';
import { getDatabasePool } from '../src/database';
import { SelectQuery } from '../src/fhir/sql';
import { seedDatabase } from '../src/seed';
import { withTestContext } from '../src/test.setup';

describe('Seed', () => {
beforeAll(async () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ export async function loadTestConfig(): Promise<MedplumServerConfig> {
config.binaryStorage = 'file:' + mkdtempSync(join(tmpdir(), 'medplum-temp-storage'));
config.allowedOrigins = undefined;
config.database.host = process.env['POSTGRES_HOST'] ?? 'localhost';
config.database.port = process.env['POSTGRES_PORT'] ? parseInt(process.env['POSTGRES_PORT'], 10) : 5432;
config.database.port = process.env['POSTGRES_PORT'] ? Number.parseInt(process.env['POSTGRES_PORT'], 10) : 5432;
config.database.dbname = 'medplum_test';
config.redis.db = 7; // Select logical DB `7` so we don't collide with existing dev Redis cache.
config.redis.password = process.env['REDIS_PASSWORD_DISABLED_IN_TESTS'] ? undefined : config.redis.password;
Expand Down
2 changes: 1 addition & 1 deletion packages/server/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"extends": "../../tsconfig.json",
"include": ["src/**/*.ts"]
"include": ["src/**/*.ts", "seed-tests/seed-serial.test.ts", "seed-tests/seed.test.ts"]
}
16 changes: 16 additions & 0 deletions packages/server/turbo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://turborepo.org/schema.json",
"extends": ["//"],
"pipeline": {
"test:seed:serial": {
"dependsOn": ["build"],
"outputs": ["coverage/**"],
"inputs": ["src/**/*.tsx", "src/**/*.ts"]
},
"test:seed:parallel": {
"dependsOn": ["build"],
"outputs": ["coverage/**"],
"inputs": ["src/**/*.tsx", "src/**/*.ts"]
}
}
}
21 changes: 16 additions & 5 deletions scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,29 @@ set -e
set -x

# Set node options
export NODE_OPTIONS='--max-old-space-size=5120'
export NODE_OPTIONS='--max-old-space-size=8192'

# Clear old code coverage data
rm -rf coverage
rm -rf coverage-seed
mkdir -p coverage/packages
mkdir -p coverage/combined
mkdir -p coverage-seed/serial
mkdir -p coverage-seed/parallel

# Seed the database
# Testing production path of seeding the database
# This is a special "test" which runs all of the seed logic, such as setting up structure definitions
# On a normal developer machine, this is run only rarely when setting up a new database
# This test must be run first, and cannot be run concurrently with other tests
time npx turbo run test --filter=./packages/server -- seed.test.ts --coverage
cp "packages/server/coverage/coverage-final.json" "coverage/packages/coverage-server-seed.json"
# We execute this in parallel with the main line of tests
{
time npx turbo run test:seed:serial --filter=./packages/server -- --coverage
cp "packages/server/coverage-seed/serial/coverage-final.json" "coverage/packages/coverage-server-seed-serial.json"
} &

# Seed the database before testing
# This is the parallel implementation so it's faster
time npx turbo run test:seed:parallel --filter=./packages/server -- --coverage
cp "packages/server/coverage-seed/parallel/coverage-final.json" "coverage/packages/coverage-server-seed-parallel.json"

# Test
# Run them separately because code coverage is resource intensive
Expand All @@ -36,6 +46,7 @@ for dir in `ls examples`; do
fi
done

wait

# Combine test coverage
PACKAGES=(
Expand Down

0 comments on commit 000a017

Please sign in to comment.