mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-19 23:17:16 +03:00
165 lines
5.9 KiB
JavaScript
165 lines
5.9 KiB
JavaScript
const { dialog } = require('electron')
|
|
const FileRecoveryService = require('../../src/main-process/file-recovery-service')
|
|
const fs = require('fs-plus')
|
|
const fsreal = require('fs')
|
|
const EventEmitter = require('events').EventEmitter
|
|
const { assert } = require('chai')
|
|
const sinon = require('sinon')
|
|
const { escapeRegExp } = require('underscore-plus')
|
|
const temp = require('temp').track()
|
|
|
|
describe('FileRecoveryService', () => {
|
|
let recoveryService, recoveryDirectory, spies
|
|
|
|
beforeEach(() => {
|
|
recoveryDirectory = temp.mkdirSync('atom-spec-file-recovery')
|
|
recoveryService = new FileRecoveryService(recoveryDirectory)
|
|
spies = sinon.sandbox.create()
|
|
})
|
|
|
|
afterEach(() => {
|
|
spies.restore()
|
|
try {
|
|
temp.cleanupSync()
|
|
} catch (e) {
|
|
// Ignore
|
|
}
|
|
})
|
|
|
|
describe('when no crash happens during a save', () => {
|
|
it('creates a recovery file and deletes it after saving', async () => {
|
|
const mockWindow = {}
|
|
const filePath = temp.path()
|
|
|
|
fs.writeFileSync(filePath, 'some content')
|
|
await recoveryService.willSavePath(mockWindow, filePath)
|
|
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
|
|
|
|
fs.writeFileSync(filePath, 'changed')
|
|
await recoveryService.didSavePath(mockWindow, filePath)
|
|
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
|
|
assert.equal(fs.readFileSync(filePath, 'utf8'), 'changed')
|
|
|
|
fs.removeSync(filePath)
|
|
})
|
|
|
|
it('creates only one recovery file when many windows attempt to save the same file, deleting it when the last one finishes saving it', async () => {
|
|
const mockWindow = {}
|
|
const anotherMockWindow = {}
|
|
const filePath = temp.path()
|
|
|
|
fs.writeFileSync(filePath, 'some content')
|
|
await recoveryService.willSavePath(mockWindow, filePath)
|
|
await recoveryService.willSavePath(anotherMockWindow, filePath)
|
|
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
|
|
|
|
fs.writeFileSync(filePath, 'changed')
|
|
await recoveryService.didSavePath(mockWindow, filePath)
|
|
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
|
|
assert.equal(fs.readFileSync(filePath, 'utf8'), 'changed')
|
|
|
|
await recoveryService.didSavePath(anotherMockWindow, filePath)
|
|
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
|
|
assert.equal(fs.readFileSync(filePath, 'utf8'), 'changed')
|
|
|
|
fs.removeSync(filePath)
|
|
})
|
|
})
|
|
|
|
describe('when a crash happens during a save', () => {
|
|
it('restores the created recovery file and deletes it', async () => {
|
|
const mockWindow = {}
|
|
const filePath = temp.path()
|
|
|
|
fs.writeFileSync(filePath, 'some content')
|
|
await recoveryService.willSavePath(mockWindow, filePath)
|
|
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
|
|
|
|
fs.writeFileSync(filePath, 'changed')
|
|
await recoveryService.didCrashWindow(mockWindow)
|
|
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
|
|
assert.equal(fs.readFileSync(filePath, 'utf8'), 'some content')
|
|
|
|
fs.removeSync(filePath)
|
|
})
|
|
|
|
it('restores the created recovery file when many windows attempt to save the same file and one of them crashes', async () => {
|
|
const mockWindow = {}
|
|
const anotherMockWindow = {}
|
|
const filePath = temp.path()
|
|
|
|
fs.writeFileSync(filePath, 'A')
|
|
await recoveryService.willSavePath(mockWindow, filePath)
|
|
fs.writeFileSync(filePath, 'B')
|
|
await recoveryService.willSavePath(anotherMockWindow, filePath)
|
|
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
|
|
|
|
fs.writeFileSync(filePath, 'C')
|
|
|
|
await recoveryService.didCrashWindow(mockWindow)
|
|
assert.equal(fs.readFileSync(filePath, 'utf8'), 'A')
|
|
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
|
|
|
|
fs.writeFileSync(filePath, 'D')
|
|
await recoveryService.willSavePath(mockWindow, filePath)
|
|
fs.writeFileSync(filePath, 'E')
|
|
await recoveryService.willSavePath(anotherMockWindow, filePath)
|
|
assert.equal(fs.listTreeSync(recoveryDirectory).length, 1)
|
|
|
|
fs.writeFileSync(filePath, 'F')
|
|
|
|
await recoveryService.didCrashWindow(anotherMockWindow)
|
|
assert.equal(fs.readFileSync(filePath, 'utf8'), 'D')
|
|
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
|
|
|
|
fs.removeSync(filePath)
|
|
})
|
|
|
|
it("emits a warning when a file can't be recovered", async () => {
|
|
const mockWindow = {}
|
|
const filePath = temp.path()
|
|
fs.writeFileSync(filePath, 'content')
|
|
|
|
let logs = []
|
|
spies.stub(console, 'log', message => logs.push(message))
|
|
spies.stub(dialog, 'showMessageBox')
|
|
|
|
// Copy files to be recovered before mocking fs.createWriteStream
|
|
await recoveryService.willSavePath(mockWindow, filePath)
|
|
|
|
// Stub out fs.createWriteStream so that we can return a fake error when
|
|
// attempting to copy the recovered file to its original location
|
|
var fakeEmitter = new EventEmitter()
|
|
var onStub = spies.stub(fakeEmitter, 'on')
|
|
onStub
|
|
.withArgs('error')
|
|
.yields(new Error('Nope'))
|
|
.returns(fakeEmitter)
|
|
onStub.withArgs('open').returns(fakeEmitter)
|
|
spies
|
|
.stub(fsreal, 'createWriteStream')
|
|
.withArgs(filePath)
|
|
.returns(fakeEmitter)
|
|
|
|
await recoveryService.didCrashWindow(mockWindow)
|
|
let recoveryFiles = fs.listTreeSync(recoveryDirectory)
|
|
assert.equal(recoveryFiles.length, 1)
|
|
assert.equal(logs.length, 1)
|
|
assert.match(logs[0], new RegExp(escapeRegExp(filePath)))
|
|
assert.match(logs[0], new RegExp(escapeRegExp(recoveryFiles[0])))
|
|
|
|
fs.removeSync(filePath)
|
|
})
|
|
})
|
|
|
|
it("doesn't create a recovery file when the file that's being saved doesn't exist yet", async () => {
|
|
const mockWindow = {}
|
|
|
|
await recoveryService.willSavePath(mockWindow, 'a-file-that-doesnt-exist')
|
|
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
|
|
|
|
await recoveryService.didSavePath(mockWindow, 'a-file-that-doesnt-exist')
|
|
assert.equal(fs.listTreeSync(recoveryDirectory).length, 0)
|
|
})
|
|
})
|