Files
Azornes-Comfyui-LayerForge/tests/test_persistence_resilience.mjs

126 lines
3.7 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
const currentState = {
layers: [],
viewport: { x: 0, y: 0, zoom: 1 },
width: 512,
height: 512,
outputAreaBounds: { x: 0, y: 0, width: 512, height: 512 },
};
test('persisted state migration restores defaults for legacy records', async () => {
const { migratePersistedCanvasState } = await import('../js/persistence/contracts.js?resilience');
const migrated = migratePersistedCanvasState({
layers: [{
id: 'legacy-layer',
imageSrc: 'data:image/png;base64,legacy',
width: 320,
height: 240,
}],
width: 1024,
height: 768,
});
assert.deepEqual(migrated, {
version: 2,
layers: [{
id: 'legacy-layer',
imageSrc: 'data:image/png;base64,legacy',
width: 320,
height: 240,
}],
viewport: { x: -256, y: -192, zoom: 0.8 },
width: 1024,
height: 768,
outputAreaBounds: { x: -256, y: -192, width: 1024, height: 768 },
});
});
test('persisted state migration rejects corrupted or incomplete records', async () => {
const { migratePersistedCanvasState } = await import('../js/persistence/contracts.js?resilience-invalid');
assert.equal(migratePersistedCanvasState(null), null);
assert.equal(migratePersistedCanvasState({}), null);
assert.equal(migratePersistedCanvasState({ layers: null }), null);
assert.equal(migratePersistedCanvasState({ layers: [{ id: 'missing-image' }] }), null);
});
test('database requests reject the underlying IndexedDB error', async () => {
const { createDBRequest } = await import('../js/persistence/db_shared.js?resilience-request');
const storageError = new Error('quota exceeded');
const logs = [];
const store = {
get() {
const request = { error: storageError, onerror: null, onsuccess: null };
queueMicrotask(() => request.onerror?.({ target: request }));
return request;
},
};
await assert.rejects(
createDBRequest(store, 'get', 'node-1', 'Unable to read state', {
error: (...args) => logs.push(args),
info() {},
}),
storageError,
);
assert.equal(logs.length, 1);
});
test('state saver worker ignores malformed messages and reports storage failures', async () => {
const originalSelf = Object.getOwnPropertyDescriptor(globalThis, 'self');
const originalIndexedDB = Object.getOwnPropertyDescriptor(globalThis, 'indexedDB');
const originalConsoleError = console.error;
const errors = [];
Object.defineProperty(globalThis, 'self', {
configurable: true,
value: {},
});
Object.defineProperty(globalThis, 'indexedDB', {
configurable: true,
value: {
open() {
const request = {
error: new Error('worker quota exceeded'),
onerror: null,
onupgradeneeded: null,
onsuccess: null,
result: undefined,
};
queueMicrotask(() => request.onerror?.({ target: request }));
return request;
},
},
});
console.error = (...args) => errors.push(args);
try {
await import('../js/persistence/state_saver.worker.js?resilience-worker');
await globalThis.self.onmessage({ data: { stateKey: '', state: null } });
assert.match(errors.flat().join(' '), /Invalid data received/);
await globalThis.self.onmessage({
data: {
stateKey: 'node-1',
state: currentState,
},
});
assert.match(errors.flat().join(' '), /Failed to save state for key: node-1/);
} finally {
console.error = originalConsoleError;
if (originalSelf) {
Object.defineProperty(globalThis, 'self', originalSelf);
} else {
delete globalThis.self;
}
if (originalIndexedDB) {
Object.defineProperty(globalThis, 'indexedDB', originalIndexedDB);
} else {
delete globalThis.indexedDB;
}
}
});