Skip to content

Commit 7ee1daf

Browse files
committed
refactor(qa): share mantis phase timer
1 parent 3a7a385 commit 7ee1daf

3 files changed

Lines changed: 54 additions & 104 deletions

File tree

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Qa Lab plugin module implements shared Mantis phase timing behavior.
2+
export type MantisPhaseTiming = {
3+
durationMs: number;
4+
finishedAt: string;
5+
name: string;
6+
startedAt: string;
7+
status: "accepted" | "fail" | "pass";
8+
};
9+
10+
export type MantisPhaseTimings = {
11+
phases: MantisPhaseTiming[];
12+
totalMs: number;
13+
};
14+
15+
export function createPhaseTimer(startedAt: Date) {
16+
const phases: MantisPhaseTiming[] = [];
17+
const origin = startedAt.getTime();
18+
function recordPhase(name: string, phaseStarted: Date, status: MantisPhaseTiming["status"]) {
19+
const phaseFinished = new Date();
20+
phases.push({
21+
durationMs: phaseFinished.getTime() - phaseStarted.getTime(),
22+
finishedAt: phaseFinished.toISOString(),
23+
name,
24+
startedAt: phaseStarted.toISOString(),
25+
status,
26+
});
27+
}
28+
async function timePhase<T>(name: string, run: () => Promise<T>): Promise<T> {
29+
const phaseStarted = new Date();
30+
try {
31+
const result = await run();
32+
recordPhase(name, phaseStarted, "pass");
33+
return result;
34+
} catch (error) {
35+
recordPhase(name, phaseStarted, "fail");
36+
throw error;
37+
}
38+
}
39+
function snapshot(now = new Date()): MantisPhaseTimings {
40+
return {
41+
phases: [...phases],
42+
totalMs: now.getTime() - origin,
43+
};
44+
}
45+
function updatePhaseStatus(name: string, status: MantisPhaseTiming["status"]) {
46+
const phase = phases.findLast((entry) => entry.name === name);
47+
if (phase) {
48+
phase.status = status;
49+
}
50+
}
51+
return { recordPhase, snapshot, timePhase, updatePhaseStatus };
52+
}

extensions/qa-lab/src/mantis/slack-desktop-smoke.runtime.ts

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
stopCrabbox,
2121
warmupCrabbox,
2222
} from "./crabbox-runtime.js";
23+
import { createPhaseTimer, type MantisPhaseTimings } from "../mantis-phase-timer.runtime.js";
2324

2425
export type MantisSlackDesktopSmokeOptions = {
2526
alternateModel?: string;
@@ -103,19 +104,6 @@ type MantisSlackDesktopSmokeSummary = {
103104
warning?: string;
104105
};
105106

106-
type MantisPhaseTiming = {
107-
durationMs: number;
108-
finishedAt: string;
109-
name: string;
110-
startedAt: string;
111-
status: "accepted" | "fail" | "pass";
112-
};
113-
114-
type MantisPhaseTimings = {
115-
phases: MantisPhaseTiming[];
116-
totalMs: number;
117-
};
118-
119107
type SlackDesktopRemoteMetadata = {
120108
gatewayAlive?: boolean;
121109
gatewayPid?: string;
@@ -188,45 +176,6 @@ function normalizeHydrateMode(
188176
throw new Error(`Unsupported Mantis Slack desktop hydrate mode: ${value}`);
189177
}
190178

191-
function createPhaseTimer(startedAt: Date) {
192-
const phases: MantisPhaseTiming[] = [];
193-
const origin = startedAt.getTime();
194-
function recordPhase(name: string, phaseStarted: Date, status: MantisPhaseTiming["status"]) {
195-
const phaseFinished = new Date();
196-
phases.push({
197-
durationMs: phaseFinished.getTime() - phaseStarted.getTime(),
198-
finishedAt: phaseFinished.toISOString(),
199-
name,
200-
startedAt: phaseStarted.toISOString(),
201-
status,
202-
});
203-
}
204-
async function timePhase<T>(name: string, run: () => Promise<T>): Promise<T> {
205-
const phaseStarted = new Date();
206-
try {
207-
const result = await run();
208-
recordPhase(name, phaseStarted, "pass");
209-
return result;
210-
} catch (error) {
211-
recordPhase(name, phaseStarted, "fail");
212-
throw error;
213-
}
214-
}
215-
function snapshot(now = new Date()): MantisPhaseTimings {
216-
return {
217-
phases: [...phases],
218-
totalMs: now.getTime() - origin,
219-
};
220-
}
221-
function updatePhaseStatus(name: string, status: MantisPhaseTiming["status"]) {
222-
const phase = phases.findLast((entry) => entry.name === name);
223-
if (phase) {
224-
phase.status = status;
225-
}
226-
}
227-
return { recordPhase, snapshot, timePhase, updatePhaseStatus };
228-
}
229-
230179
function defaultOutputDir(repoRoot: string, startedAt: Date) {
231180
const stamp = startedAt.toISOString().replace(/[:.]/gu, "-");
232181
return path.join(repoRoot, ".artifacts", "qa-e2e", "mantis", `slack-desktop-${stamp}`);

extensions/qa-lab/src/mantis/telegram-desktop-builder.runtime.ts

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
stopCrabbox,
2121
warmupCrabbox,
2222
} from "./crabbox-runtime.js";
23+
import { createPhaseTimer, type MantisPhaseTimings } from "../mantis-phase-timer.runtime.js";
2324

2425
export type MantisTelegramDesktopBuilderOptions = {
2526
commandRunner?: CommandRunner;
@@ -95,19 +96,6 @@ type MantisTelegramDesktopBuilderSummary = {
9596
timings: MantisPhaseTimings;
9697
};
9798

98-
type MantisPhaseTiming = {
99-
durationMs: number;
100-
finishedAt: string;
101-
name: string;
102-
startedAt: string;
103-
status: "accepted" | "fail" | "pass";
104-
};
105-
106-
type MantisPhaseTimings = {
107-
phases: MantisPhaseTiming[];
108-
totalMs: number;
109-
};
110-
11199
type TelegramDesktopRemoteMetadata = {
112100
gatewayAlive?: boolean;
113101
gatewayPid?: string;
@@ -161,45 +149,6 @@ function normalizeHydrateMode(
161149
throw new Error(`Unsupported Mantis Telegram desktop hydrate mode: ${value}`);
162150
}
163151

164-
function createPhaseTimer(startedAt: Date) {
165-
const phases: MantisPhaseTiming[] = [];
166-
const origin = startedAt.getTime();
167-
function recordPhase(name: string, phaseStarted: Date, status: MantisPhaseTiming["status"]) {
168-
const phaseFinished = new Date();
169-
phases.push({
170-
durationMs: phaseFinished.getTime() - phaseStarted.getTime(),
171-
finishedAt: phaseFinished.toISOString(),
172-
name,
173-
startedAt: phaseStarted.toISOString(),
174-
status,
175-
});
176-
}
177-
async function timePhase<T>(name: string, run: () => Promise<T>): Promise<T> {
178-
const phaseStarted = new Date();
179-
try {
180-
const result = await run();
181-
recordPhase(name, phaseStarted, "pass");
182-
return result;
183-
} catch (error) {
184-
recordPhase(name, phaseStarted, "fail");
185-
throw error;
186-
}
187-
}
188-
function snapshot(now = new Date()): MantisPhaseTimings {
189-
return {
190-
phases: [...phases],
191-
totalMs: now.getTime() - origin,
192-
};
193-
}
194-
function updatePhaseStatus(name: string, status: MantisPhaseTiming["status"]) {
195-
const phase = phases.findLast((entry) => entry.name === name);
196-
if (phase) {
197-
phase.status = status;
198-
}
199-
}
200-
return { recordPhase, snapshot, timePhase, updatePhaseStatus };
201-
}
202-
203152
function defaultOutputDir(repoRoot: string, startedAt: Date) {
204153
const stamp = startedAt.toISOString().replace(/[:.]/gu, "-");
205154
return path.join(repoRoot, ".artifacts", "qa-e2e", "mantis", `telegram-desktop-${stamp}`);

0 commit comments

Comments
 (0)