mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-03 16:10:21 +00:00
Co-authored-by: Shrinath-O2 <214651540+Shrinath-O2@users.noreply.github.com>
This commit is contained in:
co-authored by
Shrinath-O2
parent
9c0995435c
commit
df9a274df3
@@ -534,7 +534,8 @@
|
||||
"connectDataSourcePopup.spec.js",
|
||||
"splunk-hec-ingestion-window.spec.js",
|
||||
"enrichment.spec.js",
|
||||
"schema.spec.js"
|
||||
"schema.spec.js",
|
||||
"first-event-status.spec.js"
|
||||
],
|
||||
"disabled": []
|
||||
},
|
||||
|
||||
@@ -10,6 +10,9 @@ export class FirstEventPage {
|
||||
this.firstRecord = page.locator('[data-test="first-event-status-first-record"]');
|
||||
this.openBtn = page.locator('[data-test="first-event-status-open-btn"]');
|
||||
this.troubleshootBtn = page.locator('[data-test="first-event-status-troubleshoot-btn"]');
|
||||
this.checkNowBtn = page.locator('[data-test="first-event-status-check-now-btn"]');
|
||||
this.connectSourceBtn = page.locator('[data-test="first-event-status-connect-source-btn"]');
|
||||
this.setupAnotherBtn = page.locator('[data-test="first-event-status-setup-another-btn"]');
|
||||
this.diagnosis = page.locator('[data-test="first-event-diagnosis"]');
|
||||
this.diagnosisFix = page.locator('[data-test="first-event-diagnosis-fix"]');
|
||||
this.diagnosisCopyBtn = page.locator('[data-test="first-event-diagnosis-copy-btn"]');
|
||||
@@ -17,6 +20,7 @@ export class FirstEventPage {
|
||||
this.diagnosisEndpoint = page.locator('[data-test="first-event-diagnosis-endpoint"]');
|
||||
this.stillStuck = page.locator('[data-test="first-event-diagnosis-still-stuck"]');
|
||||
this.docsLink = page.locator('[data-test="first-event-diagnosis-docs-link"]');
|
||||
this.askAiBtn = page.locator('[data-test="first-event-diagnosis-ask-ai-btn"]');
|
||||
this.contactSupportLink = page.locator('[data-test="first-event-diagnosis-contact-support-link"]');
|
||||
this.notice = page.locator('[data-test="first-data-notice"]');
|
||||
this.noticeText = page.locator('[data-test="first-data-notice-text"]');
|
||||
@@ -48,6 +52,10 @@ export class FirstEventPage {
|
||||
await this.troubleshootBtn.click();
|
||||
}
|
||||
|
||||
async clickCheckNow() {
|
||||
await this.checkNowBtn.click();
|
||||
}
|
||||
|
||||
async clickOpen() {
|
||||
await this.openBtn.click();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
const { test, expect, navigateToBase } = require('../utils/enhanced-baseFixtures.js');
|
||||
const testLogger = require('../utils/test-logger.js');
|
||||
const { FirstEventPage } = require('../../pages/generalPages/firstEventPage.js');
|
||||
const {
|
||||
ingest,
|
||||
withFreshOrg,
|
||||
targetProbe,
|
||||
waitForStreamWithRecords,
|
||||
} = require('../utils/first-event-helpers.js');
|
||||
|
||||
test.describe('Ingestion First-Event Status testcases', () => {
|
||||
test.describe.configure({ mode: 'parallel' });
|
||||
|
||||
test.beforeEach(async ({ page }, testInfo) => {
|
||||
testLogger.testStart(testInfo.title, testInfo.file);
|
||||
await navigateToBase(page);
|
||||
testLogger.info('Test setup completed');
|
||||
});
|
||||
|
||||
test('turns green on the curl test guide with test-kind markers and "Connect your real source"', {
|
||||
tag: ['@first-event-status', '@ingestion', '@all', '@P0'],
|
||||
}, async ({ page }) => {
|
||||
testLogger.info('Opening the curl test guide on a fresh org');
|
||||
await withFreshOrg(page, 'fe_curl', async (orgId) => {
|
||||
const fe = new FirstEventPage(page);
|
||||
const baseline = targetProbe(page, 'logs', 'default');
|
||||
await fe.openGuide('/ingestion/custom/logs/curl', orgId);
|
||||
await fe.expectState('waiting');
|
||||
await expect(fe.bar).toHaveAttribute('data-kind', 'test');
|
||||
await baseline;
|
||||
|
||||
await ingest(page, orgId, 'default', [{ level: 'info', log: 'first event e2e curl' }]);
|
||||
await fe.expectState('received', 15000);
|
||||
await expect(fe.bar).toHaveAttribute('data-kind', 'test');
|
||||
await expect(fe.summary).toContainText('default');
|
||||
await expect(fe.firstRecord).toContainText('first event e2e curl');
|
||||
await expect(fe.openBtn).toHaveText(/Open in Logs/);
|
||||
await expect(fe.connectSourceBtn).toBeVisible();
|
||||
await expect(fe.connectSourceBtn).toContainText('Connect your real source');
|
||||
await expect(fe.setupAnotherBtn).toHaveCount(0);
|
||||
testLogger.info('Curl test guide turned green with test-kind markers');
|
||||
});
|
||||
});
|
||||
|
||||
test.fixme('idle state unreachable in e2e: useFirstEventWatch.ts:241 hasRecords reads stream-list doc_num (no SQL COUNT fallback unlike confirmNewStream), which stays 0 until the 10-min memtable TTL flush', {
|
||||
tag: ['@first-event-status', '@ingestion', '@all', '@P1'],
|
||||
}, async ({ page }) => {
|
||||
testLogger.info('Ingesting before mount so the baseline probe sees an existing stream');
|
||||
await withFreshOrg(page, 'fe_idle', async (orgId) => {
|
||||
await ingest(page, orgId, 'default', [{ level: 'info', log: 'pre-existing record' }]);
|
||||
expect(await waitForStreamWithRecords(page, orgId, 'default')).toBe(true);
|
||||
|
||||
const fe = new FirstEventPage(page);
|
||||
await fe.openGuide('/ingestion/custom/logs/curl', orgId);
|
||||
await fe.expectState('idle');
|
||||
await expect(fe.checkNowBtn).toBeVisible();
|
||||
await expect(fe.troubleshootBtn).toHaveCount(0);
|
||||
|
||||
await fe.clickCheckNow();
|
||||
await fe.expectState('waiting');
|
||||
await expect(fe.checkNowBtn).toHaveCount(0);
|
||||
|
||||
await ingest(page, orgId, 'default', [{ level: 'info', log: 'second record after check now' }]);
|
||||
await fe.expectState('received', 15000);
|
||||
await expect(fe.summary).toContainText('default');
|
||||
testLogger.info('Idle held on pre-existing data, then Check now engaged and received');
|
||||
});
|
||||
});
|
||||
|
||||
test('Troubleshoot on a fresh tracked org shows no-requests immediately with org id and endpoint', {
|
||||
tag: ['@first-event-status', '@ingestion', '@all', '@P1'],
|
||||
}, async ({ page }) => {
|
||||
testLogger.info('Opening the fluentbit guide on a fresh, data-free org');
|
||||
await withFreshOrg(page, 'fe_noreq', async (orgId) => {
|
||||
const fe = new FirstEventPage(page);
|
||||
await fe.openGuide('/ingestion/custom/logs/fluentbit', orgId);
|
||||
await fe.expectState('waiting');
|
||||
await fe.clickTroubleshoot();
|
||||
await fe.expectState('no-requests');
|
||||
await fe.expectDiagnosis({ trigger: 'troubleshoot' });
|
||||
await expect(fe.summary).toContainText('Nothing has arrived');
|
||||
await expect(fe.diagnosisOrgId).toHaveText(orgId);
|
||||
await expect(fe.diagnosisEndpoint).not.toHaveText('');
|
||||
await expect(fe.diagnosisFix).toHaveText('Check that your command uses this org id and endpoint.');
|
||||
await expect(fe.diagnosisCopyBtn).toBeVisible();
|
||||
await expect(fe.stillStuck).toContainText('Still stuck?');
|
||||
await expect(fe.docsLink).toBeVisible();
|
||||
await expect(fe.docsLink).toHaveAttribute('target', '_blank');
|
||||
await expect(fe.troubleshootBtn).toHaveCount(0);
|
||||
testLogger.info('Troubleshoot showed no-requests immediately');
|
||||
});
|
||||
});
|
||||
|
||||
test.fixme('Ask AI button — not wired in OSS: FirstEventStatus.vue:360 requires enterprise + ai_enabled', {
|
||||
tag: ['@first-event-status', '@all', '@P2'],
|
||||
}, async ({ page }) => {
|
||||
testLogger.info('Ask AI CTA in the Still stuck row (enterprise + ai_enabled only)');
|
||||
await withFreshOrg(page, 'fe_askai', async (orgId) => {
|
||||
const fe = new FirstEventPage(page);
|
||||
await fe.openGuide('/ingestion/custom/logs/fluentbit', orgId);
|
||||
await fe.expectState('waiting');
|
||||
await fe.clickTroubleshoot();
|
||||
await fe.expectState('no-requests');
|
||||
await expect(fe.askAiBtn).toBeVisible();
|
||||
testLogger.info('Ask AI button visible after diagnosis');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
const { test, expect } = require('@playwright/test');
|
||||
const { getAuthHeaders, authedRequest, isCloudEnvironment } = require('./cloud-auth.js');
|
||||
|
||||
const base = () => process.env.ZO_BASE_URL.replace(/\/$/, '');
|
||||
const ingestionBase = () => (process.env.INGESTION_URL || process.env.ZO_BASE_URL).replace(/\/$/, '');
|
||||
|
||||
async function ingest(page, orgId, stream, records) {
|
||||
const res = await page.request.post(`${ingestionBase()}/api/${orgId}/${stream}/_json`, {
|
||||
headers: getAuthHeaders(),
|
||||
data: records,
|
||||
});
|
||||
expect(res.ok()).toBeTruthy();
|
||||
}
|
||||
|
||||
async function withFreshOrg(page, tag, fn) {
|
||||
const created = await authedRequest(page, 'post', `${base()}/api/organizations`, {
|
||||
data: { name: `e2e_${tag}_${Date.now()}` },
|
||||
});
|
||||
// Cloud creates orgs only through signup, so a non-200 there means this env cannot stage the scenario.
|
||||
test.skip(isCloudEnvironment() && !created.ok(), 'Cloud creates orgs only through signup');
|
||||
expect(created.ok()).toBeTruthy();
|
||||
const body = await created.json();
|
||||
const orgId = body.identifier || (body.data && body.data.identifier);
|
||||
try {
|
||||
await fn(orgId);
|
||||
} finally {
|
||||
await authedRequest(page, 'delete', `${base()}/api/organizations/${orgId}`).catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
// The bar's baseline probe for its own stream, so an ingest never lands before the watch has looked.
|
||||
const targetProbe = (page, type, stream) =>
|
||||
page.waitForResponse(
|
||||
(r) => r.url().includes(`/streams?type=${type}&offset=0&limit=20&keyword=${stream}`),
|
||||
{ timeout: 20000 },
|
||||
);
|
||||
|
||||
// The watcher's idle gate reads doc_num from the stream list (not search), so wait for it to be non-zero.
|
||||
async function waitForStreamWithRecords(page, orgId, streamName, type = 'logs', maxWaitMs = 30000) {
|
||||
const start = Date.now();
|
||||
while (Date.now() - start < maxWaitMs) {
|
||||
const res = await page.request.get(`${ingestionBase()}/api/${orgId}/streams?type=${type}`, {
|
||||
headers: getAuthHeaders(),
|
||||
});
|
||||
if (res.ok()) {
|
||||
const data = await res.json().catch(() => null);
|
||||
const list = Array.isArray(data?.list) ? data.list : [];
|
||||
const row = list.find((s) => s?.name === streamName);
|
||||
if (row && Number(row.stats?.doc_num ?? 0) > 0) return true;
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
module.exports = { ingest, withFreshOrg, targetProbe, waitForStreamWithRecords };
|
||||
Reference in New Issue
Block a user