mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-30 19:12:45 +03:00
Compare commits
6 Commits
fix/11787-
...
fix/releas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c26216b85 | ||
|
|
3f3cb0392a | ||
|
|
767d846a44 | ||
|
|
2af28c4e2c | ||
|
|
6f1f1668dd | ||
|
|
8aa3f1e5ab |
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@@ -976,7 +976,11 @@ jobs:
|
||||
# 10min was sized before #7114 added the lcov reporter (Codecov/Sonar need it);
|
||||
# merging 8 shard JSONs + text+json+lcov now takes ~10-12min — three consecutive
|
||||
# release-tip runs died at exactly 10m as job-timeout "cancelled" (2026-07-15/16).
|
||||
timeout-minutes: 20
|
||||
# 30, not 20 (2026-08-29): the informational Codecov upload below hung for the rest of
|
||||
# the budget on two consecutive main runs (33207760653, 33215115341); the job ended
|
||||
# `cancelled` and dragged the whole run's conclusion to `cancelled` although every
|
||||
# blocking job was green. The upload step now has its own ceiling; this is headroom.
|
||||
timeout-minutes: 30
|
||||
needs: test-unit
|
||||
if: ${{ !cancelled() && needs.test-unit.result == 'success' && !contains(github.event.pull_request.labels.*.name, 'hotfix') }}
|
||||
env:
|
||||
@@ -1055,6 +1059,10 @@ jobs:
|
||||
# (if-no-files-found: warn) — Sonar consumes the same file.
|
||||
- name: Upload coverage to Codecov (informational)
|
||||
if: always()
|
||||
# Informational means informational: its own ceiling and continue-on-error, so a
|
||||
# stalled upload can neither eat the job's budget nor turn a green job cancelled.
|
||||
timeout-minutes: 5
|
||||
continue-on-error: true
|
||||
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
|
||||
with:
|
||||
files: coverage/lcov.info
|
||||
|
||||
23
.github/workflows/electron-release.yml
vendored
23
.github/workflows/electron-release.yml
vendored
@@ -4,12 +4,21 @@ on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
# A dispatch builds the ref it is dispatched ON (`gh workflow run … --ref v3.8.50` rebuilds
|
||||
# that tag; `--ref main` builds the repaired line). The ref is deliberately NOT an input:
|
||||
# CodeQL flags an input-controlled checkout next to the npm cache on the default branch as
|
||||
# cache poisoning (actions/cache-poisoning/poisonable-step), and `github.ref` is trusted.
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: "Release version (e.g., v1.6.8)"
|
||||
required: true
|
||||
type: string
|
||||
publish_npm:
|
||||
description: "Also run the npm publish leg (turn off when re-attaching desktop assets to a release whose npm package already shipped)"
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
|
||||
# Least-privilege default: read-only at the top level; each job grants the writes it
|
||||
# needs (build/release upload assets, publish-npm forwards npm provenance / packages
|
||||
@@ -404,7 +413,10 @@ jobs:
|
||||
tag_name: ${{ needs.validate.outputs.version }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
generate_release_notes: true
|
||||
# Only on the tag push. A re-attach dispatch runs against a release whose curated
|
||||
# notes already exist, and `true` APPENDS GitHub's auto-generated "What's Changed"
|
||||
# block to them (v3.8.50, run 33238093090: +1,416 chars on a 121 KB body).
|
||||
generate_release_notes: ${{ github.event_name != 'workflow_dispatch' }}
|
||||
fail_on_unmatched_files: false
|
||||
files: |
|
||||
release-assets/*.dmg
|
||||
@@ -462,11 +474,20 @@ jobs:
|
||||
publish-npm:
|
||||
name: Publish to npm
|
||||
needs: [validate, release]
|
||||
# A re-dispatch that only re-attaches desktop assets must not publish the npm package again.
|
||||
if: ${{ github.event_name != 'workflow_dispatch' || inputs.publish_npm }}
|
||||
permissions:
|
||||
# Must be `write`, not `read`: this job calls the reusable npm-publish.yml whose
|
||||
# `publish` job needs `contents: write` (gh release upload — attach the SBOM, #3874).
|
||||
# A reusable workflow's job cannot request more permission than the caller grants,
|
||||
# so a `read` here makes GitHub reject the run at startup (startup_failure).
|
||||
#
|
||||
# `actions: read` for the same reason: the called `publish` job downloads the next-build
|
||||
# artefact and requests it. v3.8.50 (run 33005490476) died at startup with "The nested
|
||||
# job 'publish' is requesting 'actions: read', but is only allowed 'actions: none'" — and
|
||||
# because `release` lives in this same workflow, the tag shipped with ZERO assets. Keep
|
||||
# this block a superset of every job's permissions in npm-publish.yml.
|
||||
actions: read
|
||||
contents: write
|
||||
id-token: write # npm provenance (forwarded to the reusable workflow)
|
||||
packages: write # publish to npm.pkg.github.com
|
||||
|
||||
1
changelog.d/fixes/v3850-electron-lockfile-build-ref.md
Normal file
1
changelog.d/fixes/v3850-electron-lockfile-build-ref.md
Normal file
@@ -0,0 +1 @@
|
||||
- Electron release: `electron/package-lock.json` regained the optional `electron-builder-squirrel-windows` subtree (13 entries) that `npm ci` had been refusing as out of sync — the Linux desktop leg died on it — and `electron-release.yml` gained a `build_ref` dispatch input so a release whose tag was cut with the broken lock can have its assets rebuilt from the repaired line
|
||||
1
changelog.d/fixes/v3850-electron-release-assets.md
Normal file
1
changelog.d/fixes/v3850-electron-release-assets.md
Normal file
@@ -0,0 +1 @@
|
||||
- Electron release workflow: the `publish-npm` job now grants `actions: read` to the reusable `npm-publish.yml` it calls (its `publish` job requests it), which is what made GitHub refuse the whole v3.8.50 run at startup and ship the release with zero desktop assets; a `workflow_dispatch` now builds the requested tag instead of the dispatching branch and can skip the npm leg (`publish_npm=false`) when only re-attaching assets
|
||||
@@ -0,0 +1 @@
|
||||
- `Coverage` job on `ci.yml`: the informational Codecov upload gets its own 5-minute ceiling and `continue-on-error`, and the job budget grows from 20 to 30 minutes (the 8-shard c8 merge alone takes ~10) — a stalled upload no longer ends the job `cancelled` and drags a fully green `main` run's conclusion down with it
|
||||
195
electron/package-lock.json
generated
195
electron/package-lock.json
generated
@@ -297,6 +297,45 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/windows-sign": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@electron/windows-sign/-/windows-sign-1.2.2.tgz",
|
||||
"integrity": "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cross-dirname": "^0.1.0",
|
||||
"debug": "^4.3.4",
|
||||
"fs-extra": "^11.1.1",
|
||||
"minimist": "^1.2.8",
|
||||
"postject": "^1.0.0-alpha.6"
|
||||
},
|
||||
"bin": {
|
||||
"electron-windows-sign": "bin/electron-windows-sign.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/windows-sign/node_modules/fs-extra": {
|
||||
"version": "11.4.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.0.tgz",
|
||||
"integrity": "sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/fs-minipass": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
|
||||
@@ -1091,6 +1130,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cross-dirname": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cross-dirname/-/cross-dirname-0.1.0.tgz",
|
||||
"integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
@@ -1411,6 +1459,19 @@
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-builder-squirrel-windows": {
|
||||
"version": "26.15.3",
|
||||
"resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-26.15.3.tgz",
|
||||
"integrity": "sha512-Jc19XPV9y9+2bAdZPkXuVNGNIEFBq9poHC61l8Kv6FdK7DRG3+Ic0rerC0DXOaeHNz8yW0fg/JnF8GQROOF5MA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"app-builder-lib": "26.15.3",
|
||||
"builder-util": "26.15.3",
|
||||
"electron-winstaller": "5.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-publish": {
|
||||
"version": "26.15.3",
|
||||
"resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-26.15.3.tgz",
|
||||
@@ -1445,6 +1506,66 @@
|
||||
"tiny-typed-emitter": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-winstaller": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/electron-winstaller/-/electron-winstaller-5.4.0.tgz",
|
||||
"integrity": "sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@electron/asar": "^3.2.1",
|
||||
"debug": "^4.1.1",
|
||||
"fs-extra": "^7.0.1",
|
||||
"lodash": "^4.17.21",
|
||||
"temp": "^0.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@electron/windows-sign": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-winstaller/node_modules/fs-extra": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
|
||||
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"jsonfile": "^4.0.0",
|
||||
"universalify": "^0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6 <7 || >=8"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-winstaller/node_modules/jsonfile": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||
"integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"optionalDependencies": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/electron-winstaller/node_modules/universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
@@ -2359,6 +2480,20 @@
|
||||
"node": ">= 18"
|
||||
}
|
||||
},
|
||||
"node_modules/mkdirp": {
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.6"
|
||||
},
|
||||
"bin": {
|
||||
"mkdirp": "bin/cmd.js"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
@@ -2622,6 +2757,36 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/postject": {
|
||||
"version": "1.0.0-alpha.6",
|
||||
"resolved": "https://registry.npmjs.org/postject/-/postject-1.0.0-alpha.6.tgz",
|
||||
"integrity": "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"commander": "^9.4.0"
|
||||
},
|
||||
"bin": {
|
||||
"postject": "dist/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postject/node_modules/commander": {
|
||||
"version": "9.5.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
|
||||
"integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "^12.20.0 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/proc-log": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz",
|
||||
@@ -2816,6 +2981,21 @@
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/rimraf": {
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
|
||||
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
|
||||
"deprecated": "Rimraf versions prior to v4 are no longer supported",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"glob": "^7.1.3"
|
||||
},
|
||||
"bin": {
|
||||
"rimraf": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/roarr": {
|
||||
"version": "2.15.4",
|
||||
"resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz",
|
||||
@@ -3071,6 +3251,21 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/temp": {
|
||||
"version": "0.9.4",
|
||||
"resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz",
|
||||
"integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"mkdirp": "^0.5.1",
|
||||
"rimraf": "~2.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/temp-file": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz",
|
||||
|
||||
@@ -123,6 +123,48 @@ function discoverPackagedExecutable() {
|
||||
throw new Error(`Packaged Electron smoke check does not support ${platform()}.`);
|
||||
}
|
||||
|
||||
/**
|
||||
* The packaged app opens SQLite lazily: `/login` (the readiness URL) never touches the
|
||||
* database, so a smoke that only waits for readiness sees no `[DB]` line at all. After
|
||||
* readiness the smoke requests a DB-backed endpoint and waits for evidence that the
|
||||
* database opened. The primary open path does NOT print "[DB] Driver: ..." (only the
|
||||
* recovery path and the sql.js fallback do), so the evidence is any `[DB]`/`[Migration]`
|
||||
* startup line — and the #7592 guard below rejects the fallback's own line explicitly.
|
||||
*/
|
||||
export const DB_TOUCH_PATH = "/api/monitoring/health";
|
||||
export const DB_OPEN_EVIDENCE_PATTERN =
|
||||
/\[DB\] (Driver: |SQLite database ready|Added [^\n]* column|Changing cache_size|cache_size changed)|\[Migration\] (Applied|Pre-migration backup)/;
|
||||
|
||||
export async function waitForDatabaseOpen(getLogs, { timeoutMs = 15_000, pollMs = 250 } = {}) {
|
||||
const startedAt = Date.now();
|
||||
while (Date.now() - startedAt < timeoutMs) {
|
||||
const logs = getLogs();
|
||||
assertNoFatalLogs(logs);
|
||||
if (DB_OPEN_EVIDENCE_PATTERN.test(logs)) return logs;
|
||||
await sleep(pollMs);
|
||||
}
|
||||
throw new Error(
|
||||
`Packaged Electron app logged no [DB]/[Migration] startup line within ${timeoutMs}ms of ` +
|
||||
`touching ${DB_TOUCH_PATH} — the database never opened, so the SQLite driver cannot be verified.`
|
||||
);
|
||||
}
|
||||
|
||||
async function openDatabaseForSmoke({ logs, smokeUrl }) {
|
||||
const touchUrl = new URL(DB_TOUCH_PATH, smokeUrl).toString();
|
||||
try {
|
||||
const response = await fetchWithTimeout(touchUrl, 5_000);
|
||||
console.log(
|
||||
`[electron-smoke] touched ${touchUrl} (HTTP ${response.status}) to open the database`
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(
|
||||
`[electron-smoke] touching ${touchUrl} failed (${error instanceof Error ? error.message : String(error)}) — waiting for the database anyway`
|
||||
);
|
||||
}
|
||||
await waitForDatabaseOpen(() => logs.value);
|
||||
console.log("[electron-smoke] database opened");
|
||||
}
|
||||
|
||||
async function fetchWithTimeout(url, timeoutMs) {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
||||
@@ -450,8 +492,13 @@ export function assertNativeDriverSelected(logs) {
|
||||
);
|
||||
}
|
||||
|
||||
// The primary open path prints no "[DB] Driver: ..." line at all (only the recovery path and
|
||||
// the sql.js fallback do), so a database that demonstrably opened WITHOUT the fallback's own
|
||||
// line is the native driver — that is exactly what #7592 guards.
|
||||
if (DB_OPEN_EVIDENCE_PATTERN.test(logs)) return;
|
||||
|
||||
throw new Error(
|
||||
"Packaged Electron app logs contain no '[DB] Driver: ...' line — cannot confirm which SQLite " +
|
||||
"Packaged Electron app logs show no database activity at all — cannot confirm which SQLite " +
|
||||
"driver loaded."
|
||||
);
|
||||
}
|
||||
@@ -506,7 +553,14 @@ async function waitForReady({ logs, smokeUrl, timeoutMs, settleMs, exitState })
|
||||
* by the single-launch path and the cold-restart (two-launch) path so both
|
||||
* exercise identical spawn/readiness/shutdown behavior.
|
||||
*/
|
||||
async function launchAndCollectLogs({ appExecutable, smokeUrl, dataDir, timeoutMs, settleMs, streamLogs }) {
|
||||
async function launchAndCollectLogs({
|
||||
appExecutable,
|
||||
smokeUrl,
|
||||
dataDir,
|
||||
timeoutMs,
|
||||
settleMs,
|
||||
streamLogs,
|
||||
}) {
|
||||
const smokeEnv = buildSmokeEnv({ dataDir });
|
||||
await assertPortIsFree(smokeUrl);
|
||||
await ensureSmokeEnvDirs(smokeEnv, dataDir);
|
||||
@@ -538,6 +592,8 @@ async function launchAndCollectLogs({ appExecutable, smokeUrl, dataDir, timeoutM
|
||||
|
||||
try {
|
||||
await waitForReady({ logs, smokeUrl, timeoutMs, settleMs, exitState });
|
||||
// Outside waitForReady on purpose: a missing database is a verdict, not a readiness retry.
|
||||
await openDatabaseForSmoke({ logs, smokeUrl });
|
||||
return logs.value;
|
||||
} catch (error) {
|
||||
if (!streamLogs) {
|
||||
@@ -568,7 +624,14 @@ async function main() {
|
||||
!process.env.ELECTRON_SMOKE_DATA_DIR && process.env.ELECTRON_SMOKE_KEEP_DATA !== "1";
|
||||
|
||||
try {
|
||||
await launchAndCollectLogs({ appExecutable, smokeUrl, dataDir, timeoutMs, settleMs, streamLogs });
|
||||
await launchAndCollectLogs({
|
||||
appExecutable,
|
||||
smokeUrl,
|
||||
dataDir,
|
||||
timeoutMs,
|
||||
settleMs,
|
||||
streamLogs,
|
||||
});
|
||||
|
||||
if (!coldRestart) return;
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ import {
|
||||
FATAL_LOG_PATTERNS,
|
||||
LINUX_EXECUTABLE_NAMES,
|
||||
stopApp,
|
||||
waitForDatabaseOpen,
|
||||
DB_TOUCH_PATH,
|
||||
} from "../../scripts/dev/smoke-electron-packaged.mjs";
|
||||
|
||||
test("electron smoke discovers the default Linux executable name", () => {
|
||||
@@ -94,6 +96,46 @@ test("electron smoke flags a cold-restart fallback to the sql.js WASM driver", (
|
||||
test("electron smoke flags startup logs missing any driver selection line", () => {
|
||||
assert.throws(
|
||||
() => assertNativeDriverSelected("[electron] [server] listening on 20128"),
|
||||
/no '\[DB\] Driver: \.\.\.' line/
|
||||
/no database activity/
|
||||
);
|
||||
});
|
||||
|
||||
test("electron smoke waits for database-open evidence after touching a DB-backed endpoint", async () => {
|
||||
assert.equal(DB_TOUCH_PATH, "/api/monitoring/health");
|
||||
let logs = "[electron] [Server] [STARTUP] ready\n";
|
||||
setTimeout(() => {
|
||||
logs += "[electron] [Server] [DB] Added usage_history.combo_strategy column\n";
|
||||
}, 60);
|
||||
const seen = await waitForDatabaseOpen(() => logs, { timeoutMs: 2_000, pollMs: 20 });
|
||||
assert.match(seen, /\[DB\] Added/);
|
||||
});
|
||||
|
||||
test("electron smoke fails clearly when the database never opens", async () => {
|
||||
await assert.rejects(
|
||||
() =>
|
||||
waitForDatabaseOpen(() => "[electron] [Server] [STARTUP] ready\n", {
|
||||
timeoutMs: 120,
|
||||
pollMs: 20,
|
||||
}),
|
||||
/logged no \[DB\]\/\[Migration\] startup line within 120ms/
|
||||
);
|
||||
});
|
||||
|
||||
test("electron smoke driver guard: native line, DB evidence and sql.js fallback", () => {
|
||||
assert.doesNotThrow(() =>
|
||||
assertNativeDriverSelected("[DB] Driver: better-sqlite3 | file: /tmp/x/storage.sqlite\n")
|
||||
);
|
||||
assert.doesNotThrow(() =>
|
||||
assertNativeDriverSelected(
|
||||
"[electron] [Server] [DB] Added call_logs.session_tag column\n[electron] [Server] [Migration] Applied: 046_database_settings\n"
|
||||
)
|
||||
);
|
||||
assert.throws(
|
||||
() => assertNativeDriverSelected("[DB] Driver: sql.js | file: /tmp/x/storage.sqlite\n"),
|
||||
/sql\.js \(WASM\) driver/
|
||||
);
|
||||
assert.throws(
|
||||
() => assertNativeDriverSelected("[STARTUP] nothing here\n"),
|
||||
/no database activity/
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user