Skip to content

Add internet stability test#766

Open
tomrhudson wants to merge 2 commits intolibrespeed:masterfrom
tomrhudson:internet-stability
Open

Add internet stability test#766
tomrhudson wants to merge 2 commits intolibrespeed:masterfrom
tomrhudson:internet-stability

Conversation

@tomrhudson
Copy link

@tomrhudson tomrhudson commented Mar 15, 2026

Closes #758

Summary

Adds a prolonged ping-based internet stability test to LibreSpeed, providing users with a tool to monitor and diagnose connection quality over time — similar to packetstats.com.

  • New stability.html — Self-contained page with real-time canvas line chart, live stats (current/avg/min/max ping, jitter, packet loss), stability rating (Great/Good/Poor/Bad), alert threshold with audio notification, and CSV export
  • New stability_worker.js — Web Worker that continuously pings the backend (or external hosts like Google/Cloudflare/Apple via fetch no-cors) and reports delta ping data to the UI
  • Docker support — Updated both Dockerfiles, entrypoint.sh, and ui.php to include the stability test page and navigation link

Features

  • Configurable test duration (60s, 90s, 2min, 3min, 5min)
  • Ping target selection: Local server, Google, Cloudflare, Apple (external targets use fetch with mode: "no-cors")
  • Scrolling 60-second canvas chart with auto-scaling Y-axis and lost packet markers
  • Stability rating based on avg ping, jitter, and packet loss thresholds
  • Optional alert beep (Web Audio API) when ping exceeds a configurable threshold
  • CSV download of all ping data points
  • Dark mode support via prefers-color-scheme: dark
  • UI/UX consistent with the main speed test page (same button styles, stat layout, colors)
  • Bidirectional navigation between speed test and stability test

Files changed

File Change
stability_worker.js New — ping web worker
stability.html New — stability test UI
Dockerfile Copy stability.html into image
Dockerfile.alpine Copy stability.html into image
docker/entrypoint.sh Copy stability.html to web root
docker/ui.php Add "Stability Test" link on main page
package.json Add stability_worker.js to lint/files

Test plan

  • Open stability.html and start a test — verify pings appear in real-time on the chart
  • Verify stats update live (current, avg, min, max, jitter, packet loss)
  • Verify stability rating updates appropriately
  • Test each duration option — confirm test auto-stops at configured time
  • Test external ping targets (Google, Cloudflare, Apple)
  • Test Reset button clears chart and stats
  • Test CSV download contains all recorded ping data
  • Test alert threshold slider and audio beep
  • Verify dark mode renders correctly
  • Verify navigation links work in both directions (speed test ↔ stability test)
  • Build and run Docker image — verify stability test is accessible and functional

🤖 Generated with Claude Code

Add a prolonged ping-based stability test with real-time canvas chart,
stats (avg/min/max/jitter/packet loss), stability rating, external ping
targets, CSV export, and Docker support. Link from main page to stability test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@qodo-free-for-open-source-projects
Copy link
Contributor

Review Summary by Qodo

Add internet stability test with real-time ping monitoring

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add prolonged ping-based internet stability test with real-time canvas chart
• Implement Web Worker for continuous background pinging with configurable targets
• Display live statistics (current/avg/min/max ping, jitter, packet loss, elapsed time)
• Provide stability rating system (Great/Good/Poor/Bad) based on connection metrics
• Support external ping targets (Google, Cloudflare, Apple) via fetch no-cors mode
• Add alert threshold with audio notification when ping exceeds threshold
• Enable CSV export of all ping data points for analysis
• Include dark mode support and responsive design
• Add bidirectional navigation between speed test and stability test pages
• Update Docker configuration and package.json to include new stability test files
Diagram
flowchart LR
  UI["stability.html<br/>UI & Chart"]
  Worker["stability_worker.js<br/>Ping Worker"]
  Backend["Backend/External<br/>Ping Targets"]
  Export["CSV Export<br/>& Alerts"]
  
  UI -- "start/status/abort" --> Worker
  Worker -- "continuous pings" --> Backend
  Worker -- "delta data" --> UI
  UI -- "threshold check" --> Export
  UI -- "navigation link" --> MainPage["Speed Test<br/>index.html"]
Loading

Grey Divider

File Changes

1. stability.html ✨ Enhancement +793/-0

Stability test UI with interactive chart and statistics

• New self-contained HTML page with real-time canvas line chart for ping visualization
• Displays live statistics: current/avg/min/max ping, jitter, packet loss, elapsed time
• Implements stability rating system (Great/Good/Poor/Bad) with color coding
• Provides configurable test duration (60s, 90s, 2min, 3min, 5min) and ping target selection
• Includes alert threshold slider with audio beep notification and CSV download functionality
• Supports dark mode via prefers-color-scheme media query with responsive design
• Bidirectional navigation links to speed test page

stability.html


2. stability_worker.js ✨ Enhancement +216/-0

Web Worker for continuous ping monitoring

• New Web Worker for continuous background ping operations
• Supports both local server pinging (XMLHttpRequest) and external targets (fetch no-cors)
• Calculates real-time statistics: average, min, max ping, jitter, and packet loss
• Implements delta-based data delivery to main thread for efficient updates
• Uses Performance API for accurate ping measurement when available
• Handles test state management (idle, starting, running, finished, aborted)
• Records all ping data points with timestamps for chart rendering and CSV export

stability_worker.js


3. docker/ui.php ✨ Enhancement +1/-1

Add stability test navigation link

• Add navigation link to stability test page in main footer
• Link appears alongside existing source code link

docker/ui.php


View more (4)
4. docker/entrypoint.sh ⚙️ Configuration changes +1/-0

Copy stability test to web root

• Copy stability.html file to web root during Docker container initialization

docker/entrypoint.sh


5. Dockerfile ⚙️ Configuration changes +1/-0

Include stability test in Docker image

• Add COPY directive to include stability.html in Docker image

Dockerfile


6. Dockerfile.alpine ⚙️ Configuration changes +1/-0

Include stability test in Alpine image

• Add COPY directive to include stability.html in Alpine Docker image

Dockerfile.alpine


7. package.json ⚙️ Configuration changes +4/-2

Update package configuration for stability test

• Add stability_worker.js to ESLint configuration for lint and lint:fix scripts
• Add stability_worker.js and stability.html to files array for npm package distribution

package.json


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Contributor

qodo-free-for-open-source-projects bot commented Mar 15, 2026

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Local ping target wrong🐞 Bug ✓ Correctness
Description
In stability.html, “Local Server” mode only sets workerSettings.url_ping when selectedServer is set;
since SPEEDTEST_SERVERS is empty by default, selectedServer stays null and the worker pings its
default backend/empty.php. In Docker MODE=frontend the backend folder (and empty.php) is not
deployed, so the stability test reports packet loss and cannot target the configured /servers.json
servers.
Code

stability.html[R414-424]

+	var externalTarget = I("targetSelect").value;
+	var workerSettings = {
+		duration: parseInt(I("durationSelect").value),
+		ping_allowPerformanceApi: true,
+		url_ping_external: externalTarget
+	};
+
+	if (!externalTarget && selectedServer) {
+		workerSettings.url_ping = selectedServer.server + selectedServer.pingURL;
+		workerSettings.mpot = true;
+	}
Evidence
The stability UI never populates SPEEDTEST_SERVERS, so selectedServer remains null and startTest()
doesn’t set url_ping; the worker then falls back to backend/empty.php. In Docker frontend mode,
entrypoint.sh does not copy backend/empty.php, while docker/ui.php uses /servers.json to provide
servers for the speedtest UI—meaning stability.html’s “Local Server” does not match the actual
configured test servers and can outright fail in frontend mode.

stability.html[311-313]
stability.html[341-344]
stability.html[414-424]
stability_worker.js[24-30]
docker/entrypoint.sh[29-56]
docker/ui.php[12-18]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The stability test’s “Local Server” mode often pings `backend/empty.php` because `selectedServer` is never set (server list is never loaded). In Docker `MODE=frontend`, `backend/empty.php` isn’t deployed, leading to false packet loss and inability to target the configured servers.
## Issue Context
- The Docker speed test UI gets its servers from `/servers.json` (injected by `docker/ui.php`).
- The stability page is a static HTML page and currently defines `SPEEDTEST_SERVERS = []` without ever populating it.
## Fix Focus Areas
- stability.html[311-424]
- stability_worker.js[24-30]
- docker/entrypoint.sh[29-56]
- docker/ui.php[12-18]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Back link breaks subdir🐞 Bug ✓ Correctness
Description
stability.html links back to the speed test using an absolute “/”, which points to the site root
rather than the speed test page when LibreSpeed is installed under a subdirectory. This breaks
navigation for the documented YOURSITE/speedtest/index.html installation layout.
Code

stability.html[223]

+<nav><a href="/">&larr; Speed Test</a></nav>
Evidence
The stability page hardcodes the back link to “/”, but the project’s installation instructions
explicitly describe serving LibreSpeed from a subdirectory (e.g., /speedtest/index.html). In that
common layout, “/” does not resolve to the speed test page.

stability.html[222-224]
README.md[43-46]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The stability page uses `href=&amp;quot;/&amp;quot;` for back navigation, which breaks in subdirectory installs (e.g. `/speedtest/`).
## Issue Context
README explicitly documents subdirectory hosting and visiting `/speedtest/index.html`.
## Fix Focus Areas
- stability.html[222-224]
- README.md[43-46]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Chart redraw scales poorly🐞 Bug ➹ Performance
Description
The UI redraws the chart every animation frame and scans allPingData to compute scaling and visible
points, while the worker generates samples as fast as RTT with no pacing. Over multi-minute tests
this can increase CPU usage and degrade UI responsiveness, especially on low-latency links where
sample count grows quickly.
Code

stability.html[R737-742]

+// Animation frame loop
+window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || (function(callback) { setTimeout(callback, 1000 / 60); });
+function frame() {
+	requestAnimationFrame(frame);
+	updateUI();
+	drawChart();
Evidence
The render loop calls drawChart() every frame, and drawChart() performs full-array scans to compute
yMax and filter visible points. Meanwhile, the worker schedules the next ping immediately after each
response, so the number of samples (and therefore the cost of those scans) grows with test duration
and decreases with RTT.

stability.html[737-744]
stability.html[580-658]
stability_worker.js[160-186]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Chart rendering does full-history scans every animation frame while the worker produces samples as fast as RTT, which can drive unnecessary CPU usage on longer runs.
## Issue Context
- `frame()` calls `drawChart()` on every `requestAnimationFrame`.
- `drawChart()` loops over `allPingData` to compute scaling and visible data.
- Worker immediately schedules the next ping on each response.
## Fix Focus Areas
- stability.html[539-722]
- stability.html[737-744]
- stability_worker.js[141-186]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

- Load server list dynamically from servers.json for Docker frontend/dual modes
- Copy servers.json to web root in entrypoint.sh for frontend/dual modes
- Change back link from href="/" to href="./" for subdirectory installs
- Use binary search for visible chart data range (O(log n) vs O(n))
- Add 200ms minimum interval between pings to limit sample rate

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@tomrhudson
Copy link
Author

Thanks for the review! All three issues have been addressed in the latest commit (6f1d8c5):

  1. Local ping target wrong — The stability page now dynamically fetches servers.json at startup, so it discovers configured backend servers in frontend/dual Docker modes. The entrypoint also copies servers.json to the web root for these modes.
  2. Back link breaks subdir — Changed href="/" to href="./" so navigation works when hosted under a subdirectory.
  3. Chart redraw scales poorly — Added binary search to find visible data range (O(log n) instead of full array scan), and added a 200ms minimum interval between pings in the worker to cap sample rate on low-latency links.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

add internet stability test

1 participant