Skip to content

Commit

Permalink
fix: wait for db creation in pg-test (#209)
Browse files Browse the repository at this point in the history
  • Loading branch information
ForbesLindesay authored Jan 13, 2022
1 parent 45fbef7 commit 7e5dc48
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 15 deletions.
5 changes: 3 additions & 2 deletions packages/mysql-test/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ const DEFAULT_MYSQL_PASSWORD =
const DEFAULT_MYSQL_DB = process.env.MYSQL_TEST_DB || config.test.mySqlDb;

export interface Options
extends Pick<
extends Omit<
WithContainerOptions,
Exclude<keyof WithContainerOptions, 'internalPort'>
'internalPort' | 'enableDebugInstructions' | 'testConnection'
> {
mysqlUser: string;
mysqlPassword: string;
Expand Down Expand Up @@ -141,6 +141,7 @@ export default async function getDatabase(options: Partial<Options> = {}) {
MYSQL_PASSWORD: mysqlPassword,
MYSQL_DATABASE: mysqlDb,
},
enableDebugInstructions: `To view logs, run with MYSQL_TEST_DEBUG=true environment variable.`,
});

const databaseURL = `mysql://${mysqlUser}:${mysqlPassword}@localhost:${externalPort}/${mysqlDb}`;
Expand Down
2 changes: 2 additions & 0 deletions packages/pg-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
"dependencies": {
"@databases/pg-config": "^0.0.0",
"@databases/with-container": "^0.0.0",
"@types/cross-spawn": "^6.0.0",
"cross-spawn": "^6.0.5",
"modern-spawn": "^1.0.0",
"ms": "^2.1.2",
"parameter-reducers": "^2.0.0",
Expand Down
31 changes: 29 additions & 2 deletions packages/pg-test/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import startContainer, {
killOldContainers,
} from '@databases/with-container';
import {getPgConfigSync} from '@databases/pg-config';
import spawn = require('cross-spawn');

const config = getPgConfigSync();
const DEFAULT_PG_DEBUG = !!process.env.PG_TEST_DEBUG || config.test.debug;
Expand All @@ -26,9 +27,9 @@ const DEFAULT_PG_USER = process.env.PG_TEST_USER || config.test.pgUser;
const DEFAULT_PG_DB = process.env.PG_TEST_DB || config.test.pgDb;

export interface Options
extends Pick<
extends Omit<
WithContainerOptions,
Exclude<keyof WithContainerOptions, 'internalPort'>
'internalPort' | 'enableDebugInstructions' | 'testConnection'
> {
pgUser: string;
pgDb: string;
Expand Down Expand Up @@ -64,6 +65,32 @@ export default async function getDatabase(options: Partial<Options> = {}) {
POSTGRES_USER: pgUser,
POSTGRES_DB: pgDb,
},

enableDebugInstructions: `To view logs, run with PG_TEST_DEBUG=true environment variable.`,
async testConnection({
debug,
containerName,
testPortConnection,
}): Promise<boolean> {
if (!(await testPortConnection())) return false;
return await new Promise<boolean>((resolve) => {
spawn(
`docker`,
[
`exec`,
containerName,
`psql`,
`--username=${pgUser}`,
`--dbname=${pgDb}`,
`-c`,
`select 1`,
],
debug ? {stdio: 'inherit'} : {},
)
.on(`error`, () => resolve(false))
.on(`exit`, (code) => resolve(code === 0));
});
},
});

const databaseURL = `postgres://${pgUser}@localhost:${externalPort}/${pgDb}`;
Expand Down
54 changes: 43 additions & 11 deletions packages/with-container/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export interface Options {
*/
refreshImage?: boolean;
detached?: boolean;
enableDebugInstructions?: string;
testConnection?: (
opts: NormalizedOptions & {testPortConnection: () => Promise<boolean>},
) => Promise<boolean>;
}

export interface NormalizedOptions
Expand Down Expand Up @@ -111,29 +115,57 @@ export async function waitForDatabaseToStart(options: NormalizedOptions) {
finished = true;
reject(
new Error(
`Unable to connect to database after ${options.connectTimeoutSeconds} seconds. To view logs, run with DEBUG_PG_DOCKER=true environment variable`,
`Unable to connect to database after ${
options.connectTimeoutSeconds
} seconds.${
options.enableDebugInstructions
? ` ${options.enableDebugInstructions}`
: ``
}`,
),
);
}, options.connectTimeoutSeconds * 1000);
function test() {
console.warn(
`Waiting for ${options.containerName} on port ${options.externalPort}...`,
);
const connection = connect(options.externalPort)
.on('error', () => {
(options.testConnection
? options.testConnection({
...options,
testPortConnection: async () => await testConnection(options),
})
: testConnection(options)
).then(
(isConnected) => {
if (finished) return;
setTimeout(test, 500);
})
.on('connect', () => {
finished = true;
clearTimeout(timeout);
connection.end();
setTimeout(resolve, 1000);
});
if (isConnected) {
finished = true;
clearTimeout(timeout);
setTimeout(resolve, 1000);
} else {
setTimeout(test, 500);
}
},
(err) => {
reject(err);
},
);
}
test();
});
}
async function testConnection(options: NormalizedOptions): Promise<boolean> {
return new Promise<boolean>((resolve) => {
const connection = connect(options.externalPort)
.on('error', () => {
resolve(false);
})
.on('connect', () => {
connection.end();
resolve(true);
});
});
}

export async function killOldContainers(
options: Pick<NormalizedOptions, 'debug' | 'containerName'>,
Expand Down

0 comments on commit 7e5dc48

Please sign in to comment.