Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Improvements around docker in Playwright #12261

Merged
merged 10 commits into from
Feb 20, 2024
45 changes: 25 additions & 20 deletions playwright/plugins/docker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,35 @@ import * as crypto from "crypto";
import * as childProcess from "child_process";
import * as fse from "fs-extra";

/**
* @param cmd - command to execute
* @param args - arguments to pass to executed command
* @param pipeStdout - whether to pipe stdout to that of this process
* @param pipeStderr - whether to pipe stderr to that of this process
* @return Promise which resolves to an object containing the string value of what was
* written to stdout and stderr by the executed command, unaffected by the pipe options.
*/
const exec = (
// Command to execute
cmd: string,
// Arguments to pass to executed command
args: string[],
// Whether to pipe stdout and stderr to that of this process
pipe = true,
pipeStdout = true,
pipeStderr = true,
): Promise<{ stdout: string; stderr: string }> => {
return new Promise((resolve, reject) => {
if (pipe) {
if (pipeStdout || pipeStderr) {
const log = ["Running command:", cmd, ...args, "\n"].join(" ");
process.stdout.write(log);
process.stderr.write(log);
if (pipeStdout) process.stdout.write(log);
if (pipeStderr) process.stderr.write(log);
}
const { stdout, stderr } = childProcess.execFile(cmd, args, { encoding: "utf8" }, (err, stdout, stderr) => {
if (err) reject(err);
resolve({ stdout, stderr });
if (pipe) {
process.stdout.write("\n");
process.stderr.write("\n");
}
if (pipeStdout) process.stdout.write("\n");
if (pipeStderr) process.stderr.write("\n");
});
if (pipe) {
stdout.pipe(process.stdout);
stderr.pipe(process.stderr);
if (pipeStdout || pipeStderr) {
if (pipeStdout) stdout.pipe(process.stdout);
if (pipeStderr) stderr.pipe(process.stderr);
}
});
};
Expand Down Expand Up @@ -75,12 +79,13 @@ export class Docker {
}
}

// Make host.containers.internal work to allow the container to talk to other services via host ports.
if (isPodman) {
// Make host.containers.internal work to allow the container to talk to other services via host ports.
params.push("--network");
params.push("slirp4netns:allow_host_loopback=true");
} else {
// Make host.docker.internal work to allow the container to talk to other services via host ports.
// Docker for Desktop includes a host-gateway mapping on host.docker.internal but to simplify the config
// we use the Podman variant host.containers.internal in all environments.
params.push("--add-host");
params.push("host.containers.internal:host-gateway");
}
Expand Down Expand Up @@ -111,16 +116,16 @@ export class Docker {
await exec("docker", ["stop", this.id]);
} catch (err) {
console.error(`Failed to stop docker container`, this.id, err);
await exec("docker", ["container", "ls"]);
}
}

/**
* @param params - list of parameters to pass to `docker exec`
* @param pipe - whether to pipe stdout and stderr to that of this process for introspection
* @param pipeStdout - whether to pipe stdout to that of this process, if set to false stdout will be suppressed
* @param pipeStderr - whether to pipe stderr to that of this process, if set to false stderr will be suppressed
*/
async exec(params: string[], pipe = true): Promise<void> {
await exec("docker", ["exec", this.id, ...params], pipe);
async exec(params: string[], pipeStdout = true, pipeStderr = true): Promise<void> {
await exec("docker", ["exec", this.id, ...params], pipeStdout, pipeStderr);
}

async getContainerIp(): Promise<string> {
Expand Down
10 changes: 5 additions & 5 deletions playwright/plugins/postgres/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,23 +50,23 @@ export class PostgresDocker extends Docker {
}

public async start(): Promise<{
postgresIp: string;
postgresId: string;
ipAddress: string;
containerId: string;
}> {
console.log(new Date(), "starting postgres container");
const postgresId = await this.run({
const containerId = await this.run({
image: "postgres",
containerName: `react-sdk-playwright-postgres-${this.key}`,
params: ["--tmpfs=/pgtmpfs", "-e", "PGDATA=/pgtmpfs", "-e", `POSTGRES_PASSWORD=${PG_PASSWORD}`],
// Optimise for testing - https://www.postgresql.org/docs/current/non-durability.html
cmd: ["-c", `fsync=off`, "-c", `synchronous_commit=off`, "-c", `full_page_writes=off`],
});

const postgresIp = await this.getContainerIp();
const ipAddress = await this.getContainerIp();
console.log(new Date(), "postgres container up");

await this.waitForPostgresReady();
console.log(new Date(), "postgres container ready");
return { postgresIp, postgresId };
return { ipAddress, containerId };
}
}
2 changes: 1 addition & 1 deletion playwright/plugins/sliding-sync-proxy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class SlidingSyncProxy {
async start(): Promise<ProxyInstance> {
console.log(new Date(), "Starting sliding sync proxy...");

const { postgresId, postgresIp } = await this.postgresDocker.start();
const { ipAddress: postgresId, containerId: postgresIp } = await this.postgresDocker.start();

const port = await getFreePort();
console.log(new Date(), "starting proxy container...", SLIDING_SYNC_PROXY_TAG);
Expand Down
Loading