mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-05 16:10:43 +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".
122 lines
5.1 KiB
JavaScript
122 lines
5.1 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* build-ci-matrix.js — single source of truth for the Playwright UI shard matrix.
|
|
*
|
|
* Prints a GitHub Actions matrix object: {"include":[ {testfolder,actual_folder,browser,run_files}, ... ]}
|
|
* consumed by `strategy.matrix: ${{ fromJSON(needs.generate_matrix.outputs.matrix) }}`.
|
|
*
|
|
* Usage:
|
|
* node build-ci-matrix.js <base.json> # OSS: base manifest verbatim
|
|
* node build-ci-matrix.js <base.json> <overlay.json> # ENT: base + enterprise overlay
|
|
*
|
|
* The base (OSS tests/ui-testing/ci-matrix/ci_matrix.json) is the ONLY place shared shards are
|
|
* listed. ENT never re-lists shared specs — its overlay (ci_matrix.ent.json) carries
|
|
* only the delta, so a spec added to OSS flows into ENT automatically:
|
|
* { "append": { "<testfolder>": ["extra.spec.js", ...] }, // add ENT-only specs to a shared shard
|
|
* "shards": [ {testfolder,actual_folder,browser,run_files} ], // whole ENT-only shards (Workflows, SDR…)
|
|
* "disabled": { "<testfolder>": [{file,reason}, ...] } } // ENT-only specs turned off (doc only)
|
|
*
|
|
* DISABLING A SPEC (JSON has no // comments): don't delete it — move it into a
|
|
* shard's "disabled": [{ "file": "x.spec.js", "reason": "why" }] array. Disabled
|
|
* entries are documentation only: this script never emits them, so they don't run,
|
|
* but the record + reason survive. "_comment" (or any _-prefixed key) is also ignored.
|
|
*
|
|
* This lives in OSS so ENT can reuse it from its tree-merged OSS checkout.
|
|
*/
|
|
const fs = require("fs");
|
|
|
|
function die(msg) {
|
|
process.stderr.write(`build-ci-matrix: ${msg}\n`);
|
|
process.exit(1);
|
|
}
|
|
|
|
function readJson(path) {
|
|
try {
|
|
return JSON.parse(fs.readFileSync(path, "utf8"));
|
|
} catch (e) {
|
|
die(`cannot read/parse ${path}: ${e.message}`);
|
|
}
|
|
}
|
|
|
|
const [basePath, overlayPath] = process.argv.slice(2);
|
|
if (!basePath) die("usage: build-ci-matrix.js <base.json> [overlay.json]");
|
|
|
|
const base = readJson(basePath);
|
|
if (!Array.isArray(base)) die(`base ${basePath} must be a JSON array of shards`);
|
|
|
|
// Deep-copy base so we never mutate the parsed source objects.
|
|
const include = base.map((s) => ({ ...s, run_files: [...(s.run_files || [])] }));
|
|
const byFolder = new Map(include.map((s) => [s.testfolder, s]));
|
|
|
|
if (overlayPath) {
|
|
const overlay = readJson(overlayPath);
|
|
|
|
// append: add enterprise-only specs to an EXISTING shared shard.
|
|
for (const [folder, specs] of Object.entries(overlay.append || {})) {
|
|
const shard = byFolder.get(folder);
|
|
if (!shard) {
|
|
die(`overlay append targets unknown folder "${folder}" — it must exist in the base manifest`);
|
|
}
|
|
for (const spec of specs) {
|
|
if (shard.run_files.includes(spec)) {
|
|
die(`overlay append: "${spec}" already in base shard "${folder}" — remove it from the overlay`);
|
|
}
|
|
shard.run_files.push(spec);
|
|
}
|
|
}
|
|
|
|
// shards: whole enterprise-only shards (Workflows, SDR-Logs, SDR-Traces, …).
|
|
for (const shard of overlay.shards || []) {
|
|
if (byFolder.has(shard.testfolder)) {
|
|
die(`overlay shard "${shard.testfolder}" collides with a base shard — use "append" instead`);
|
|
}
|
|
const copy = { browser: "chrome", ...shard, run_files: [...(shard.run_files || [])] };
|
|
include.push(copy);
|
|
byFolder.set(copy.testfolder, copy);
|
|
}
|
|
|
|
// disabled: enterprise-only turned-off specs, recorded against a shard for docs only.
|
|
for (const [folder, entries] of Object.entries(overlay.disabled || {})) {
|
|
const shard = byFolder.get(folder);
|
|
if (!shard) die(`overlay disabled targets unknown folder "${folder}"`);
|
|
shard.disabled = [...(shard.disabled || []), ...entries];
|
|
}
|
|
}
|
|
|
|
// Sanity: unique testfolders, no empty shards, no dup specs, and no spec both
|
|
// active (run_files) and disabled in the same shard.
|
|
const seen = new Set();
|
|
for (const s of include) {
|
|
if (!s.testfolder) die(`shard missing testfolder: ${JSON.stringify(s)}`);
|
|
if (seen.has(s.testfolder)) die(`duplicate testfolder "${s.testfolder}"`);
|
|
seen.add(s.testfolder);
|
|
if (!s.actual_folder) s.actual_folder = s.testfolder;
|
|
if (!s.run_files || s.run_files.length === 0) die(`shard "${s.testfolder}" has no run_files`);
|
|
if (new Set(s.run_files).size !== s.run_files.length) {
|
|
die(`shard "${s.testfolder}" has duplicate run_files`);
|
|
}
|
|
for (const d of s.disabled || []) {
|
|
if (s.run_files.includes(d.file)) {
|
|
die(`shard "${s.testfolder}": "${d.file}" is in both run_files and disabled`);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Emit ONLY the fields the CI matrix consumes — disabled/_comment/notes are stripped,
|
|
// so turned-off specs never reach `npx playwright test`.
|
|
//
|
|
// quick_mode_enabled is always emitted (defaulting to "false") so every shard
|
|
// carries the key: the workflow feeds it to ZO_QUICK_MODE_ENABLED when starting
|
|
// that shard's OpenObserve process. The flag is read once at server start, so it
|
|
// cannot vary per test — a shard is the smallest unit that can change it.
|
|
const matrix = include.map((s) => ({
|
|
testfolder: s.testfolder,
|
|
actual_folder: s.actual_folder,
|
|
browser: s.browser || "chrome",
|
|
run_files: s.run_files,
|
|
quick_mode_enabled:
|
|
s.quick_mode_enabled === true || s.quick_mode_enabled === "true" ? "true" : "false",
|
|
}));
|
|
|
|
process.stdout.write(JSON.stringify({ include: matrix }));
|