/* eslint-env mocha */ /* global DEBUG */ /** * Load and modify part of fs to ensure writeFile will crash after writing 5000 bytes */ const fs = require('fs') function rethrow () { // Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and // is fairly slow to generate. if (DEBUG) { const backtrace = new Error() return function (err) { if (err) { backtrace.stack = err.name + ': ' + err.message + backtrace.stack.substr(backtrace.name.length) throw backtrace } } } return function (err) { if (err) { throw err // Forgot a callback but don't know where? Use NODE_DEBUG=fs } } } function maybeCallback (cb) { return typeof cb === 'function' ? cb : rethrow() } function isFd (path) { return (path >>> 0) === path } function assertEncoding (encoding) { if (encoding && !Buffer.isEncoding(encoding)) { throw new Error('Unknown encoding: ' + encoding) } } let onePassDone = false function writeAll (fd, isUserFd, buffer, offset, length, position, callback_) { const callback = maybeCallback(arguments[arguments.length - 1]) if (onePassDone) { process.exit(1) } // Crash on purpose before rewrite done const l = Math.min(5000, length) // Force write by chunks of 5000 bytes to ensure data will be incomplete on crash // write(fd, buffer, offset, length, position, callback) fs.write(fd, buffer, offset, l, position, function (writeErr, written) { if (writeErr) { if (isUserFd) { if (callback) callback(writeErr) } else { fs.close(fd, function () { if (callback) callback(writeErr) }) } } else { onePassDone = true if (written === length) { if (isUserFd) { if (callback) callback(null) } else { fs.close(fd, callback) } } else { offset += written length -= written if (position !== null) { position += written } writeAll(fd, isUserFd, buffer, offset, length, position, callback) } } }) } fs.writeFile = function (path, data, options, callback_) { const callback = maybeCallback(arguments[arguments.length - 1]) if (!options || typeof options === 'function') { options = { encoding: 'utf8', mode: 438, flag: 'w' } // Mode 438 == 0o666 (compatibility with older Node releases) } else if (typeof options === 'string') { options = { encoding: options, mode: 438, flag: 'w' } // Mode 438 == 0o666 (compatibility with older Node releases) } else if (typeof options !== 'object') { throw new Error(`throwOptionsError${options}`) } assertEncoding(options.encoding) const flag = options.flag || 'w' if (isFd(path)) { writeFd(path, true) return } fs.open(path, flag, options.mode, function (openErr, fd) { if (openErr) { if (callback) callback(openErr) } else { writeFd(fd, false) } }) function writeFd (fd, isUserFd) { const buffer = (data instanceof Buffer) ? data : Buffer.from('' + data, options.encoding || 'utf8') const position = /a/.test(flag) ? null : 0 writeAll(fd, isUserFd, buffer, 0, buffer.length, position, callback) } } fs.createWriteStream = function (path) { let content = '' return { write(data) { content += data }, close(callback) { fs.writeFile(path, content, callback) } } } // End of fs modification const Nedb = require('../lib/datastore.js') const db = new Nedb({ filename: 'workspace/lac.db' }) db.loadDatabase()