@browserstack/mcp-server 1.4.1-beta.1 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { apiClient } from "../../../lib/apiClient.js";
|
|
2
|
-
import { TCG_TRIGGER_URL, TCG_POLL_URL, FETCH_DETAILS_URL, FORM_FIELDS_URL, BULK_CREATE_URL, TC_DETAILS_MAX_BATCH, } from "./config.js";
|
|
2
|
+
import { TCG_TRIGGER_URL, TCG_POLL_URL, FETCH_DETAILS_URL, FORM_FIELDS_URL, BULK_CREATE_URL, TC_DETAILS_MAX_BATCH, TCG_POLL_INTERVAL_MS, TCG_POLL_MAX_WAIT_MS, } from "./config.js";
|
|
3
3
|
import { createTestCasePayload } from "./helpers.js";
|
|
4
4
|
import { getBrowserStackAuth } from "../../../lib/get-auth.js";
|
|
5
5
|
import { getTMBaseURL } from "../../../lib/tm-base-url.js";
|
|
@@ -118,9 +118,15 @@ export async function pollTestCaseDetails(traceRequestId, config) {
|
|
|
118
118
|
let done = false;
|
|
119
119
|
const tmBaseUrl = await getTMBaseURL(config);
|
|
120
120
|
const TCG_POLL_URL_VALUE = TCG_POLL_URL(tmBaseUrl);
|
|
121
|
+
const deadline = Date.now() + TCG_POLL_MAX_WAIT_MS;
|
|
121
122
|
while (!done) {
|
|
123
|
+
// Bail out if the backend never sends a "termination" message, so a stuck
|
|
124
|
+
// job cannot keep this loop (and its callers) alive forever.
|
|
125
|
+
if (Date.now() > deadline) {
|
|
126
|
+
throw new Error(`TCG test-case detail polling timed out after ${TCG_POLL_MAX_WAIT_MS}ms (trace ${traceRequestId})`);
|
|
127
|
+
}
|
|
122
128
|
// add a bit of jitter to avoid synchronized polling storms
|
|
123
|
-
await new Promise((r) => setTimeout(r,
|
|
129
|
+
await new Promise((r) => setTimeout(r, TCG_POLL_INTERVAL_MS + Math.random() * 5000));
|
|
124
130
|
const poll = await apiClient.post({
|
|
125
131
|
url: `${TCG_POLL_URL_VALUE}?x-bstack-traceRequestId=${encodeURIComponent(traceRequestId)}`,
|
|
126
132
|
headers: {
|
|
@@ -159,7 +165,20 @@ export async function pollScenariosTestDetails(args, traceId, context, documentI
|
|
|
159
165
|
const TCG_POLL_URL_VALUE = TCG_POLL_URL(tmBaseUrl);
|
|
160
166
|
// Promisify interval-style polling using a wrapper
|
|
161
167
|
await new Promise((resolve, reject) => {
|
|
162
|
-
const
|
|
168
|
+
const timers = {};
|
|
169
|
+
const stop = () => {
|
|
170
|
+
if (timers.interval)
|
|
171
|
+
clearInterval(timers.interval);
|
|
172
|
+
if (timers.timeout)
|
|
173
|
+
clearTimeout(timers.timeout);
|
|
174
|
+
};
|
|
175
|
+
// Hard wall-clock deadline: if the backend never sends a "termination"
|
|
176
|
+
// message, reject instead of letting the interval fire forever.
|
|
177
|
+
timers.timeout = setTimeout(() => {
|
|
178
|
+
stop();
|
|
179
|
+
reject(new Error(`TCG scenario polling timed out after ${TCG_POLL_MAX_WAIT_MS}ms (trace ${traceId})`));
|
|
180
|
+
}, TCG_POLL_MAX_WAIT_MS);
|
|
181
|
+
timers.interval = setInterval(async () => {
|
|
163
182
|
try {
|
|
164
183
|
const poll = await apiClient.post({
|
|
165
184
|
url: `${TCG_POLL_URL_VALUE}?x-bstack-traceRequestId=${encodeURIComponent(traceId)}`,
|
|
@@ -169,7 +188,7 @@ export async function pollScenariosTestDetails(args, traceId, context, documentI
|
|
|
169
188
|
body: {},
|
|
170
189
|
});
|
|
171
190
|
if (poll.status !== 200) {
|
|
172
|
-
|
|
191
|
+
stop();
|
|
173
192
|
reject(new Error(`Polling error: ${poll.statusText || poll.status}`));
|
|
174
193
|
return;
|
|
175
194
|
}
|
|
@@ -221,16 +240,16 @@ export async function pollScenariosTestDetails(args, traceId, context, documentI
|
|
|
221
240
|
}
|
|
222
241
|
}
|
|
223
242
|
if (msg.type === "termination") {
|
|
224
|
-
|
|
243
|
+
stop();
|
|
225
244
|
resolve();
|
|
226
245
|
}
|
|
227
246
|
}
|
|
228
247
|
}
|
|
229
248
|
catch (err) {
|
|
230
|
-
|
|
249
|
+
stop();
|
|
231
250
|
reject(err);
|
|
232
251
|
}
|
|
233
|
-
},
|
|
252
|
+
}, TCG_POLL_INTERVAL_MS);
|
|
234
253
|
});
|
|
235
254
|
// once all detail fetches are triggered, wait for them to complete
|
|
236
255
|
const detailsList = await Promise.all(detailPromises);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export declare const TC_DETAILS_MAX_BATCH = 10;
|
|
2
|
+
export declare const TCG_POLL_INTERVAL_MS = 10000;
|
|
3
|
+
export declare const TCG_POLL_MAX_WAIT_MS: number;
|
|
2
4
|
export declare const TCG_TRIGGER_URL: (baseUrl: string) => string;
|
|
3
5
|
export declare const TCG_POLL_URL: (baseUrl: string) => string;
|
|
4
6
|
export declare const FETCH_DETAILS_URL: (baseUrl: string) => string;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
export const TC_DETAILS_MAX_BATCH = 10;
|
|
2
|
+
// Wall-clock bounds for the TCG generation polling loops. Without a hard
|
|
3
|
+
// deadline, a job that never emits a "termination" message keeps the loop
|
|
4
|
+
// (and every caller awaiting it) alive forever.
|
|
5
|
+
export const TCG_POLL_INTERVAL_MS = 10_000;
|
|
6
|
+
export const TCG_POLL_MAX_WAIT_MS = 10 * 60 * 1000; // 10 minutes
|
|
2
7
|
export const TCG_TRIGGER_URL = (baseUrl) => `${baseUrl}/api/v1/integration/tcg/test-generation/suggest-test-cases`;
|
|
3
8
|
export const TCG_POLL_URL = (baseUrl) => `${baseUrl}/api/v1/integration/tcg/test-generation/test-cases-polling`;
|
|
4
9
|
export const FETCH_DETAILS_URL = (baseUrl) => `${baseUrl}/api/v1/integration/tcg/test-generation/fetch-test-case-details`;
|