Allow httpd API ports to be generated randomly.

To avoid port collisions between tests that can eventually run in
parallel, we need to be able to generate random port numbers.

This commit generates random httpd port numbers for inline tests,
while keeping the current palm seed with the default port number 8080.

Signed-off-by: Sebastian Martinez <me@sebastinez.dev>
This commit is contained in:
Sebastian Martinez
2023-07-09 14:19:47 +02:00
committed by Rūdolfs Ošiņš
parent bde2d97c9b
commit db94969f8a
6 changed files with 72 additions and 37 deletions
+1 -1
View File
@@ -52,7 +52,7 @@ export default async function globalSetup(): Promise<() => void> {
console.log("Running tests");
await palm.stopNode();
} else {
await startPalmHttpd();
await startPalmHttpd(8080);
}
return () => killAllProcesses();
+19 -19
View File
@@ -11,12 +11,12 @@ import { createProject } from "@tests/support/project";
test("peer and branch switching", async ({ page }) => {
await page.goto(sourceBrowsingUrl);
await page.locator('role=link[name="6 commits"]').click();
await page.getByRole("link", { name: "6 commits" }).click();
// Alice's peer.
{
await page.getByTitle("Change peer").click();
await page.locator(`text=${aliceRemote}`).click();
await page.getByText(aliceRemote).click();
await expect(page.getByTitle("Change peer")).toHaveText(
` did:key:${aliceRemote
.substring(8)
@@ -37,7 +37,7 @@ test("peer and branch switching", async ({ page }) => {
await expect(earliestCommit).toContainText("36d5bbe");
await page.getByTitle("Change branch").click();
await page.locator("text=feature/branch").click();
await page.getByText("feature/branch").click();
await expect(page.getByTitle("Current branch")).toContainText(
"feature/branch 1aded56",
@@ -46,7 +46,7 @@ test("peer and branch switching", async ({ page }) => {
await expect(page.locator(".history .teaser")).toHaveCount(9);
await page.getByTitle("Change branch").click();
await page.locator("text=orphaned-branch").click();
await page.getByText("orphaned-branch").click();
await expect(page.getByTitle("Current branch")).toContainText(
"orphaned-branch af3641c",
@@ -58,7 +58,7 @@ test("peer and branch switching", async ({ page }) => {
// Bob's peer.
{
await page.getByTitle("Change peer").click();
await page.locator(`text=${bobRemote}`).click();
await page.getByText(bobRemote).click();
await expect(page.getByTitle("Change peer")).toContainText(
` did:key:${bobRemote.substring(8).substring(0, 6)}…${bobRemote.slice(
-6,
@@ -89,7 +89,7 @@ test("peer and branch switching", async ({ page }) => {
test("expand commit message", async ({ page }) => {
await page.goto(sourceBrowsingUrl);
await page.locator('role=link[name="6 commits"]').click();
await page.getByRole("link", { name: "6 commits" }).click();
const commitToggle = page
.locator("div")
.filter({ hasText: /^Add a C source file and its binary …$/ })
@@ -117,10 +117,10 @@ test("relative timestamps", async ({ page }) => {
});
await page.goto(sourceBrowsingUrl);
await page.locator('role=link[name="6 commits"]').click();
await page.getByRole("link", { name: "6 commits" }).click();
await page.getByTitle("Change peer").click();
await page.locator(`text=${bobRemote}`).click();
await page.getByText(bobRemote).click();
await expect(page.getByTitle("Change peer")).toHaveText(
`did:key:${bobRemote.substring(8).substring(0, 6)}…${bobRemote.slice(-6)}`,
);
@@ -138,12 +138,12 @@ test("pushing changes while viewing history", async ({ page, peerManager }) => {
name: "alice",
gitOptions: gitOptions["alice"],
});
await alice.startHttpd(8090);
await alice.startHttpd();
await alice.startNode();
const { rid, projectFolder } = await createProject(alice, "alice-project");
await page.goto(`/seeds/127.0.0.1:8090/${rid}`);
await page.locator('role=link[name="1 commit"]').click();
await expect(page).toHaveURL(`/seeds/127.0.0.1:8090/${rid}/history`);
await page.goto(`${alice.uiUrl()}/${rid}`);
await page.getByRole("link", { name: "1 commit" }).click();
await expect(page).toHaveURL(`${alice.uiUrl()}/${rid}/history`);
await alice.git(["commit", "--allow-empty", "--message", "first change"], {
cwd: projectFolder,
@@ -152,13 +152,13 @@ test("pushing changes while viewing history", async ({ page, peerManager }) => {
cwd: projectFolder,
});
await page.reload();
await expect(page).toHaveURL(`/seeds/127.0.0.1:8090/${rid}/history`);
await expect(page.locator('role=link[name="2 commits"]')).toBeVisible();
await expect(page).toHaveURL(`${alice.uiUrl()}/${rid}/history`);
await expect(page.getByRole("link", { name: "2 commits" })).toBeVisible();
await expect(page.getByTitle("Current branch")).toContainText("main 516fa74");
await page.locator("text=alice-project").click();
await expect(page).toHaveURL(`/seeds/127.0.0.1:8090/${rid}`);
await page.locator('role=link[name="2 commits"]').click();
await page.getByText("alice-project").click();
await expect(page).toHaveURL(`${alice.uiUrl()}/${rid}`);
await page.getByRole("link", { name: "2 commits" }).click();
await alice.git(
[
@@ -175,8 +175,8 @@ test("pushing changes while viewing history", async ({ page, peerManager }) => {
cwd: projectFolder,
});
await page.reload();
await expect(page).toHaveURL(`/seeds/127.0.0.1:8090/${rid}/history`);
await expect(page.locator('role=link[name="3 commits"]')).toHaveText(
await expect(page).toHaveURL(`${alice.uiUrl()}/${rid}/history`);
await expect(page.getByRole("link", { name: "3 commits" })).toHaveText(
"3 commits",
);
await expect(page.getByTitle("Current branch")).toContainText("main bb9089a");
+4 -2
View File
@@ -48,7 +48,7 @@ test("test issue editing failing", async ({ page, authenticatedPeer }) => {
);
await page.goto(
`/seeds/127.0.0.1:8070/${rid}/issues/d316f7a90a40dacbfb8728044bad50c9f71d44ba`,
`${authenticatedPeer.uiUrl()}/${rid}/issues/d316f7a90a40dacbfb8728044bad50c9f71d44ba`,
);
await page.getByPlaceholder("Leave your comment").fill("This is a comment");
@@ -62,7 +62,9 @@ test("go through the entire ui issue flow", async ({
}) => {
const { rid } = await createProject(authenticatedPeer, "commenting");
await page.goto(`/seeds/127.0.0.1:8070/${rid}`);
await page.goto(
`/seeds/${authenticatedPeer.httpdBaseUrl.hostname}:${authenticatedPeer.httpdBaseUrl.port}/${rid}`,
);
await page.getByRole("link", { name: "0 issues" }).click();
await page.getByRole("link", { name: "New issue" }).click();
await page.getByPlaceholder("Title").fill("This is a title");
+8 -7
View File
@@ -165,18 +165,20 @@ export const test = base.extend<{
gitOptions: gitOptions["bob"],
});
await peer.startHttpd(8070);
await peer.startHttpd();
await peer.startNode();
await page.goto("/");
await page.getByRole("button", { name: "radicle.local" }).click();
await page.locator('input[name="port"]').fill("8070");
await page
.locator('input[name="port"]')
.fill(peer.httpdBaseUrl.port.toString());
await page.locator('input[name="port"]').press("Enter");
const { stdout } = await peer.rad([
"web",
"--frontend",
"http://localhost:3001",
"--backend",
"http://127.0.0.1:8070",
`${peer.httpdBaseUrl.scheme}://${peer.httpdBaseUrl.hostname}:${peer.httpdBaseUrl.port}`,
"--json",
]);
const result = authSchema.safeParse(JSON.parse(stdout));
@@ -191,7 +193,7 @@ export const test = base.extend<{
await use(peer);
await peer.stopHttpd(8070);
await peer.stopHttpd();
await peer.stopNode();
},
@@ -256,13 +258,13 @@ export function appConfigWithFixture() {
};
}
export async function startPalmHttpd() {
export async function startPalmHttpd(httpdPort: number) {
const peerManager = await createPeerManager({
dataDir: Path.resolve(Path.join(tmpDir, "peers")),
outputLog: FsSync.createWriteStream(Path.resolve(Path.join(tmpDir, "log"))),
});
const palm = await peerManager.startPeer({ name: "palm" });
await palm.startHttpd(8080);
await palm.startHttpd(httpdPort);
}
export async function createSourceBrowsingFixture(
@@ -611,7 +613,6 @@ export const markdownRid = "rad:z2tchH2Ti4LxRKdssPQYs6VHE5rsg";
export const sourceBrowsingUrl = `/seeds/127.0.0.1/${sourceBrowsingRid}`;
export const cobUrl = `/seeds/127.0.0.1/${cobRid}`;
export const markdownUrl = `/seeds/127.0.0.1/${markdownRid}`;
export const seedPort = 8080;
export const seedRemote = "z6MktULudTtAsAhRegYPiZ6631RV3viv12qd4GQF8z1xB22S";
export const gitOptions = {
alice: {
+1 -1
View File
@@ -61,7 +61,7 @@ export default async function globalSetup(): Promise<() => void> {
console.log("Running tests");
await palm.stopNode();
} else {
await startPalmHttpd();
await startPalmHttpd(8080);
}
return () => killAllProcesses();
+39 -7
View File
@@ -1,4 +1,5 @@
/* eslint-disable @typescript-eslint/naming-convention */
import type { BaseUrl } from "@httpd-client";
import type { ExecaChildProcess, Options } from "execa";
import * as Fs from "node:fs/promises";
@@ -115,6 +116,7 @@ export class RadiclePeer {
#outputLog: Stream.Writable;
#gitOptions?: Record<string, string>;
#listenSocketAddr?: string;
#httpdBaseUrl?: BaseUrl;
#nodeProcess?: ExecaChildProcess;
#httpdProcess?: ExecaChildProcess;
@@ -184,25 +186,42 @@ export class RadiclePeer {
});
}
public async startHttpd(port: number) {
public async startHttpd(port?: number): Promise<void> {
if (!port) {
port = await getPort();
}
this.#httpdBaseUrl = {
hostname: "127.0.0.1",
port,
scheme: "http",
};
this.#httpdProcess = this.spawn("radicle-httpd", [
"--listen",
`0.0.0.0:${port}`,
`${this.#httpdBaseUrl.hostname}:${this.#httpdBaseUrl.port}`,
]);
await waitOn({
resources: [`tcp:127.0.0.1:${port}`],
resources: [
`tcp:${this.#httpdBaseUrl.hostname}:${this.#httpdBaseUrl.port}`,
],
timeout: 7000,
});
}
public async stopHttpd(port: number) {
public async stopHttpd() {
if (!this.#httpdBaseUrl || !this.#httpdProcess) {
throw new Error("No httpd service running");
}
this.#httpdProcess?.kill("SIGTERM");
await waitOn({
resources: [`tcp:127.0.0.1:${port}`],
resources: [
`tcp:${this.#httpdBaseUrl.hostname}:${this.#httpdBaseUrl.port}`,
],
reverse: true,
});
this.#httpdBaseUrl = undefined;
}
public async startNode(params?: {
@@ -312,10 +331,23 @@ export class RadiclePeer {
}
public uiUrl(): string {
return `/seeds/127.0.0.1:8080`;
if (!this.#httpdBaseUrl) {
throw new Error("No httpd service running");
}
return `/seeds/${this.#httpdBaseUrl.hostname}:${this.#httpdBaseUrl.port}`;
}
public ridUrl(rid: string): string {
return `/seeds/127.0.0.1:8080/${rid}`;
return `/seeds/${this.httpdBaseUrl.hostname}:${this.httpdBaseUrl.port}/${rid}`;
}
public get httpdBaseUrl(): BaseUrl {
if (!this.#httpdBaseUrl) {
throw new Error("No httpd service running");
}
return this.#httpdBaseUrl;
}
public git(args: string[] = [], opts?: Options): ExecaChildProcess {