77 lines
3.0 KiB
TypeScript
77 lines
3.0 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest';
|
|
import type { BackendStartupFailureInfo } from '@/common/types/platform/electron';
|
|
import { recoverCorruptedDatabaseAfterUserConfirmation } from '@/process/startup/recoverCorruptedDatabase';
|
|
|
|
function makeDeps(failure: BackendStartupFailureInfo | null) {
|
|
return {
|
|
getFailure: vi.fn(() => failure),
|
|
stopBackend: vi.fn().mockResolvedValue(undefined),
|
|
startBackendWithRecovery: vi.fn().mockResolvedValue(25808),
|
|
markReady: vi.fn(),
|
|
reloadMainWindow: vi.fn(),
|
|
logInfo: vi.fn(),
|
|
logWarn: vi.fn(),
|
|
};
|
|
}
|
|
|
|
describe('recoverCorruptedDatabaseAfterUserConfirmation', () => {
|
|
it('rejects when no recoverable startup failure is active', async () => {
|
|
const deps = makeDeps(null);
|
|
|
|
await expect(recoverCorruptedDatabaseAfterUserConfirmation(deps)).rejects.toThrow(
|
|
'backend_corrupted_database_recovery_not_available'
|
|
);
|
|
|
|
expect(deps.stopBackend).not.toHaveBeenCalled();
|
|
expect(deps.startBackendWithRecovery).not.toHaveBeenCalled();
|
|
expect(deps.logWarn).toHaveBeenCalledOnce();
|
|
});
|
|
|
|
it('rejects data migration failures that are not recoverable corruption', async () => {
|
|
const deps = makeDeps({
|
|
reason: 'backend_data_migration_failed',
|
|
backendBoundaryCode: 'BOOTSTRAP_DATA_INIT_FAILED',
|
|
backendBoundaryStage: 'database.migration',
|
|
});
|
|
|
|
await expect(recoverCorruptedDatabaseAfterUserConfirmation(deps)).rejects.toThrow(
|
|
'backend_corrupted_database_recovery_not_available'
|
|
);
|
|
|
|
expect(deps.stopBackend).not.toHaveBeenCalled();
|
|
expect(deps.startBackendWithRecovery).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('restarts the backend with recovery and reloads the main window after confirmation', async () => {
|
|
const deps = makeDeps({
|
|
reason: 'backend_recoverable_database_corruption',
|
|
backendBoundaryCode: 'BOOTSTRAP_DATA_INIT_FAILED',
|
|
backendBoundaryStage: 'database.recoverable_corruption',
|
|
});
|
|
|
|
await recoverCorruptedDatabaseAfterUserConfirmation(deps);
|
|
|
|
expect(deps.stopBackend).toHaveBeenCalledOnce();
|
|
expect(deps.startBackendWithRecovery).toHaveBeenCalledOnce();
|
|
expect(deps.markReady).toHaveBeenCalledWith(25808, 'backendManager.recoverCorruptedDatabase');
|
|
expect(deps.reloadMainWindow).toHaveBeenCalledOnce();
|
|
expect(deps.logInfo).toHaveBeenCalledOnce();
|
|
});
|
|
|
|
it('does not mark ready or reload when restart fails', async () => {
|
|
const failure: BackendStartupFailureInfo = {
|
|
reason: 'backend_recoverable_database_corruption',
|
|
backendBoundaryCode: 'BOOTSTRAP_DATA_INIT_FAILED',
|
|
backendBoundaryStage: 'database.recoverable_corruption',
|
|
};
|
|
const deps = makeDeps(failure);
|
|
deps.startBackendWithRecovery.mockRejectedValue(new Error('restart failed'));
|
|
|
|
await expect(recoverCorruptedDatabaseAfterUserConfirmation(deps)).rejects.toThrow('restart failed');
|
|
|
|
expect(deps.markReady).not.toHaveBeenCalled();
|
|
expect(deps.reloadMainWindow).not.toHaveBeenCalled();
|
|
expect(deps.getFailure()).toBe(failure);
|
|
});
|
|
});
|