Files
openobserve/tests/ui-testing/scripts/ingest-service-graph.js
T
befa1883a0 test: add alpha1 cloud compatibility for E2E logs tests (#10763)
## Summary
- Add cloud auth infrastructure (`cloud-env.js`, `cloud-auth.js`) for
cloud/self-hosted switching
- Centralize ingestion auth via `getAuthHeaders()` across all ingestion
utilities (data, trace, service-graph, metrics)
- Refactor `commonActions.js` from `exec(curl)` to `page.request.post()`
for cloud cookie compatibility
- Enhance `cloudLoginPage.js` + `page-manager.js` for conditional cloud
page objects
- Update `global-setup-alpha1.js` to fetch org identifier and passcode
from cloud session
- Fix `global-teardown.js` race condition with proper error handling
- Replace `console.log` with `testLogger` in `commonActions.js`,
`ingest-service-graph.spec.js`, `scripts/ingest-service-graph.js`
- Replace raw selectors with POM methods (`applyQueryButton`, VRL
editor, pagination, time range)
- Add missing test tags to `searchpartition`, `unflattened`,
`ingest-service-graph` specs
- Fix `networkidle` → `domcontentloaded` across multiple spec files

## Companion PR
- Enterprise: sets `IS_CLOUD=true` in alpha1 E2E workflow

## Test plan
- [ ] Self-hosted E2E tests pass (no behavioral changes — only routing
through POM + testLogger)
- [ ] Alpha1 cloud E2E tests pass with cloud auth enabled
- [ ] Verify no credential leaks in logs (passcode/password values never
logged)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Shrinath Rao <undefined@users.noreply.github.com>
2026-03-07 07:00:07 +05:30

147 lines
4.2 KiB
JavaScript

#!/usr/bin/env node
/**
* Standalone service graph data ingestion script.
* Uses native fetch (Node 18+) instead of Playwright page.request.
*
* Usage: node scripts/ingest-service-graph.js
* Reads credentials from ../.env
*/
const path = require('path');
// Load .env from the ui-testing directory
require('dotenv').config({ path: path.join(__dirname, '..', '.env') });
const testLogger = require('../playwright-tests/utils/test-logger.js');
const {
generateFullTopology,
generateAllEdgeCases,
} = require('../playwright-tests/utils/service-graph-ingestion.js');
// Build auth headers — cloud envs use passcode from cloud-config.json
let _headers = null;
function getHeaders() {
if (_headers) return _headers;
const configFile = path.join(__dirname, '..', 'playwright-tests', 'utils', 'auth', 'cloud-config.json');
let email, secret;
try {
const config = JSON.parse(require('fs').readFileSync(configFile, 'utf-8'));
if (config.passcode) {
email = config.userEmail;
secret = config.passcode;
}
} catch (_) { /* no cloud config */ }
if (!email) {
email = process.env.ZO_ROOT_USER_EMAIL;
secret = process.env.ZO_ROOT_USER_PASSWORD;
}
const basicAuth = Buffer.from(`${email}:${secret}`).toString('base64');
_headers = {
'Authorization': `Basic ${basicAuth}`,
'Content-Type': 'application/json',
};
return _headers;
}
function getBaseUrl() {
const url = process.env.INGESTION_URL || process.env.ZO_BASE_URL;
return url.endsWith('/') ? url.slice(0, -1) : url;
}
function getOrgId() {
return process.env.ORGNAME || 'default';
}
async function ingestTrace(traceData) {
const headers = getHeaders();
const baseUrl = getBaseUrl();
const orgId = getOrgId();
const payload = traceData.payload || traceData;
const url = `${baseUrl}/api/${orgId}/v1/traces`;
const response = await fetch(url, {
method: 'POST',
headers,
body: JSON.stringify(payload),
});
return { status: response.status };
}
async function main() {
const baseUrl = getBaseUrl();
const orgId = getOrgId();
testLogger.info('=== Service Graph Data Ingestion ===');
testLogger.info(`Target: ${baseUrl}`);
testLogger.info(`Org: ${orgId}`);
// Step 1: Generate full topology traces
testLogger.info('Generating full topology traces...');
const fullTopologyTraces = generateFullTopology({ tracesPerFlow: 3, errorRate: 0.1 });
testLogger.info(` Generated ${fullTopologyTraces.length} topology traces`);
// Step 2: Generate edge case traces
testLogger.info('Generating edge case traces...');
const edgeCaseTraces = generateAllEdgeCases();
testLogger.info(` Generated ${edgeCaseTraces.length} edge case traces`);
const allTraces = [...fullTopologyTraces, ...edgeCaseTraces];
testLogger.info(`Ingesting ${allTraces.length} total traces...`);
let success = 0;
let failed = 0;
for (let i = 0; i < allTraces.length; i++) {
try {
const result = await ingestTrace(allTraces[i]);
if (result.status === 200) {
success++;
} else {
failed++;
if (failed <= 3) testLogger.warn(`Trace ${i} returned status ${result.status}`);
}
} catch (e) {
failed++;
if (failed <= 3) testLogger.error(`Trace ${i} failed`, { error: e.message });
}
// Small delay between requests
if (i % 10 === 0) {
await new Promise(r => setTimeout(r, 50));
}
}
testLogger.info('=== Ingestion Complete ===');
testLogger.info(`Success: ${success}/${allTraces.length}, Failed: ${failed}/${allTraces.length}`);
// Step 3: Verify topology appears
testLogger.info('Waiting 10s for daemon to process...');
await new Promise(r => setTimeout(r, 10000));
const headers = getHeaders();
try {
const topoResponse = await fetch(
`${baseUrl}/api/${orgId}/traces/service_graph/topology/current`,
{ headers }
);
const topoData = await topoResponse.json();
const data = topoData?.nodes ? topoData : topoData?.data;
testLogger.info(`Topology: ${data?.nodes?.length || 0} nodes, ${data?.edges?.length || 0} edges`);
} catch (e) {
testLogger.error(`Topology check failed`, { error: e.message });
}
testLogger.info('Done!');
}
main().catch(e => {
testLogger.error('Fatal error', { error: e.message });
process.exit(1);
});