Application Update — Manual Test Checklist
End-to-end verification of the "detect update → user consents → self-download/install/restart" flow across all three deployment modes. Each section is self-contained: run it on the target platform with the listed prerequisites.
The unit tests (
UpdateCheckServiceTest,portable-updater.test.ts,auto-updater.test.ts) cover version comparison and detection logic. This checklist verifies the real download → verify → swap → relaunch pipeline, which must be exercised against a real GitHub release or an FY-Proxy intranet repository on the target OS.
Shared prerequisites (all modes)
- Two releases must exist on GitHub so "old" can detect "new":
- An older tagged release you will install/run (e.g.
v4.0.0-beta.1). - A newer tagged release available on the Releases page (e.g.
v4.0.0-beta.4). - The newer release MUST have been built by
fengyu-release.ymlAFTER the changes in this feature landed (solatest*.yml,*.blockmap, andchecksums.txtare published — required by electron-updater and the portable self-updater).
- An older tagged release you will install/run (e.g.
- Confirm the newer release's assets include the ones your mode needs (see below).
- Have the older build installed/extracted and running before you trigger the check.
How to confirm the newer release has the required feed files
Open https://github.com/MuskStark/FengYu/releases/tag/v<NEW_VERSION> and confirm these assets exist (if any is missing, the CI change did not take effect and auto-update cannot work):
| Asset | Required by |
|---|---|
latest.yml (Windows) / latest-mac.yml (macOS) | electron-updater (NSIS install + macOS) |
*.blockmap | electron-updater differential download |
Infinia-<ver>-win32-x64-portable.zip | Windows portable self-update |
Infinia.jar + checksums.txt | Portable Web (java -jar) self-update |
Intranet / offline store channel (the store replaces FY-Proxy)
Set Settings → Update channel → Upgrade channel URL to the Infinia Store origin, for example http://10.0.0.5:8080 (the separately deployed store platform — it replaces the old FY-Proxy distribution center, and the same value also routes plugin installs and cloud-account sign-in), and turn on "Allow private network (self-hosted store)" on the same page — a custom channel (including a localhost debug store) is only active while that toggle is on; with it off the address stays dormant and the store and updates fall back to the official store and GitHub. The value is persisted and loaded before the desktop window opens, so both the startup probe and About → Check for updates avoid GitHub.
The store channel currently serves these asset classes:
| Platform/package | Required asset | Discovery endpoint (relative to the store base) |
|---|---|---|
| Windows portable x64 | STABLE-channel APP release with a Infinia-<version>-win32-x64-portable.zip artifact | /api/v1/compat/fengyu/fengyu-releases/api/releases/latest?channel=windows-portable |
| Debian/Ubuntu lite x64 | legacy FY-Proxy only, until the store ships an electron-updater feed | /fengyu-updates/deb/latest-linux.yml (FY-Proxy contract) |
Publish app releases through the store's publisher flow (an APP listing with versioned releases and artifacts) instead of FY-Proxy's file upload page. For portable ZIP, the release response carries a mandatory SHA-256 digest that Infinia verifies before extraction; the deb feed uses electron-updater's SHA-512 verification. The manual download page becomes the store's web app (/web). Confirm automatic discovery after launch, then use About → Recheck to confirm manual discovery. NSIS, AppImage, macOS, JRE, and portable Web/JAR updates are deliberately unsupported on the store channel.
Mode 1: Windows NSIS install (*-setup.exe)
Platform: Windows 10/11 · Update mechanism: electron-updater
Public GitHub channel only; FY-Proxy rejects NSIS assets.
Setup
- Download and install the older
*-win-x64-setup.exe. - Launch Infinia from the Start menu / desktop shortcut.
Steps
- Open About (sidebar). The "Update" row should show
Version <NEW_VERSION> is availableafter a few seconds (the StatusBar badge also appears). - Click Update now. A confirmation popover appears warning the build is unsigned.
- Click Continue.
- A download progress indicator fills (the
update:progressIPC events flow). - On completion the app quits and the NSIS installer runs silently, then Infinia relaunches.
- Windows SmartScreen MAY warn (unsigned build) — click "More info" → "Run anyway". This is expected for unsigned builds.
- After relaunch, open About again — the version should now read
<NEW_VERSION>, and the "Update" row should say "Up to date".
Pass criteria
- [ ] Update detected on the older build
- [ ] Download progress visible
- [ ] App quits, installer runs, app relaunches
- [ ] New version confirmed in About after relaunch
- [ ] StatusBar badge gone after update
Common failures
| Symptom | Likely cause |
|---|---|
| "Update check failed" in About | latest.yml not published on the release (CI glob missing) |
| Download never starts | signedRelease gating — the consent IPC path should bypass it; check update:download-install is reached (DevTools → Network/Console) |
| App quits but doesn't relaunch | NSIS --updated flow failed; check the installer log in %TEMP% |
Mode 2: Windows portable zip (*-portable.zip)
Platform: Windows 10 1803+ · Update mechanism: custom pipeline (portable-updater.ts)
electron-updater CANNOT update a portable zip — this mode uses a custom download → tar extract → robocopy replace → relaunch pipeline. This is the mode most likely to surface file-lock or single-instance issues, so test it carefully.
Setup
- Download and extract the older
*-win-x64-portable.zipto a folder, e.g.C:\Users\<you>\Infinia\. - Run
C:\Users\<you>\Infinia\Infinia.exe.
Steps
- Open About → the "Update" row detects
<NEW_VERSION>(via the GitHub API or the configured FY-Proxywindows-portablerelease endpoint, notlatest.yml). - Click Update now → Continue (unsigned warning).
- Download progress fills (the portable zip is large; watch the percent).
- The app quits. A detached
.bat(in%TEMP%) takes over:- Waits for the old
Infinia.exePID + backend JVM tree to exit (tasklist polling). - Sweeps any process still running from the install folder (a leaked plugin worker keeps the bundled
resources\jreimage files locked). robocopys the extracted new tree over the install folder, retrying once if destination files were still locked.- Restarts
Infinia.exe.
- Waits for the old
- Infinia relaunches automatically.
Pass criteria
- [ ] Portable detection worked (About shows an update, NOT a silent failure)
- [ ] Download progress visible
- [ ] Old process fully exits before file replacement (no "file in use" error)
- [ ]
Infinia.exe+resources\binaries\FengYu.jar+resources\app.asarall replaced - [ ] App relaunches with the new version (About shows
<NEW_VERSION>) - [ ] No second-instance error on relaunch (single-instance lock released cleanly)
How to inspect the update if it fails
- The detached bat log:
%TEMP%\fengyu-portable-update-<pid>.log - The bat itself (before self-delete):
%TEMP%\fengyu-portable-update-<pid>.bat - Staging dir:
%TEMP%\fengyu-portable-update-*\(extracted new tree) - Run from a cmd window to see console output:
Infinia.exelogs to<runtime>\.fengyu\logs\.
Common failures
| Symptom | Likely cause |
|---|---|
tar extraction failed | Windows older than 10 1803 (no bsdtar); or the zip asset name doesn't contain -portable.zip |
| robocopy reports "file in use" | A process was still running from the install folder (a leaked plugin worker locks the bundled JRE). The replace bat sweeps app-tree processes before copying and retries robocopy once; if it still fails, read the sweep output and robocopy exit code in .fengyu/logs/update.log |
| App relaunches but immediately exits | Single-instance lock not released (old process still alive); or the new exe path differs |
| About never shows an update | isWindowsPortable() returned false — confirm resources\app-update.yml is ABSENT in the portable extract |
Mode 3: Portable Web (java -jar, run.sh / run.bat)
Platform: any (macOS/Linux/Windows) · Update mechanism: backend SelfUpdateService (JAR download → SHA256 verify → detached restart script → JVM exit → swap → relaunch)
This is the only mode testable end-to-end on macOS/Linux. It swaps only the JAR (the launcher scripts and plugins stay put). This mode is available only through GitHub; FY-Proxy rejects JAR assets.
Setup
- Download and extract the older
Infinia-<OLD>-web.zip(or.tar.gz). - Launch it:
- macOS/Linux:
./run.sh - Windows:
run.bat
- macOS/Linux:
- Note the generated token printed to stderr (
Generated per-launch token ...: zf-...). - Open the UI in a browser at the printed URL (or use curl with the token).
Steps
- Open About → "Update" row shows
<NEW_VERSION>is available.- The release MUST have an
Infinia.jarasset AND achecksums.txtasset (both published by the release workflow). Withoutchecksums.txt, the SHA256 verification step fails.
- The release MUST have an
- Click Update now → Continue.
- The backend:
- Downloads
Infinia.jarfrom the release to a staging file. - Downloads
checksums.txt, parses theInfinia.jarline, verifies SHA256. - Generates
self-update.sh(POSIX) orself-update.bat(Windows) into<runtime>\runtime-files\. - Spawns the script detached, then exits the JVM (
System.exitafter a 1s flush delay).
- Downloads
- The detached script:
- Waits for the old JVM PID to exit (
tail --pid=on POSIX /taskliston Windows). - Backs up the old JAR to
Infinia.jar.bak. - Moves the downloaded JAR into place.
- Re-launches
java -jar Infinia.jar <original args>.
- Waits for the old JVM PID to exit (
- The new backend comes up; the browser reconnects (StatusBar dot returns to green).
Pass criteria
- [ ] Update detected (About shows
<NEW_VERSION>) - [ ] Download + SHA256 verification succeed (check the backend log for
[self-update] checksum verified) - [ ] Old JVM exits cleanly (backend log shows context close + shutdown hooks)
- [ ] JAR replaced:
Infinia.jaris the new version,Infinia.jar.bakis the old - [ ] New JVM restarts with the same port/token (UI reconnects without manual action)
- [ ] About now shows
<NEW_VERSION>and "Up to date"
How to inspect the update if it fails
- Backend log:
<extract>\data\logs\(the-Dfengyu.runtime.dir=$ROOT/datalocation). - Restart script:
<extract>\data\runtime-files\self-update.sh(or.bat). - Restart script log:
<extract>\data\runtime-files\self-update-*.log. - Staging download:
<extract>\data\runtime-files\update-staging-*.jar.
Common failures
| Symptom | Likely cause |
|---|---|
SHA-256 mismatch for Infinia.jar | checksums.txt on the release is stale or doesn't match the published JAR |
checksums.txt has no entry for Infinia.jar | The release was built before checksums.txt was added to the CI collect step |
| Old JAR not replaced (still old version after restart) | Detached script wasn't truly detached (process died with the JVM); or java.class.path didn't resolve to the JAR path |
| JVM exits but nothing restarts | Script's relaunch command is wrong — inspect self-update.sh, check the exec java ... line has the right -D flags and --token |
| Restarts but on a different port | The relaunch didn't carry --port=<n> through; sun.java.command parsing in SelfUpdateService.buildRelaunchCommand missed it |
Mode 4: macOS desktop (*-mac-arm64.dmg)
Platform: macOS (Apple Silicon) · Update mechanism: manual download (unsigned Gatekeeper fallback)
macOS unsigned builds CANNOT auto-relaunch after a
quitAndInstall(Gatekeeper blocks the replaced bundle). The app degrades to "download + open releases page". This is intentional until code-signing + notarization lands. FY-Proxy intranet mode does not support macOS.
Setup
- Download and install the older
*-mac-arm64.dmg(drag Infinia to Applications). - On first launch, right-click → Open (to bypass Gatekeeper for the unsigned old build).
- Run Infinia.
Steps
- Open About → "Update" row detects
<NEW_VERSION>.- Note: the About page detects macOS and shows an "Open page" button instead of "Update now" (because the shell's
update:download-installIPC returns{action:'manual'}on darwin).
- Note: the About page detects macOS and shows an "Open page" button instead of "Update now" (because the shell's
- Click Open page → browser opens the GitHub releases page.
- Download the newer
*-mac-arm64.dmgmanually. - Replace the old Infinia.app in /Applications (drag the new one in, agree to replace).
- Right-click → Open the new Infinia (Gatekeeper warning again — unsigned).
Pass criteria
- [ ] Update detected
- [ ] "Open page" button shown (NOT "Update now" — confirms the darwin branch)
- [ ] Releases page opens to the right URL
- [ ] After manual replacement, new version confirmed in About
Future: when code-signing lands
Re-run Mode 4 after a signed+notarized build: the darwin branch in ipc/update.ts should be changed to call downloadUpdate() + quitAndInstall() (same as Windows NSIS), and the About button should switch to "Update now". At that point the full auto flow applies.
Cross-mode sanity checks (quick, after any successful update)
Regardless of mode, after a successful update verify the app is fully functional, not just "new version number":
- [ ] Plugins still load: open Tools — the 4 official plugins appear (markdown/excel/ email/offlinepython; browser automation is a host-embedded capability, not a plugin). The updated JAR/asar must have shipped matching plugin packages.
- [ ] AI chat works: send a message in Chat — a response streams back.
- [ ] Database intact: open Settings — the DB config persisted across the restart (the
data/runtime dir was NOT wiped by the update). - [ ] Re-check returns "up to date": About → "Recheck" → now says "Up to date" (the new build's version equals the latest release tag).