mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-04 14:25:08 +00:00
* fix(web): update-all skips Starlark apps and no longer misses plugins Check & Update All posted every entry from /plugins/installed to POST /plugins/update, including the virtual starlark:<app_id> entries that list installed Starlark apps. The store manager cannot find those, so each answered 500 "plugin not found". Update-all now sends only plugin ids (install_manager.js, and the older app-shell.js copy), and the route answers a starlark: id with a 400 saying it is a Starlark app. A request that got no HTTP answer was recorded as failed and never sent again. On a device, a web-service restart mid-run killed the in-flight request and refused the next one, stock-news, which was left on 2.6.2 with 2.8.0 available. Such requests are now re-sent with backoff (about 30s) before being reported as failed. HTTP error answers are not retried. Tests: test/js/unit/test_update_all.js (run from pytest via test/web_interface/test_update_all_plugins.py so CI covers it) and the route contract for starlark: ids. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * refactor(web): walk update-all retry delays without indexed lookup Codacy's ESLint security/detect-object-injection rule flagged retryDelays[attempt] as a High issue. The index was a bounded loop counter over a fixed array, but shifting a per-plugin copy of the schedule gives the same backoff without the pattern. No behaviour change: test/js/unit/test_update_all.js (21) and test/web_interface/test_update_all_plugins.py (7) pass unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
63 lines
2.6 KiB
JavaScript
Executable File
63 lines
2.6 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
// Runs the web-interface JS suites.
|
|
//
|
|
// node run_all.js unit suites, plus DOM suites if a
|
|
// web interface is reachable
|
|
// BASE=http://10.0.10.169:5000 node run_all.js point the DOM suites at a rig
|
|
//
|
|
// Unit suites need nothing but node. The DOM suites need `npm install` (jsdom)
|
|
// and a running web interface, because they deliberately test against the real
|
|
// server-rendered HTML and the real API rather than fixtures.
|
|
const { spawnSync } = require('child_process');
|
|
const http = require('http');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
|
|
const BASE = process.env.BASE || 'http://localhost:5000';
|
|
const UNIT = ['unit/test_list_filter.js', 'unit/test_render_cards.js',
|
|
'unit/test_html_escaping.js', 'unit/test_style_editor_element_keys.js',
|
|
'unit/test_style_editor_layout_leaf_columns.js',
|
|
'unit/test_style_editor_layout_leaf_collision.js',
|
|
'unit/test_update_all.js'];
|
|
const DOM = ['dom/test_installed_dom.js', 'dom/test_store_dom.js', 'dom/test_no_double_fetch.js',
|
|
'dom/test_tools_sections.js'];
|
|
|
|
function reachable(url) {
|
|
return new Promise(res => {
|
|
const req = http.get(url, r => { r.resume(); res(r.statusCode < 500); });
|
|
req.on('error', () => res(false));
|
|
req.setTimeout(4000, () => { req.destroy(); res(false); });
|
|
});
|
|
}
|
|
|
|
function run(file) {
|
|
const r = spawnSync(process.execPath, [path.join(__dirname, file)],
|
|
{ stdio: 'inherit', cwd: __dirname, env: process.env });
|
|
return r.status === 0;
|
|
}
|
|
|
|
(async () => {
|
|
const results = [];
|
|
for (const f of UNIT) results.push([f, run(f)]);
|
|
|
|
const haveJsdom = fs.existsSync(path.join(__dirname, 'node_modules', 'jsdom'));
|
|
const up = await reachable(BASE + '/');
|
|
|
|
if (!haveJsdom) {
|
|
console.log(`\nSKIPPING DOM suites: jsdom not installed (run: npm install)\n`);
|
|
} else if (!up) {
|
|
console.log(`\nSKIPPING DOM suites: no web interface reachable at ${BASE}`);
|
|
console.log(` start one with: EMULATOR=true python3 web_interface/app.py`);
|
|
console.log(` or point at a rig: BASE=http://<host>:5000 node run_all.js\n`);
|
|
} else {
|
|
console.log(`\nDOM suites against ${BASE}\n`);
|
|
for (const f of DOM) results.push([f, run(f)]);
|
|
}
|
|
|
|
const failed = results.filter(([, ok]) => !ok);
|
|
console.log('\n─── summary ───');
|
|
results.forEach(([f, ok]) => console.log(` ${ok ? 'PASS' : 'FAIL'} ${f}`));
|
|
if (failed.length) { console.log(`\n${failed.length} suite(s) failed\n`); process.exit(1); }
|
|
console.log('\nall suites passed\n');
|
|
})();
|