Files
openobserve/tests/ui-testing/utils/apiUtils.js
T
Neha PandClaude Sonnet 4.6 5ea540c0d6 fix(test): extend keep-alive/compress fix to GeneralTests, Streams, Reports, SDR jobs (#12804)
## Summary

Applies the same node-fetch v2 fix from PR #12799 (pipelines) to all
remaining CI jobs that show \"Premature close\" / ECONNRESET failures:

- **apiUtils.js** (`sendRequest`): adds `compress:false` +
`noKeepAliveAgent` — fixes **Streams** job
(`multiselect-stream.spec.js`, `streamname.spec.js`)
- **apiCleanup.js** (`_fetch`): same fix on the node-fetch fallback path
— fixes **Reports** job (dashboard/report API calls)
- **model-pricing.spec.js**: wraps `node-fetch` with a local safe-fetch
shim — fixes **GeneralTests** job (`/llm/models` premature close)
- **streamsPage.js**: replaces four dynamic `node-fetch` imports with a
shared `_nodeFetchSafe` helper
- **ingestionPage.js**: adds `fetchWithRetry` around native fetch to
handle transient `ECONNRESET`/premature close in `beforeEach` ingestion

**SDR fix:** `regexPatternManagement.spec.js` — `AddRegexPattern.vue`
migrated to `OForm` with submit-time Zod validation
(`AddRegexPattern.schema.ts`). The `ODrawer` primary button is no longer
disabled for empty fields; validation triggers on click and keeps the
drawer open on error. Replaces stale `expect(isDisabled).toBeTruthy()`
checks with click-then-expect-drawer-still-visible assertions.

## Root cause (same as #12799)

`node-fetch` v2 defaults to `keepAlive: true` (connection pooling) and
`compress: true` (Gunzip stream). When the server closes a pooled
connection early, the Gunzip stream throws \"Premature close\". Because
the dead socket stays in the pool, retries hit the same socket.
`keepAlive: false` + `compress: false` eliminates both failure modes.

## Test plan

- [ ] GeneralTests / `model-pricing.spec.js` — no more premature close
on `/llm/models`
- [ ] Streams / `multiselect-stream.spec.js` + `streamname.spec.js` — no
more premature close on ingestion
- [ ] Reports / `reportsScheduleNow.spec.js` — no more premature close
during beforeEach ingestion
- [ ] SDR / `regexPatternManagement.spec.js` — validation test passes
with updated assertion

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 08:38:02 +00:00

63 lines
2.1 KiB
JavaScript

import fs from 'fs';
import path from 'path';
import http from 'http';
// Cache cloud config to avoid re-reading on every call
let _cachedCloudConfig = null;
// node-fetch v2 keep-alive pooling + gzip decompression is the root cause of
// "Premature close" / ECONNRESET flakiness in CI. A fresh connection per
// request (keepAlive: false) + skipping the Gunzip stream (compress: false)
// eliminates both failure modes.
const noKeepAliveAgent = new http.Agent({ keepAlive: false });
export const getHeaders = () => {
// On cloud, use email:passcode from cloud-config.json (written by global-setup-alpha1.js)
if (process.env.IS_CLOUD === 'true') {
try {
if (!_cachedCloudConfig) {
const configPath = path.join(process.cwd(), 'playwright-tests', 'utils', 'auth', 'cloud-config.json');
_cachedCloudConfig = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
}
if (_cachedCloudConfig.passcode) {
const basicAuth = Buffer.from(
`${_cachedCloudConfig.userEmail}:${_cachedCloudConfig.passcode}`
).toString('base64');
return {
Authorization: `Basic ${basicAuth}`,
"Content-Type": "application/json",
};
}
} catch (e) {
console.warn('[apiUtils] Failed to read cloud-config.json, falling back to password auth:', e.message);
}
}
const basicAuthCredentials = Buffer.from(
`${process.env["ZO_ROOT_USER_EMAIL"]}:${process.env["ZO_ROOT_USER_PASSWORD"]}`
).toString("base64");
return {
Authorization: `Basic ${basicAuthCredentials}`,
"Content-Type": "application/json",
};
};
export const getIngestionUrl = (orgId, streamName) => {
return `${process.env.INGESTION_URL}/api/${orgId}/${streamName}/_json`;
};
export const sendRequest = async (page, url, payload, headers) => {
// Use Node.js fetch instead of browser fetch to avoid CORS issues with deployed environments
const fetch = (await import('node-fetch')).default;
const response = await fetch(url, {
method: "POST",
headers: headers,
body: JSON.stringify(payload),
compress: false,
agent: noKeepAliveAgent,
});
return await response.json();
};