Close startup and recovery transaction gaps

This commit is contained in:
Sucukdeluxe
2026-08-13 21:37:00 +02:00
parent c1003074cd
commit 1dd0e32709
6 changed files with 69 additions and 23 deletions
+3 -1
View File
@@ -150,8 +150,10 @@ test('close readiness is signaled only after the renderer explicitly finishes in
assert.deepEqual(sent, [['app:close-preparation-started', 7]]);
exposedApi.signalCloseHandshakeReady();
exposedApi.signalRendererInitializationFailed({ message: 'init failed' });
assert.deepEqual(sent, [
['app:close-preparation-started', 7],
['app:close-handshake-ready']
['app:close-handshake-ready'],
['app:renderer-initialization-failed', { message: 'init failed' }]
]);
});
+27
View File
@@ -28,6 +28,7 @@ test('main process wires bounded startup recovery into real load and crash paths
assert.match(source, /createStartupRecoveryCoordinator/);
assert.match(source, /startupRecoveryCoordinator\.loadInitial/);
assert.match(source, /startupRecoveryCoordinator\.rendererCrashed/);
assert.match(source, /startupRecoveryCoordinator\.rendererInitializationFailed/);
assert.match(source, /startupRecoveryCoordinator\.rendererReady/);
assert.match(source, /createStartupFailureDocument/);
});
@@ -284,6 +285,32 @@ test('renderer crash recovery reloads once and cannot enter an infinite reload l
assert.equal(revealCalls, 1);
});
test('renderer initialization failures share the bounded recovery path', async () => {
const failures = [];
let reloadCalls = 0;
const coordinator = createStartupRecoveryCoordinator({
load() {},
async reload() {
reloadCalls++;
},
reveal() {},
async showFailure(failure) {
failures.push(failure);
},
close() {}
});
await coordinator.rendererInitializationFailed({ message: 'first failure' });
await coordinator.rendererInitializationFailed({ message: 'second failure' });
assert.equal(reloadCalls, 1);
assert.deepEqual(failures, [{
phase: 'renderer-initialization',
attempt: 2,
details: { message: 'second failure' }
}]);
});
test('a successful renderer ready event reveals content and resets crash recovery', async () => {
const crashes = [
{ reason: 'crashed', exitCode: 21 },
+1
View File
@@ -90,6 +90,7 @@ test('main and renderer keep recovery evidence until final queue persistence suc
assert.match(startFailure, /if \(queuePersisted && terminalRecoveryPersisted\)[\s\S]*saveUploadRecovery\(null\)/);
const startHandler = mainSource.slice(mainSource.indexOf("ipcMain.handle('start-upload'"), mainSource.indexOf("ipcMain.handle('cancel-upload'"));
assert.match(startHandler, /await configStore\.saveUploadRecovery\(recovery\)/);
assert.ok(startHandler.indexOf('sourceCleanup.registerGroups(sourceCleanupGroups)') < startHandler.indexOf('saveUploadRecovery(recovery)'));
assert.match(startHandler, /catch \(error\)[\s\S]*return { error: 'Upload-Wiederherstellung konnte nicht gespeichert werden' }/);
const addHandler = mainSource.slice(mainSource.indexOf("ipcMain.handle('add-jobs-to-batch'"), mainSource.indexOf("ipcMain.handle('finish-after-active'"));
assert.match(addHandler, /await configStore\.saveUploadRecovery\(nextRecovery\)/);