Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: e2e flakky #438

Merged
merged 4 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:

- shell: bash
run: |
pnpm install --no-frozen-lockfile
pnpm install --frozen-lockfile
pnpm exec playwright install --with-deps

- shell: bash
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ node_modules/
**/flamegraph.*
!**/flamegraph.sh

test.e2e.log
test-results/
playwright-report/
blob-report/
Expand Down
7 changes: 1 addition & 6 deletions configs/e2e-bootstrap.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@
"listen_addresses": ["/ip4/0.0.0.0/tcp/50000/ws", "/ip4/0.0.0.0/tcp/50001"],
"bootstrap": true,
"bootstrap_peers": [],
"private_key_seed": "bootstrap",
"pubsub": {
"peer_discovery_interval": 1000,
"prune_backoff": 10,
"heartbeat_interval": 10
}
"private_key_seed": "bootstrap"
}
}
95 changes: 84 additions & 11 deletions examples/grid/e2e/grid.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,62 @@
import { type Page, expect, test } from "@playwright/test";
import * as fs from "node:fs";
import * as path from "node:path";
import * as readline from "node:readline";

const peersSelector = "#peers";
const peerIdSelector = "#peerIdExpanded";
const DRPIdInputSelector = "#gridInput";
const joinGridButtonSelector = "#joinGrid";
const objectPeersSelector = "#objectPeers";

function tailFileUntilTwoMatches(
filePath: string,
searchString: string,
matchCount = 2
): Promise<void> {
return new Promise((resolve, reject) => {
let count = 0;
let filePosition = 0;
const intervalMs = 100;

const interval = setInterval(() => {
fs.stat(filePath, (err, stats) => {
if (err) {
clearInterval(interval);
return reject(err);
}

if (stats.size > filePosition) {
const stream = fs.createReadStream(filePath, {
start: filePosition,
end: stats.size,
encoding: "utf8",
});

filePosition = stats.size;

const rl = readline.createInterface({ input: stream });
rl.on("line", (line) => {
if (line.includes(searchString)) {
count++;
if (count === matchCount) {
clearInterval(interval);
rl.close();
resolve();
}
}
});
}
});
}, intervalMs);
});
}

async function clearLogFile() {
const logPath = path.join(process.cwd(), "test.e2e.log");
await fs.promises.writeFile(logPath, "");
}

async function getGlowingPeer(page: Page, peerID: string) {
const div = page.locator(`div[data-glowing-peer-id="${peerID}"]`);
const style = await div.getAttribute("style");
Expand Down Expand Up @@ -41,18 +92,37 @@ test.describe("grid", () => {
let page2: Page;

test.beforeEach(async ({ browser }) => {
const { promise, resolve } = Promise.withResolvers<boolean>();
let hasGraftPage2 = false;
let hasGraftPage1 = false;
await clearLogFile();

page1 = await browser.newPage();
page1.on("console", async (msg) => {
if (!page2) return;
const peerID2 = await getPeerID(page2);
if (msg.text().includes(`graft {peerId: ${peerID2}`)) {
hasGraftPage1 = true;
}
if (hasGraftPage1 && hasGraftPage2) resolve(true);
});

await page1.goto("/");
await page1.waitForSelector("#loadingMessage", { state: "hidden" });

// wait for the peer to identify so the PX go well
await tailFileUntilTwoMatches("test.e2e.log", "::start::peer::identify");

page2 = await browser.newPage();
page2.on("console", async (msg) => {
if (!page1) return;
const peerID1 = await getPeerID(page1);
if (msg.text().includes(`graft {peerId: ${peerID1}`)) hasGraftPage2 = true;
if (hasGraftPage1 && hasGraftPage2) resolve(true);
});
await page2.goto("/");
await page2.waitForSelector("#loadingMessage", { state: "hidden" });
});

test.afterEach(async () => {
await page1.close();
await page2.close();
await promise;
});

test("check peerID", async () => {
Expand Down Expand Up @@ -94,18 +164,21 @@ test.describe("grid", () => {
timeout: 10000,
});

await page1.keyboard.press("w");
await page2.keyboard.press("s");

await expect(page1.locator(DRPIdInputSelector)).toHaveValue(drpId);
await expect(page2.locator(DRPIdInputSelector)).toHaveValue(drpId);

await page1.keyboard.press("w");
await page2.keyboard.press("s");
await expect(page2.locator(`div[data-glowing-peer-id="${peerID1}"]`)).toBeVisible({
timeout: 10000,
});
await expect(page2.locator(`div[data-glowing-peer-id="${peerID2}"]`)).toBeVisible({
timeout: 10000,
});

await expect(page2.locator(`div[data-glowing-peer-id="${peerID1}"]`)).toBeVisible();
await expect(page2.locator(`div[data-glowing-peer-id="${peerID2}"]`)).toBeVisible();
await new Promise((resolve) => setTimeout(resolve, 150));
const glowingPeer1 = await getGlowingPeer(page1, peerID1);
const glowingPeer2 = await getGlowingPeer(page1, peerID2);
console.log(glowingPeer1, glowingPeer2);
expect(Math.abs(glowingPeer1.top - glowingPeer2.top)).toBe(100);
});
});
22 changes: 1 addition & 21 deletions examples/grid/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,8 @@ import { getColorForPeerId } from "./util/color";
export function getNetworkConfigFromEnv() {
const hasBootstrapPeers = Boolean(import.meta.env.VITE_BOOTSTRAP_PEERS);
const hasDiscoveryInterval = Boolean(import.meta.env.VITE_DISCOVERY_INTERVAL);
const hasPubsubPruneBackoff = Boolean(import.meta.env.VITE_PUBSUB_PRUNE_BACKOFF);
const hasPubsubHeartbeatInterval = Boolean(import.meta.env.VITE_PUBSUB_HEARTBEAT_INTERVAL);

const hasEnv =
hasBootstrapPeers ||
hasDiscoveryInterval ||
hasPubsubPruneBackoff ||
hasPubsubHeartbeatInterval;
const hasEnv = hasBootstrapPeers || hasDiscoveryInterval;

const config: Record<string, unknown> = {
browser_metrics: true,
Expand All @@ -35,20 +29,6 @@ export function getNetworkConfigFromEnv() {
};
}

if (hasPubsubPruneBackoff) {
config.pubsub = {
...(config.pubsub || {}),
prune_backoff: import.meta.env.VITE_PUBSUB_PRUNE_BACKOFF,
};
}

if (hasPubsubHeartbeatInterval) {
config.pubsub = {
...(config.pubsub || {}),
heartbeat_interval: import.meta.env.VITE_PUBSUB_HEARTBEAT_INTERVAL,
};
}

return config;
}

Expand Down
2 changes: 0 additions & 2 deletions examples/grid/vite-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ interface ImportMetaEnv {
readonly VITE_BOOTSTRAP_PEERS: string;
readonly VITE_DISCOVERY_INTERVAL: number;
readonly VITE_RENDER_INFO_INTERVAL: number;
readonly VITE_PUBSUB_PRUNE_BACKOFF: number;
readonly VITE_PUBSUB_HEARTBEAT_INTERVAL: number;
}

interface ImportMeta {
Expand Down
18 changes: 4 additions & 14 deletions packages/network/src/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@ export interface DRPNetworkNodeConfig {
private_key_seed?: string;
pubsub?: {
peer_discovery_interval?: number;
prune_backoff?: number;
heartbeat_interval?: number;
};
}

Expand Down Expand Up @@ -119,12 +117,6 @@ export class DRPNetworkNode {
pubsub: gossipsub({
doPX: true,
allowPublishToZeroTopicPeers: true,
...(this._config?.pubsub?.prune_backoff
? { pruneBackoff: this._config.pubsub.prune_backoff }
: {}),
...(this._config?.pubsub?.heartbeat_interval
? { heartbeatInterval: this._config.pubsub.heartbeat_interval }
: {}),
scoreParams: createPeerScoreParams({
IPColocationFactorWeight: 0,
appSpecificScore: (peerId: string) => {
Expand Down Expand Up @@ -156,12 +148,6 @@ export class DRPNetworkNode {
doPX: true,
ignoreDuplicatePublishError: true,
allowPublishToZeroTopicPeers: true,
...(this._config?.pubsub?.prune_backoff
? { pruneBackoff: this._config.pubsub.prune_backoff }
: {}),
...(this._config?.pubsub?.heartbeat_interval
? { heartbeatInterval: this._config.pubsub.heartbeat_interval }
: {}),
scoreParams: createPeerScoreParams({
topicScoreCap: 50,
IPColocationFactorWeight: 0,
Expand Down Expand Up @@ -243,6 +229,10 @@ export class DRPNetworkNode {
log.info("::start::peer::identify", e.detail)
);

this._pubsub.addEventListener("gossipsub:graft", (e) =>
log.info("::start::gossipsub::graft", e.detail)
);

// needded as I've disabled the pubsubPeerDiscovery
this._pubsub?.subscribe("drp::discovery");
}
Expand Down
6 changes: 1 addition & 5 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,10 @@ export default defineConfig({
VITE_BOOTSTRAP_PEERS: [
"/ip4/127.0.0.1/tcp/50000/ws/p2p/12D3KooWC6sm9iwmYbeQJCJipKTRghmABNz1wnpJANvSMabvecwJ",
].join(","),
VITE_DISCOVERY_INTERVAL: "10",
VITE_RENDER_INFO_INTERVAL: "300",
VITE_PUBSUB_PRUNE_BACKOFF: "100",
VITE_PUBSUB_HEARTBEAT_INTERVAL: "1",
},
},
{
command: "pnpm cli --config configs/e2e-bootstrap.json",
command: "pnpm cli --config configs/e2e-bootstrap.json > test.e2e.log",
url: "http://localhost:50000",
reuseExistingServer: !process.env.CI,
},
Expand Down