diff --git a/test/db.test.js b/test/db.test.js index a11fef2..82332d2 100755 --- a/test/db.test.js +++ b/test/db.test.js @@ -431,12 +431,10 @@ describe('Database', function () { it('If the callback throws an uncaught exception, do not catch it inside findOne, this is userspace concern', function (done) { let tryCount = 0 const currentUncaughtExceptionHandlers = process.listeners('uncaughtException') - const currentUnhandledRejectionHandlers = process.listeners('unhandledRejection') let i process.removeAllListeners('uncaughtException') - process.removeAllListeners('unhandledRejection') process.on('uncaughtException', function MINE (ex) { process.removeAllListeners('uncaughtException') @@ -449,17 +447,6 @@ describe('Database', function () { done() }) - process.on('unhandledRejection', function MINE (ex) { - process.removeAllListeners('unhandledRejection') - - for (i = 0; i < currentUnhandledRejectionHandlers.length; i += 1) { - process.on('unhandledRejection', currentUnhandledRejectionHandlers[i]) - } - - ex.message.should.equal('SOME EXCEPTION') - done() - }) - d.insert({ a: 5 }, function () { // eslint-disable-next-line node/handle-callback-err d.findOne({ a: 5 }, function (err, doc) { diff --git a/test/executor.async.test.js b/test/executor.async.test.js new file mode 100755 index 0000000..d57127e --- /dev/null +++ b/test/executor.async.test.js @@ -0,0 +1,85 @@ +/* eslint-env mocha */ +const testDb = 'workspace/test.db' +const { promises: fs, constants: fsConstants } = require('fs') +const assert = require('assert').strict +const path = require('path') +const Datastore = require('../lib/datastore') +const Persistence = require('../lib/persistence') + +// Test that operations are executed in the right order +// We prevent Mocha from catching the exception we throw on purpose by remembering all current handlers, remove them and register them back after test ends +const testRightOrder = async d => { + const docs = await d.findAsync({}) + assert.equal(docs.length, 0) + + await d.insertAsync({ a: 1 }) + await d.updateAsync({ a: 1 }, { a: 2 }, {}) + const docs2 = await d.findAsync({}) + assert.equal(docs2[0].a, 2) + d.updateAsync({ a: 2 }, { a: 3 }, {}) // not awaiting + d.executor.pushAsync(async () => { throw new Error('Some error') }) // not awaiting + const docs3 = await d.findAsync({}) + assert.equal(docs3[0].a, 3) +} + +// Note: The following test does not have any assertion because it +// is meant to address the deprecation warning: +// (node) warning: Recursive process.nextTick detected. This will break in the next version of node. Please use setImmediate for recursive deferral. +// see +const testEventLoopStarvation = async d => { + const times = 1001 + let i = 0 + while (i < times) { + i++ + d.findAsync({ bogus: 'search' }) + } + await d.findAsync({ bogus: 'search' }) +} + +// Test that operations are executed in the right order even with no callback +const testExecutorWorksWithoutCallback = async d => { + d.insertAsync({ a: 1 }) + d.insertAsync({ a: 2 }) + const docs = await d.findAsync({}) + assert.equal(docs.length, 2) +} + +describe('Executor async', function () { + describe('With persistent database', async () => { + let d + + beforeEach(async () => { + d = new Datastore({ filename: testDb }) + assert.equal(d.filename, testDb) + assert.equal(d.inMemoryOnly, false) + await Persistence.ensureDirectoryExistsAsync(path.dirname(testDb)) + try { + await fs.access(testDb, fsConstants.FS_OK) + await fs.unlink(testDb) + } catch (err) {} + await d.loadDatabaseAsync() + assert.equal(d.getAllData().length, 0) + }) + + it('Operations are executed in the right order', () => testRightOrder(d)) + + it('Does not starve event loop and raise warning when more than 1000 callbacks are in queue', () => testEventLoopStarvation(d)) + + it('Works in the right order even with no supplied callback', () => testExecutorWorksWithoutCallback(d)) + }) +}) // ==== End of 'With persistent database' ==== + +describe('With non persistent database', function () { + let d + + beforeEach(async () => { + d = new Datastore({ inMemoryOnly: true }) + assert.equal(d.inMemoryOnly, true) + await d.loadDatabaseAsync() + assert.equal(d.getAllData().length, 0) + }) + + it('Operations are executed in the right order', () => testRightOrder(d)) + + it('Works in the right order even with no supplied callback', () => testExecutorWorksWithoutCallback(d)) +}) // ==== End of 'With non persistent database' ====