mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-04 08:09:27 +00:00
## Summary Adds **10 E2E tests** covering the two defects fixed in #13244, plus the `SELECT *` behaviour change that shipped alongside them. Also introduces per-shard backend configuration so the `SELECT *` tests can actually run in CI. ## Test coverage ### `logsVisualizePersistence.spec.js` — 7 tests (quick mode **off**) | # | Test | Defect | Fix code exercised | |---|---|---|---| | 1 | Renders without the false required-fields error | A | `convertPanelData.ts` `!query?.customQuery` | | 2 | Restores chart type, query and chart after URL refresh (h-bar) | B | `setupLogsTab` re-run + `isInitialVisualizeRestore` | | 3 | Re-renders after reload with the default chart type | B | permanent No-Data half | | 4 | Restores a non-default chart type (area) after refresh | B | `restoreVisualizationFromUrlOnLoad()` | | 5 | Chart still renders after reload with a VRL function applied | B | `prepareVisualizeMode()` VRL copy | | 6 | Never shows required-fields error toggling Visualize → Logs → Visualize | A | manual-toggle rebuild path | | 7 | No `SELECT *` toast opening Visualize with no stream in the URL | B | page-load ordering guard | **Defect A** — false "Please select required fields to render the chart" on the custom-query Timechart panel. **Defect B** — URL refresh produced a `SELECT *` toast plus permanent No Data. ### `logsVisualizeSelectStar.spec.js` — 3 tests (quick mode **on**, dedicated shard) | # | Test | Behaviour verified | Call site | |---|---|---|---| | 8 | Table chart on `SELECT *` → toast shown **and** chart type reverts | Table is blocked | `Index.vue:2265` (watcher) | | 9 | Histogram chart on `SELECT *` → no toast, renders | Line/bar/area/scatter allowed | entry path | | 10 | `SELECT *` line chart survives browser refresh → no toast, state restored | Restore path doesn't re-emit | `Index.vue:2465` (restore) | ## Infrastructure changes | File | Change | Why | |---|---|---| | `ci_matrix.json` | New `Logs-SelectStar` shard with `quick_mode_enabled: "true"` | `isSelectStarForTable()` only exists when the server runs with quick mode on | | `playwright.yml` | Per-shard `ZO_QUICK_MODE_ENABLED` env on `Start OpenObserve` | The flag is read once at server start — a shard is the smallest unit that can vary it | | `build-ci-matrix.js` | Emit `quick_mode_enabled` (defaults `"false"`) | The field was being silently stripped by the emit whitelist | | `logsPage.js` | 13 assertion helpers + fixed chart-type detection | Detection read `data-selected` off the wrong element and matched retired CSS classes, so it always returned `null` | All 24 existing shards are unaffected — they omit the field and default to `false`. ## Notes on test quality - Every negative assertion ("no toast", "no error") is sequenced after a deterministic positive end-state, and gated on a precondition so it cannot pass vacuously. - Toast absence is proved with a MutationObserver recorder installed before the navigation under test, since toasts auto-dismiss. - The quick-mode precondition is a hard assertion, not `test.skip` — a misconfigured shard fails loudly instead of silently reporting "skipped".
212 lines
10 KiB
JavaScript
212 lines
10 KiB
JavaScript
const { test, expect, navigateToBase } = require('../utils/enhanced-baseFixtures.js');
|
|
const testLogger = require('../utils/test-logger.js');
|
|
const PageManager = require('../../pages/page-manager.js');
|
|
const logData = require("../../fixtures/log.json");
|
|
const { ingestTestData: _ingestData } = require('../utils/data-ingestion.js');
|
|
const { getOrgIdentifier } = require('../utils/cloud-auth.js');
|
|
|
|
// ============================================================================
|
|
// SELECT * handling on the logs Visualize tab — PR #13244 / issue #12897.
|
|
//
|
|
// The old code blocked SELECT * for EVERY chart type, before the chart type was
|
|
// even finalised. The fix replaces that with isSelectStarForTable(): only the
|
|
// table chart is blocked (it renders the raw query columns), while histogram-
|
|
// based charts (line/bar/area/scatter) render histogram(_timestamp)/count(*)
|
|
// and legitimately ignore the SELECT columns.
|
|
//
|
|
// WHY THIS IS ITS OWN SPEC FILE:
|
|
// isSelectStarForTable() short-circuits to false unless the SERVER was started
|
|
// with ZO_QUICK_MODE_ENABLED=true. That flag is read once at process start, so
|
|
// it cannot vary between tests sharing a backend. CI gives each matrix shard its
|
|
// own OpenObserve process, so this file is pinned to its own shard in
|
|
// ci-matrix/ci_matrix.json with quick_mode_enabled: "true"; every other shard
|
|
// omits the field and keeps the default (false). Keep these tests here rather
|
|
// than folding them back into logsVisualizePersistence.spec.js, or they will
|
|
// silently skip.
|
|
// ============================================================================
|
|
|
|
// ----- Helpers -----
|
|
|
|
async function ingestTestData(page) {
|
|
await _ingestData(page);
|
|
}
|
|
|
|
// ----- Test Suite -----
|
|
|
|
test.describe("Logs Visualize SELECT * handling testcases", () => {
|
|
test.describe.configure({ mode: 'parallel' });
|
|
let pm;
|
|
|
|
test.beforeEach(async ({ page }, testInfo) => {
|
|
testLogger.testStart(testInfo.title, testInfo.file);
|
|
await navigateToBase(page);
|
|
pm = new PageManager(page);
|
|
await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {});
|
|
await ingestTestData(page);
|
|
await page.waitForLoadState('domcontentloaded');
|
|
await page.goto(
|
|
`${logData.logsUrl}?org_identifier=${getOrgIdentifier()}`
|
|
);
|
|
await pm.logsPage.selectStream("e2e_automate");
|
|
await pm.logsPage.applyQueryAndWaitForSearchResponse();
|
|
await page.waitForLoadState('networkidle', { timeout: 10000 }).catch(() => {});
|
|
|
|
// Fail loudly rather than skip: this shard exists precisely to run with quick
|
|
// mode on, so a false here means the shard is misconfigured (or the matrix
|
|
// entry was lost) and the coverage has silently evaporated.
|
|
expect(
|
|
await pm.logsPage.isQuickModeEnabledOnInstance(),
|
|
'This spec requires the backend to run with ZO_QUICK_MODE_ENABLED=true — ' +
|
|
'check the quick_mode_enabled flag on this shard in ci-matrix/ci_matrix.json'
|
|
).toBe(true);
|
|
|
|
testLogger.info('Test setup completed');
|
|
});
|
|
|
|
test("should block a table chart on a SELECT * query and revert the chart type", {
|
|
tag: ['@logs-visualize-selectstar', '@all', '@logs', '@P0']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing SELECT * table guard (toast + chart type revert)');
|
|
|
|
// 1. SQL mode with an explicit SELECT * — in SQL mode
|
|
// getEffectiveVisualizeQuery() returns the raw query, so this is
|
|
// deterministically a select-all (quick mode cannot rewrite it).
|
|
await pm.logsPage.enableSQLMode();
|
|
await pm.logsPage.typeQuery('SELECT * FROM "e2e_automate"');
|
|
await pm.logsPage.applyQueryAndWaitForSearchResponse();
|
|
|
|
// Precondition gate: the editor really holds a select-all. Without this, a
|
|
// failure to enter SQL mode would surface as the confusing "expected a toast,
|
|
// none emitted" below instead of pointing at the actual cause.
|
|
await pm.logsPage.expectQueryEditorContainsText('SELECT * FROM');
|
|
|
|
// 2. Open Visualize — a histogram chart type is selected by default and must render.
|
|
await pm.logsPage.clickVisualizeToggle();
|
|
await pm.logsPage.expectVisualizeTabContentVisible();
|
|
await pm.logsPage.expectVisualizeChartRendered();
|
|
|
|
// 3. Record the chart type the panel settled on; the revert must return to it.
|
|
const typeBeforeTable = await pm.logsPage.waitForChartTypeStabilized();
|
|
expect(typeBeforeTable, 'a chart type should be selected before switching').toBeTruthy();
|
|
expect(typeBeforeTable).not.toBe('table');
|
|
|
|
// 4. Attempt to switch to the table chart with the recorder armed.
|
|
await pm.logsPage.startToastRecorder();
|
|
await pm.logsPage.selectChartType('table');
|
|
|
|
// 5. The guard fires: toast shown AND the chart type reverts to the previous one.
|
|
await pm.logsPage.expectSelectStarVisualizationToast();
|
|
await pm.logsPage.verifyChartTypeSelected('table', false);
|
|
await pm.logsPage.verifyChartTypeSelected(typeBeforeTable);
|
|
|
|
// 6. The revert must leave a WORKING panel, not a blank one — the guard returns
|
|
// early after reverting, so this proves the previous chart survived intact.
|
|
await pm.logsPage.expectVisualizeChartRendered();
|
|
await pm.logsPage.expectNoDashboardErrors();
|
|
|
|
testLogger.info(`SELECT * table guard fired and reverted to "${typeBeforeTable}"`);
|
|
});
|
|
|
|
test("should allow a histogram chart on a SELECT * query without the SELECT * toast", {
|
|
tag: ['@logs-visualize-selectstar', '@all', '@logs', '@P0']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing SELECT * is allowed for histogram-based charts');
|
|
|
|
// 1. Same SELECT * query that blocks the table chart above.
|
|
await pm.logsPage.enableSQLMode();
|
|
await pm.logsPage.typeQuery('SELECT * FROM "e2e_automate"');
|
|
await pm.logsPage.applyQueryAndWaitForSearchResponse();
|
|
|
|
// Precondition gate — ESSENTIAL here. This test's payload assertion is the
|
|
// ABSENCE of a toast, which passes trivially if the query was never a
|
|
// select-all in the first place (e.g. SQL mode failed to engage and quick mode
|
|
// rewrote it to SELECT <fields>). Verifying the editor holds a select-all is
|
|
// what stops this from becoming a test that can never fail.
|
|
await pm.logsPage.expectQueryEditorContainsText('SELECT * FROM');
|
|
|
|
// 2. Arm the recorder BEFORE entering Visualize — the pre-fix code emitted the
|
|
// toast on entry, ahead of any chart-type choice, so recording from here is
|
|
// what makes this fail on the unfixed build.
|
|
await pm.logsPage.startToastRecorder();
|
|
await pm.logsPage.clickVisualizeToggle();
|
|
await pm.logsPage.expectVisualizeTabContentVisible();
|
|
await pm.logsPage.expectVisualizeChartRendered();
|
|
|
|
// 3. Explicitly pick a histogram-based chart type and confirm it renders.
|
|
await pm.logsPage.selectChartType('line');
|
|
await pm.logsPage.verifyChartTypeSelected('line');
|
|
await pm.logsPage.expectVisualizeChartRendered();
|
|
|
|
// 4. No SELECT * toast at any point, and no error panel.
|
|
await pm.logsPage.expectNoSelectStarVisualizationToast();
|
|
await pm.logsPage.expectNoDashboardErrors();
|
|
|
|
testLogger.info('SELECT * rendered on a line chart with no toast');
|
|
});
|
|
|
|
test("should keep a SELECT * line chart rendered after a browser refresh without the SELECT * toast", {
|
|
tag: ['@logs-visualize-selectstar', '@all', '@logs', '@P0']
|
|
}, async ({ page }) => {
|
|
testLogger.info('Testing SELECT * + histogram chart survives a URL refresh');
|
|
|
|
// 1. SELECT * in SQL mode, same as the tests above.
|
|
await pm.logsPage.enableSQLMode();
|
|
await pm.logsPage.typeQuery('SELECT * FROM "e2e_automate"');
|
|
await pm.logsPage.applyQueryAndWaitForSearchResponse();
|
|
|
|
// Precondition gate — the post-refresh "no toast" assertion below is a negative,
|
|
// so it would pass trivially if this were never a select-all query.
|
|
await pm.logsPage.expectQueryEditorContainsText('SELECT * FROM');
|
|
|
|
// 2. Render a histogram-based chart (allowed for SELECT * by the fix).
|
|
await pm.logsPage.clickVisualizeToggle();
|
|
await pm.logsPage.expectVisualizeTabContentVisible();
|
|
await pm.logsPage.expectVisualizeChartRendered();
|
|
await pm.logsPage.selectChartType('line');
|
|
await pm.logsPage.verifyChartTypeSelected('line');
|
|
await pm.logsPage.expectVisualizeChartRendered();
|
|
|
|
// 3. Gate on the URL sync so the reload actually exercises URL restoration,
|
|
// and capture the payload to compare against the restored state.
|
|
await pm.logsPage.waitForVisualizeUrlState();
|
|
const configBeforeRefresh = await pm.logsPage.getVisualizationDataFromUrl();
|
|
expect(configBeforeRefresh, 'visualization_data should be present before refresh').toBeTruthy();
|
|
expect(configBeforeRefresh.type).toBe('line');
|
|
|
|
// 4. Refresh with the recorder armed — the restore path re-runs the
|
|
// visualization, which is where a spurious SELECT * toast would surface.
|
|
await pm.logsPage.startToastRecorder();
|
|
await page.reload();
|
|
await page.waitForLoadState('domcontentloaded');
|
|
|
|
// 5. The chart comes back: same type, actually painted, not the No Data state.
|
|
await pm.logsPage.expectVisualizeTabContentVisible();
|
|
await pm.logsPage.verifyChartTypeSelected('line');
|
|
await pm.logsPage.expectVisualizeChartRendered();
|
|
|
|
// 6. The SELECT * query itself survived the refresh.
|
|
await pm.logsPage.expectQueryEditorContainsText('SELECT * FROM');
|
|
|
|
// 7. The core assertion: the visualization already rendered successfully, so the
|
|
// restore must NOT re-emit the SELECT * message. Only the table chart is
|
|
// guarded, and the restored type is line.
|
|
await pm.logsPage.expectNoSelectStarVisualizationToast();
|
|
await pm.logsPage.expectNoRequiredFieldsError();
|
|
await pm.logsPage.expectNoDashboardErrors();
|
|
|
|
// 8. Panel config survived too — after load the app rewrites visualization_data
|
|
// from its restored in-memory panel, so an equal payload proves the restore
|
|
// repopulated state rather than the query string merely surviving.
|
|
await expect
|
|
.poll(async () => (await pm.logsPage.getVisualizationDataFromUrl())?.type, {
|
|
timeout: 20000,
|
|
message: 'visualization_data was not rewritten after refresh',
|
|
})
|
|
.toBe('line');
|
|
const configAfterRefresh = await pm.logsPage.getVisualizationDataFromUrl();
|
|
expect(configAfterRefresh.config).toEqual(configBeforeRefresh.config);
|
|
|
|
testLogger.info('SELECT * line chart restored after refresh with no toast');
|
|
});
|
|
});
|