Fix session loading: a no-op capture stop aborted the load (v2.4.1)
- `loadSession` begins by stopping a running capture; when there is nothing to stop the server answers 400 'No active capture' (or 403 with capture disabled) — and since the v2.3.1 `_fetch` status fix those answers throw, so the whole load was skipped and the UI alerted "Failed to load session": no session could be opened at all - new `stopCaptureIfRunning()` swallows exactly that no-op answer; both `loadSession` and the capture button use it, and the button now resets its state outside the try so a tolerated stop still clears the UI - the `_fetch` status check stays — real errors keep surfacing (an unknown session still throws 'Session not found') - tests: the helper resolves on a 400 and still calls once; source pins that `loadSession` uses the tolerant helper (the regression guard) and that `stopCapture` resets the state - v2.4.1; SW cache simtrace-analyser-v66
This commit is contained in:
1 parent
cad3999307
commit
407821ab3d
6 files changed
+48
-14
No files matched your search
+18
-10
@@ -2546,15 +2546,22 @@ async function startCapture() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function stopCapture() {
|
// Stopping when nothing is capturing answers 400 ('No active capture'), and
|
||||||
|
// 403 when capture is disabled — both mean "there is no capture to stop",
|
||||||
|
// not a failure.
|
||||||
|
async function stopCaptureIfRunning() {
|
||||||
try {
|
try {
|
||||||
await API.stopCapture();
|
await API.stopCapture();
|
||||||
STATE.captureActive = false;
|
} catch (e) { /* nothing to stop */ }
|
||||||
STATE.currentSessionId = null;
|
}
|
||||||
STATE.sessionViewId = null;
|
|
||||||
updateCaptureButton();
|
async function stopCapture() {
|
||||||
updateStatus();
|
await stopCaptureIfRunning();
|
||||||
} catch (e) {}
|
STATE.captureActive = false;
|
||||||
|
STATE.currentSessionId = null;
|
||||||
|
STATE.sessionViewId = null;
|
||||||
|
updateCaptureButton();
|
||||||
|
updateStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateCaptureButton() {
|
function updateCaptureButton() {
|
||||||
@@ -2891,8 +2898,9 @@ async function confirmComprionImport() {
|
|||||||
async function loadSession(id) {
|
async function loadSession(id) {
|
||||||
if (STATE.captureActive && !confirm(t('Opening a session stops the active capture. Continue?'))) return;
|
if (STATE.captureActive && !confirm(t('Opening a session stops the active capture. Continue?'))) return;
|
||||||
try {
|
try {
|
||||||
// Stop any active capture so it can't write into the session being viewed.
|
// Stop any active capture so it can't write into the session being
|
||||||
await API.stopCapture();
|
// viewed (a 400/403 means there is none — not an error).
|
||||||
|
await stopCaptureIfRunning();
|
||||||
STATE.captureActive = false;
|
STATE.captureActive = false;
|
||||||
STATE.currentSessionId = null;
|
STATE.currentSessionId = null;
|
||||||
stopPolling();
|
stopPolling();
|
||||||
@@ -3164,7 +3172,7 @@ function onFilterChange() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ──────────────────── Versioning ────────────────────
|
// ──────────────────── Versioning ────────────────────
|
||||||
const PWA_VERSION = '2.4.0';
|
const PWA_VERSION = '2.4.1';
|
||||||
const MIN_SERVER_VERSION = '2.3.0';
|
const MIN_SERVER_VERSION = '2.3.0';
|
||||||
|
|
||||||
function parseVersion(v) {
|
function parseVersion(v) {
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
const CACHE = 'simtrace-analyser-v65';
|
const CACHE = 'simtrace-analyser-v66';
|
||||||
|
|
||||||
const PRECACHE = [
|
const PRECACHE = [
|
||||||
'index.html',
|
'index.html',
|
||||||
|
|||||||
@@ -498,3 +498,29 @@ test('Change details modal: header, summary, legend and both views', () => {
|
|||||||
assert.match(el('file-diff-sub').textContent, /Record 2 \/ 5/);
|
assert.match(el('file-diff-sub').textContent, /Record 2 \/ 5/);
|
||||||
assert.match(el('file-diff-body').innerHTML, /image is frozen/);
|
assert.match(el('file-diff-body').innerHTML, /image is frozen/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ── Session loading must survive "no active capture" ───────────────────
|
||||||
|
eval(extractFunc(src, 'stopCaptureIfRunning'));
|
||||||
|
|
||||||
|
test('stopCaptureIfRunning tolerates "no active capture" (400)', async () => {
|
||||||
|
let calls = 0;
|
||||||
|
API.stopCapture = async () => {
|
||||||
|
calls++;
|
||||||
|
throw Object.assign(new Error('No active capture'), {status: 400});
|
||||||
|
};
|
||||||
|
await stopCaptureIfRunning(); // must resolve, not reject
|
||||||
|
assert.equal(calls, 1);
|
||||||
|
API.stopCapture = async () => { calls++; };
|
||||||
|
await stopCaptureIfRunning();
|
||||||
|
assert.equal(calls, 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('loadSession stops a capture tolerantly', () => {
|
||||||
|
const body = extractFunc(src, 'loadSession');
|
||||||
|
assert.match(body, /await stopCaptureIfRunning\(\)/);
|
||||||
|
assert.doesNotMatch(body, /await API\.stopCapture\(\)/);
|
||||||
|
// The capture button also resets its state after a tolerated stop.
|
||||||
|
const stop = extractFunc(src, 'stopCapture');
|
||||||
|
assert.match(stop, /await stopCaptureIfRunning\(\)/);
|
||||||
|
assert.match(stop, /STATE\.captureActive = false;/);
|
||||||
|
});
|
||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.backends._legacy:_Backend"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "simtrace-analyser"
|
name = "simtrace-analyser"
|
||||||
version = "2.4.0"
|
version = "2.4.1"
|
||||||
description = "SIMtrace Analyser — APDU trace analyser for GSMTAP/PCAP captures (bundles the simtrace2-pysniff utility)"
|
description = "SIMtrace Analyser — APDU trace analyser for GSMTAP/PCAP captures (bundles the simtrace2-pysniff utility)"
|
||||||
readme = {file = "README.md", content-type = "text/markdown"}
|
readme = {file = "README.md", content-type = "text/markdown"}
|
||||||
license = {text = "GPL-2.0-or-later"}
|
license = {text = "GPL-2.0-or-later"}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
"""Single source of truth for the SIMtrace Analyser version."""
|
"""Single source of truth for the SIMtrace Analyser version."""
|
||||||
|
|
||||||
__version__ = '2.4.0'
|
__version__ = '2.4.1'
|
||||||
@@ -224,7 +224,7 @@ class TestImportEndpoint(unittest.TestCase):
|
|||||||
class TestVersion(unittest.TestCase):
|
class TestVersion(unittest.TestCase):
|
||||||
def test_package_version(self):
|
def test_package_version(self):
|
||||||
from simtrace2_pysniff import __version__
|
from simtrace2_pysniff import __version__
|
||||||
self.assertEqual(__version__, '2.4.0')
|
self.assertEqual(__version__, '2.4.1')
|
||||||
|
|
||||||
def test_status_includes_version(self):
|
def test_status_includes_version(self):
|
||||||
import os
|
import os
|
||||||
|
|||||||
Reference in new issue
Block a user