Skip to content

Commit 0411567

Browse files
authored
test: add cpu & memory monitoring for e2e tests (#1862)
* test: add cpu & memory monitoring for e2e tests * test: rework pidMonitor to singleton * test: improve pid monitor start * test: collect perf data only for chromium based browsers
1 parent af473a8 commit 0411567

File tree

7 files changed

+155
-1
lines changed

7 files changed

+155
-1
lines changed

.github/actions/test/e2e/action.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,5 @@ runs:
9292
./packages/e2e-tests/logs
9393
./packages/e2e-tests/reports/allure/results
9494
./packages/e2e-tests/dmesg.log
95+
./packages/e2e-tests/metrics
9596
retention-days: 5

.github/workflows/e2e-tests-linux-split.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,9 @@ jobs:
254254
with:
255255
name: allure-results
256256
path: ./artifacts/reports/allure/results
257+
258+
- name: Upload performance metrics
259+
uses: actions/upload-artifact@v4
260+
with:
261+
name: performance-metrics
262+
path: ./artifacts/metrics

packages/e2e-tests/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ reports/
33
screenshots/
44
wallet-extension-safari-build/
55
src/support/walletConfiguration.ts
6+
metrics/

packages/e2e-tests/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"@rpii/wdio-report-events": "8.0.2",
3535
"@types/flat": "5.0.5",
3636
"@types/node": "20.14.2",
37+
"@types/pidusage": "2.0.5",
3738
"@types/puppeteer": "7.0.4",
3839
"@typescript-eslint/eslint-plugin": "6.0.0",
3940
"@typescript-eslint/parser": "6.0.0",
@@ -53,6 +54,7 @@
5354
"eslint-plugin-import": "2.27.5",
5455
"eslint-plugin-wdio": "8.37.0",
5556
"flat": "6.0.1",
57+
"pidusage": "4.0.1",
5658
"testcontainers": "10.24.2",
5759
"ts-node": "10.9.1",
5860
"typescript": "^4.9.5",

packages/e2e-tests/src/hooks/scenarioTagRunner.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,32 @@ import consoleManager from '../utils/consoleManager';
55

66
import allure from '@wdio/allure-reporter';
77
import testContext from '../utils/testContext';
8+
import PidMonitor from '../support/PidMonitor';
9+
import { Logger } from '../support/logger';
10+
11+
const monitor = PidMonitor.getInstance();
812

913
// eslint-disable-next-line no-unused-vars
1014
Before(async () => {
1115
if (String(process.env.SERVICE_WORKER_LOGS) === 'true') {
1216
await consoleManager.startLogsCollection();
1317
}
18+
if (browser.isChromium) {
19+
const pidMonitorInitialized = await monitor.init();
20+
if (pidMonitorInitialized) {
21+
monitor.start();
22+
} else {
23+
Logger.warn('PID monitor not initialized. Skipping start.');
24+
}
25+
}
1426
});
1527

16-
After({ tags: 'not @Pending and not @pending' }, async () => {
28+
After({ tags: 'not @Pending and not @pending' }, async (scenario) => {
29+
if (browser.isChromium) {
30+
monitor.stop();
31+
monitor.saveToFile(`./metrics/${scenario.testCaseStartedId}-chrome-usage.json`);
32+
monitor.clear();
33+
}
1734
testContext.clearContext();
1835
await browser.reloadSession();
1936
});
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import pidusage from 'pidusage';
2+
import fs from 'fs';
3+
import path from 'path';
4+
import { exec } from 'node:child_process';
5+
import { promisify } from 'util';
6+
import { clearInterval } from 'node:timers';
7+
import { Logger } from './logger';
8+
9+
const execAsync = promisify(exec);
10+
11+
interface UsageData {
12+
timestamp: string;
13+
cpu: number;
14+
memory: number;
15+
}
16+
17+
class PidMonitor {
18+
private static _instance: PidMonitor;
19+
20+
private pid?: number;
21+
private readonly intervalMs: number;
22+
private _data: UsageData[] = [];
23+
private timer?: ReturnType<typeof setInterval>;
24+
25+
private constructor(intervalMs = 1000) {
26+
this.intervalMs = intervalMs;
27+
}
28+
29+
public static getInstance(intervalMs = 1000): PidMonitor {
30+
if (!PidMonitor._instance) {
31+
PidMonitor._instance = new PidMonitor(intervalMs);
32+
}
33+
return PidMonitor._instance;
34+
}
35+
36+
public get data(): UsageData[] {
37+
return this._data;
38+
}
39+
40+
public async init(): Promise<boolean> {
41+
try {
42+
const { stdout } = await execAsync(
43+
"ps aux | grep '[c]hrome.*--extension-process.*--enable-automation.*--test-type=webdriver' | awk '{print $2}'"
44+
);
45+
const pid = Number(stdout.trim());
46+
47+
if (Number.isNaN(pid)) {
48+
Logger.error(`Parsed PID is NaN from stdout: "${stdout}"`);
49+
return false;
50+
}
51+
52+
this.pid = pid;
53+
return true;
54+
} catch (error) {
55+
Logger.error(`Error finding PID: ${error}`);
56+
return false;
57+
}
58+
}
59+
60+
public start(): void {
61+
if (this.pid === undefined) {
62+
Logger.warn('PID is not set. Call init() first.');
63+
return;
64+
}
65+
66+
if (this.timer) return;
67+
68+
this.timer = setInterval(async () => {
69+
if (this.pid === undefined) return;
70+
71+
try {
72+
const stats = await pidusage(this.pid);
73+
this._data.push({
74+
timestamp: new Date().toISOString(),
75+
cpu: stats.cpu,
76+
memory: stats.memory
77+
});
78+
} catch (error) {
79+
Logger.error(`pidusage failed: ${error}`);
80+
this.stop();
81+
}
82+
}, this.intervalMs);
83+
}
84+
85+
public stop(): void {
86+
if (this.timer) {
87+
clearInterval(this.timer);
88+
this.timer = undefined;
89+
}
90+
}
91+
92+
public clear(): void {
93+
this._data = [];
94+
}
95+
96+
public saveToFile(filePath: string): void {
97+
try {
98+
const dir = path.dirname(filePath);
99+
if (!fs.existsSync(dir)) {
100+
fs.mkdirSync(dir, { recursive: true });
101+
}
102+
fs.writeFileSync(filePath, JSON.stringify(this._data, undefined, 2), 'utf-8');
103+
} catch (error) {
104+
Logger.error(`Failed to save data to file: ${error}`);
105+
}
106+
}
107+
}
108+
109+
export default PidMonitor;

yarn.lock

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12673,6 +12673,7 @@ __metadata:
1267312673
"@types/chai-string": 1.4.5
1267412674
"@types/flat": 5.0.5
1267512675
"@types/node": 20.14.2
12676+
"@types/pidusage": 2.0.5
1267612677
"@types/puppeteer": 7.0.4
1267712678
"@typescript-eslint/eslint-plugin": 6.0.0
1267812679
"@typescript-eslint/parser": 6.0.0
@@ -12695,6 +12696,7 @@ __metadata:
1269512696
eslint-plugin-import: 2.27.5
1269612697
eslint-plugin-wdio: 8.37.0
1269712698
flat: 6.0.1
12699+
pidusage: 4.0.1
1269812700
testcontainers: 10.24.2
1269912701
ts-node: 10.9.1
1270012702
typescript: ^4.9.5
@@ -23063,6 +23065,13 @@ __metadata:
2306323065
languageName: node
2306423066
linkType: hard
2306523067

23068+
"@types/pidusage@npm:2.0.5":
23069+
version: 2.0.5
23070+
resolution: "@types/pidusage@npm:2.0.5"
23071+
checksum: 24188bf108b9b5a2ccb16155a492ff1cca7d7bf07aa4e2649cce421e0940dd5b0cd06baa48da9b8bde46343463fc500a7070c0788a0ed3f3f57d3e3bcf4ac64d
23072+
languageName: node
23073+
linkType: hard
23074+
2306623075
"@types/pify@npm:5.0.1":
2306723076
version: 5.0.1
2306823077
resolution: "@types/pify@npm:5.0.1"
@@ -47956,6 +47965,15 @@ __metadata:
4795647965
languageName: node
4795747966
linkType: hard
4795847967

47968+
"pidusage@npm:4.0.1":
47969+
version: 4.0.1
47970+
resolution: "pidusage@npm:4.0.1"
47971+
dependencies:
47972+
safe-buffer: ^5.2.1
47973+
checksum: 89ce11679b9871f8da6f21160c734f195fb6230e4a1017235133ac5294b9b0ec94d6c55a66fba43474bac524a7845ea309f43f37ce0e5c8f4e23512fa14ef2b6
47974+
languageName: node
47975+
linkType: hard
47976+
4795947977
"pify@npm:5.0.0, pify@npm:^5.0.0":
4796047978
version: 5.0.0
4796147979
resolution: "pify@npm:5.0.0"

0 commit comments

Comments
 (0)