mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-04 08:09:27 +00:00
test: cut alpha1 querier load from e2e helpers (#15462)
This commit is contained in:
@@ -962,10 +962,26 @@ export class LogsPage {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* True when the current page is this org's logs page and was loaded moments ago, so it has no state to reset.
|
||||
* @param {string} orgId
|
||||
* @param {number} maxAgeMs
|
||||
*/
|
||||
async isFreshLogsPage(orgId, maxAgeMs = 15000) {
|
||||
let url;
|
||||
try { url = new URL(this.page.url()); } catch { return false; }
|
||||
if (!url.pathname.endsWith('/web/logs') || url.searchParams.get('org_identifier') !== orgId) return false;
|
||||
const ageMs = await this.page.evaluate(() => performance.now()).catch(() => Infinity);
|
||||
return ageMs < maxAgeMs;
|
||||
}
|
||||
|
||||
async selectStream(stream, maxRetries = 5, apiWaitMs = null, skipNavigation = false) {
|
||||
// Cloud environments need longer for streams to be indexed after ingestion
|
||||
const effectiveApiWaitMs = apiWaitMs ?? (isCloudEnvironment() ? 120000 : 30000);
|
||||
testLogger.info(`selectStream: Selecting stream: ${stream} (apiWait: ${effectiveApiWaitMs}ms, skipNavigation: ${skipNavigation})`);
|
||||
const orgId = getOrgIdentifier();
|
||||
// Measured before the API wait, which takes time but leaves the UI untouched.
|
||||
const freshLogsPage = !skipNavigation && await this.isFreshLogsPage(orgId);
|
||||
|
||||
// First, wait for the stream to be available via API (skip if apiWaitMs is 0)
|
||||
if (effectiveApiWaitMs > 0) {
|
||||
@@ -982,10 +998,11 @@ export class LogsPage {
|
||||
// Navigate to logs page via URL to ensure fresh stream list.
|
||||
// skipNavigation=true bypasses page.goto when the caller is already
|
||||
// on the logs page and wants to avoid auto-triggering a query.
|
||||
const orgId = getOrgIdentifier();
|
||||
const logsUrl = `${process.env.ZO_BASE_URL}/web/logs?org_identifier=${orgId}`;
|
||||
|
||||
if (!skipNavigation) {
|
||||
if (freshLogsPage) {
|
||||
testLogger.info('selectStream: Logs page just loaded for this org — skipping reload (retries still reload if the stream is missing)');
|
||||
} else if (!skipNavigation) {
|
||||
testLogger.info(`selectStream: Navigating to logs page: ${logsUrl}`);
|
||||
await this.page.goto(logsUrl, { waitUntil: 'domcontentloaded', timeout: 30000 }).catch(() => {});
|
||||
// Wait for the index-dropdown wrapper to mount instead of a hard timeout.
|
||||
@@ -1270,7 +1287,7 @@ export class LogsPage {
|
||||
// Wait for button to leave Cancel/loading state before clicking —
|
||||
// otherwise a click on "Cancel" aborts the in-flight query instead
|
||||
// of starting a fresh one.
|
||||
await this.page.waitForFunction(
|
||||
const settled = await this.page.waitForFunction(
|
||||
(sel) => {
|
||||
const b = document.querySelector(sel);
|
||||
if (!b) return false;
|
||||
@@ -1280,8 +1297,13 @@ export class LogsPage {
|
||||
},
|
||||
this.queryButton,
|
||||
{ timeout: 30000 },
|
||||
).catch(() => {});
|
||||
await queryBtn.click();
|
||||
).then(() => true).catch(() => false);
|
||||
// A retry on a still-busy button would cancel and restart the same search; keep waiting on it instead.
|
||||
if (settled || attempt === 1) {
|
||||
await queryBtn.click();
|
||||
} else {
|
||||
testLogger.debug(`selectRunQuery: search still running on attempt ${attempt} — waiting instead of re-clicking`);
|
||||
}
|
||||
|
||||
try {
|
||||
await this.page.waitForSelector('[data-test="logs-search-result-logs-table"]', {
|
||||
|
||||
@@ -113,7 +113,7 @@ test.describe("dashboard UI testcases", () => {
|
||||
// we toggle JSON rendering on the field — mirrors test 4's pattern,
|
||||
// which avoids the race between the v-model toggle on
|
||||
// `fields.showFieldAsJson` and the first panel-schema build.
|
||||
await pm.dateTimeHelper.setRelativeTimeRange("6-w");
|
||||
await pm.dateTimeHelper.setRelativeTimeRange("1-h");
|
||||
await pm.dashboardPanelActions.applyDashboardBtn();
|
||||
await pm.dashboardPanelActions.waitForChartToRender();
|
||||
|
||||
@@ -181,7 +181,7 @@ test.describe("dashboard custom query mode field options testcases", () => {
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Set date-time range
|
||||
await pm.dateTimeHelper.setRelativeTimeRange("6-w");
|
||||
await pm.dateTimeHelper.setRelativeTimeRange("1-h");
|
||||
await pm.dashboardPanelActions.applyDashboardBtn();
|
||||
await pm.dashboardPanelActions.waitForChartToRender();
|
||||
|
||||
@@ -238,7 +238,7 @@ test.describe("dashboard custom query mode field options testcases", () => {
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Set date-time range
|
||||
await pm.dateTimeHelper.setRelativeTimeRange("6-w");
|
||||
await pm.dateTimeHelper.setRelativeTimeRange("1-h");
|
||||
await pm.dashboardPanelActions.applyDashboardBtn();
|
||||
await pm.dashboardPanelActions.waitForChartToRender();
|
||||
|
||||
@@ -295,7 +295,7 @@ test.describe("dashboard custom query mode field options testcases", () => {
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Set date-time range
|
||||
await pm.dateTimeHelper.setRelativeTimeRange("6-w");
|
||||
await pm.dateTimeHelper.setRelativeTimeRange("1-h");
|
||||
await pm.dashboardPanelActions.applyDashboardBtn();
|
||||
await pm.dashboardPanelActions.waitForChartToRender();
|
||||
|
||||
@@ -354,7 +354,7 @@ test.describe("dashboard custom query mode field options testcases", () => {
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Set date-time range
|
||||
await pm.dateTimeHelper.setRelativeTimeRange("6-w");
|
||||
await pm.dateTimeHelper.setRelativeTimeRange("1-h");
|
||||
await pm.dashboardPanelActions.applyDashboardBtn();
|
||||
await pm.dashboardPanelActions.waitForChartToRender();
|
||||
|
||||
@@ -409,7 +409,7 @@ test.describe("dashboard custom query mode field options testcases", () => {
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Set date-time range
|
||||
await pm.dateTimeHelper.setRelativeTimeRange("6-w");
|
||||
await pm.dateTimeHelper.setRelativeTimeRange("1-h");
|
||||
await pm.dashboardPanelActions.applyDashboardBtn();
|
||||
await pm.dashboardPanelActions.waitForChartToRender();
|
||||
|
||||
|
||||
@@ -102,8 +102,7 @@ test.describe("Logs Page testcases", () => {
|
||||
}, async ({ page }) => {
|
||||
testLogger.info('Testing VRL query execution with valid text');
|
||||
await pm.logsPage.clickDateTimeButton();
|
||||
await pm.logsPage.waitForRelative6WeeksButtonVisible();
|
||||
await pm.logsPage.clickRelative6WeeksButton();
|
||||
await pm.logsPage.clickRelative15MinButton();
|
||||
await applyQueryButton(pm);
|
||||
|
||||
await pm.logsPage.toggleVrlEditor();
|
||||
@@ -125,7 +124,7 @@ test.describe("Logs Page testcases", () => {
|
||||
}, async ({ page }) => {
|
||||
testLogger.info('Testing field list collapse/expand functionality');
|
||||
await pm.logsPage.clickDateTimeButton();
|
||||
await pm.logsPage.clickRelative6WeeksButton();
|
||||
await pm.logsPage.clickRelative15MinButton();
|
||||
await pm.logsPage.clickShowQueryToggle();
|
||||
await pm.logsPage.clickFieldListCollapseButton();
|
||||
await page.waitForLoadState('domcontentloaded'); // Replace hard wait
|
||||
@@ -140,7 +139,7 @@ test.describe("Logs Page testcases", () => {
|
||||
}, async ({ page }) => {
|
||||
testLogger.info('Testing saved views name validation with special characters');
|
||||
await pm.logsPage.clickDateTimeButton();
|
||||
await pm.logsPage.clickRelative6WeeksButton();
|
||||
await pm.logsPage.clickRelative15MinButton();
|
||||
await pm.logsPage.clickShowQueryToggle();
|
||||
await pm.logsPage.clickSavedViewsButton();
|
||||
// Allowed: alphanumeric, spaces, underscores, hyphens (/^[A-Za-z0-9 _-]+$/)
|
||||
@@ -172,8 +171,7 @@ test.describe("Logs Page testcases", () => {
|
||||
}, async ({ page }) => {
|
||||
testLogger.info('Testing logs results display on graph');
|
||||
await pm.logsPage.clickDateTimeButton();
|
||||
await pm.logsPage.waitForRelative6WeeksButtonVisible();
|
||||
await pm.logsPage.clickRelative6WeeksButton();
|
||||
await pm.logsPage.clickRelative15MinButton();
|
||||
await applyQueryButton(pm);
|
||||
await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {}); // Replace long hard wait
|
||||
await pm.logsPage.expectSearchListVisible();
|
||||
@@ -192,7 +190,7 @@ test.describe("Logs Page testcases", () => {
|
||||
testLogger.info('Testing live mode functionality with 5 second interval');
|
||||
await page.route("**/logData.ValueQuery", (route) => route.continue());
|
||||
await pm.logsPage.clickDateTimeButton();
|
||||
await pm.logsPage.clickRelative6WeeksButton();
|
||||
await pm.logsPage.clickRelative15MinButton();
|
||||
await pm.logsPage.clickLiveModeButton();
|
||||
// Wait for the 5-sec live-mode option to be enabled in the dropdown
|
||||
await pm.logsPage.waitForLiveMode5SecReady();
|
||||
|
||||
@@ -1167,7 +1167,7 @@ test.describe("Logs Regression Bug Fixes", () => {
|
||||
// Set wide time range to get more records
|
||||
await pm.logsPage.clickDateTimeButton();
|
||||
await page.waitForTimeout(500);
|
||||
await pm.logsPage.clickRelative6WeeksButton();
|
||||
await pm.logsPage.clickRelative15MinButton();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Run query
|
||||
|
||||
@@ -2,11 +2,16 @@ const testLogger = require('./test-logger.js');
|
||||
const logsdata = require("../../../test-data/logs_data.json");
|
||||
const { getAuthHeaders, getOrgIdentifier } = require('./cloud-auth.js');
|
||||
|
||||
// Rows are stamped at ingest, so a 5-min refresh keeps them inside every 15-min test window.
|
||||
const SHARED_STREAM = 'e2e_automate';
|
||||
const SHARED_STREAM_REFRESH_MS = 5 * 60 * 1000;
|
||||
const lastSharedIngest = new Map();
|
||||
|
||||
/**
|
||||
* Ingest test data into a stream via API using Node.js context (secure)
|
||||
* @param {import('@playwright/test').Page} page - Playwright page object
|
||||
* @param {string} streamName - Name of the stream to ingest data into (default: "e2e_automate")
|
||||
* @returns {Promise<object>} - API response
|
||||
* @returns {Promise<object>} - API response, or `{ skipped: true }` when this worker refreshed the shared stream within the last 5 min
|
||||
*/
|
||||
async function ingestTestData(page, streamName = "e2e_automate") {
|
||||
const orgId = getOrgIdentifier();
|
||||
@@ -15,11 +20,19 @@ async function ingestTestData(page, streamName = "e2e_automate") {
|
||||
? process.env.INGESTION_URL.slice(0, -1)
|
||||
: process.env.INGESTION_URL;
|
||||
|
||||
const sharedKey = `${orgId}:${streamName}`;
|
||||
const lastIngest = streamName === SHARED_STREAM ? lastSharedIngest.get(sharedKey) : undefined;
|
||||
if (lastIngest && Date.now() - lastIngest < SHARED_STREAM_REFRESH_MS) {
|
||||
testLogger.debug('Test data ingestion skipped — this worker refreshed the shared stream recently', { streamName, ageMs: Date.now() - lastIngest });
|
||||
return { skipped: true };
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await page.request.post(`${baseUrl}/api/${orgId}/${streamName}/_json`, {
|
||||
headers: headers,
|
||||
data: logsdata
|
||||
});
|
||||
if (response.ok() && streamName === SHARED_STREAM) lastSharedIngest.set(sharedKey, Date.now());
|
||||
|
||||
const responseData = await response.json().catch(() => ({ error: 'Failed to parse JSON' }));
|
||||
testLogger.debug('Test data ingestion response', { response: responseData, streamName });
|
||||
|
||||
@@ -560,16 +560,18 @@ async function performGlobalIngestion(page) {
|
||||
const maxWaitMs = 90000;
|
||||
const pollIntervalMs = 3000;
|
||||
const startTime = Date.now();
|
||||
let lastSeen = 'no response';
|
||||
|
||||
while (Date.now() - startTime < maxWaitMs) {
|
||||
try {
|
||||
const streamsResult = await page.evaluate(async ({ orgId, headers }) => {
|
||||
const r = await fetch(`/api/${orgId}/streams?type=logs&page_num=0&page_size=1000`, { headers });
|
||||
const r = await fetch(`/api/${orgId}/streams?type=logs&keyword=e2e_automate`, { headers });
|
||||
if (!r.ok) return { ok: false, status: r.status };
|
||||
const data = await r.json();
|
||||
const names = (data.list || []).map(s => s.name);
|
||||
return { ok: true, names };
|
||||
return { ok: true, status: r.status, names };
|
||||
}, { orgId, headers });
|
||||
lastSeen = `HTTP ${streamsResult.status}, names=[${(streamsResult.names || []).join(',')}]`;
|
||||
|
||||
if (streamsResult.ok) {
|
||||
const hasE2e = streamsResult.names.includes('e2e_automate');
|
||||
@@ -589,7 +591,7 @@ async function performGlobalIngestion(page) {
|
||||
}
|
||||
|
||||
if (Date.now() - startTime >= maxWaitMs) {
|
||||
testLogger.warn(`[alpha1] Streams not fully indexed after ${maxWaitMs}ms — tests may fail on stream selection`);
|
||||
testLogger.warn(`[alpha1] Streams not fully indexed after ${maxWaitMs}ms (last: ${lastSeen}) — tests may fail on stream selection`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -709,25 +711,28 @@ async function performGlobalIngestionWithFetch() {
|
||||
const maxWaitMs = 90000;
|
||||
const pollIntervalMs = 3000;
|
||||
const startTime = Date.now();
|
||||
let lastSeen = 'no response';
|
||||
|
||||
while (Date.now() - startTime < maxWaitMs) {
|
||||
try {
|
||||
const r = await fetch(`${baseUrl}/api/${orgId}/streams?type=logs&page_num=0&page_size=1000`, { headers });
|
||||
const r = await fetch(`${baseUrl}/api/${orgId}/streams?type=logs&keyword=e2e_automate`, { headers });
|
||||
lastSeen = `HTTP ${r.status}`;
|
||||
if (r.ok) {
|
||||
const data = await r.json();
|
||||
const names = (data.list || []).map(s => s.name);
|
||||
lastSeen += `, names=[${names.join(',')}]`;
|
||||
if (names.includes('e2e_automate')) {
|
||||
testLogger.info(`[alpha1] e2e_automate indexed after ${Date.now() - startTime}ms`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
testLogger.debug(`[alpha1] Error checking streams: ${e.message}`);
|
||||
lastSeen = `error: ${e.message}`;
|
||||
}
|
||||
await new Promise(r => setTimeout(r, pollIntervalMs));
|
||||
}
|
||||
|
||||
testLogger.warn(`[alpha1] Streams not fully indexed after ${maxWaitMs}ms — tests may fail on stream selection`);
|
||||
testLogger.warn(`[alpha1] Streams not fully indexed after ${maxWaitMs}ms (last: ${lastSeen}) — tests may fail on stream selection`);
|
||||
}
|
||||
|
||||
module.exports = globalSetup;
|
||||
|
||||
Reference in New Issue
Block a user