feat: add waitForLog to docker container

This commit is contained in:
2024-07-19 17:13:43 +02:00
parent 82635f71ff
commit 7ee495f879
10 changed files with 1618 additions and 33 deletions

24
.eslint/eslint.config.mjs Normal file
View File

@@ -0,0 +1,24 @@
import simpleImportSort from "eslint-plugin-simple-import-sort";
import tseslint from "typescript-eslint";
export default [
...tseslint.configs.recommended,
{
plugins: {
"simple-import-sort": simpleImportSort,
},
rules: {
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
},
},
{
files: ["**/*.ts"],
rules: {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": ["error", {
argsIgnorePattern: "^_",
}],
},
},
];

1502
.eslint/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

11
.eslint/package.json Normal file
View File

@@ -0,0 +1,11 @@
{
"type": "module",
"devDependencies": {
"eslint": "9.7.0",
"eslint-plugin-simple-import-sort": "12.1.1",
"typescript-eslint": "7.16.0"
},
"overrides": {
"eslint": "9.7.0"
}
}

View File

@@ -15,13 +15,26 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup Deno - name: Setup Deno
uses: maximousblk/setup-deno@v2 # Installs latest version uses: maximousblk/setup-deno@v2
- run: deno task test - run: deno task test
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.JS
uses: actions/setup-node@v4
with:
node-version: 20
- run: cd .eslint && npm ci
- run: deno task lint
publish: publish:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: test needs: [lint, test]
permissions: permissions:
contents: read contents: read

View File

@@ -1,10 +1,10 @@
name: Test name: Test
on: on:
push: pull_request:
branches: branches:
- main - main
pull_request: push:
branches: branches:
- main - main
@@ -15,6 +15,19 @@ jobs:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Setup Deno - name: Setup Deno
uses: maximousblk/setup-deno@v2 # Installs latest version uses: maximousblk/setup-deno@v2
- run: deno task test - run: deno task test
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.JS
uses: actions/setup-node@v4
with:
node-version: 20
- run: cd .eslint && npm ci
- run: deno task lint

10
.vscode/settings.json vendored
View File

@@ -1,5 +1,15 @@
{ {
"deno.enable": true, "deno.enable": true,
"deno.lint": true,
"eslint.nodePath": "./.eslint/node_modules",
"eslint.options": {
"overrideConfigFile": "./.eslint/eslint.config.mjs"
},
"editor.formatOnSave": true, "editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"[typescript]": {
"editor.defaultFormatter": "denoland.vscode-deno" "editor.defaultFormatter": "denoland.vscode-deno"
} }
}

View File

@@ -68,13 +68,9 @@ export class PostgresTestContainer {
}); });
await container.start(); await container.start();
await container.logs((line) => { await container.waitForLog("database system is ready");
if (line.includes("init process complete")) {
return true;
}
});
await delay(1000); await delay(250);
return new PostgresTestContainer(container, port, { return new PostgresTestContainer(container, port, {
username: config.username ?? "postgres", username: config.username ?? "postgres",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@valkyr/testcontainers", "name": "@valkyr/testcontainers",
"version": "1.0.0", "version": "1.0.1",
"exports": { "exports": {
"./postgres": "./containers/postgres.ts" "./postgres": "./containers/postgres.ts"
}, },
@@ -25,6 +25,7 @@
"lineWidth": 120 "lineWidth": 120
}, },
"tasks": { "tasks": {
"lint": "npx eslint -c .eslint/eslint.config.mjs .",
"test": "export ENVIRONMENT=testing && deno test --allow-all --unstable-ffi" "test": "export ENVIRONMENT=testing && deno test --allow-all --unstable-ffi"
} }
} }

View File

@@ -64,23 +64,18 @@ export class Container {
* *
* @see https://docs.docker.com/engine/api/v1.45/#tag/Container/operation/ContainerLogs * @see https://docs.docker.com/engine/api/v1.45/#tag/Container/operation/ContainerLogs
* *
* @param handler - Function to handle each line of the logs. * @param query - Query parameters to send to the request
*/ */
async logs(handler: (line: string) => true | void) { async logs(query: {
const res = await modem.request({ follow?: boolean;
method: "GET", stdout?: boolean;
path: `/containers/${this.id}/logs`, stderr?: boolean;
query: { since?: number;
stdout: true, until?: number;
follow: true, timestamps?: boolean;
tail: "all", tail?: number | "all";
}, } = {}) {
}); return modem.request({ method: "GET", path: `/containers/${this.id}/logs`, query });
for await (const chunk of res.stream) {
if (handler(chunk) === true) {
break;
}
}
} }
/** /**
@@ -103,6 +98,26 @@ export class Container {
}); });
await new Exec(Id).start(); await new Exec(Id).start();
} }
/**
* Waits for a specific log value to occur on the container within the given
* timeout limit.
*
* @param value - Value to look for.
* @param timeout - Time limit producing an error if exceeded.
*/
async waitForLog(value: string, timeout = 5_000): Promise<void> {
const response = await this.logs({ follow: true, stdout: true, stderr: true });
const timer = setTimeout(() => {
throw new Error("Timed out waiting for log result");
}, timeout);
for await (const chunk of response.stream) {
if (chunk.includes(value)) {
clearTimeout(timer);
break;
}
}
}
} }
/* /*

View File

@@ -1,7 +1,7 @@
import type { ContainerConfig } from "../types/container.ts"; import type { ContainerConfig } from "../types/container.ts";
import { modem } from "./modem.ts";
import { Container } from "./container.ts"; import { Container } from "./container.ts";
import { Image } from "./image.ts"; import { Image } from "./image.ts";
import { modem } from "./modem.ts";
export class Docker { export class Docker {
/** /**