var should = require('chai').should() , assert = require('chai').assert , testDb = 'workspace/test.db' , fs = require('fs') , path = require('path') , _ = require('underscore') , async = require('async') , model = require('../lib/model') , Datastore = require('../lib/datastore') , Persistence = require('../lib/persistence') ; // Test that even if a callback throws an exception, the next DB operations will still be executed // 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 function testThrowInCallback (d, done) { var currentUncaughtExceptionHandlers = process.listeners('uncaughtException'); process.removeAllListeners('uncaughtException'); process.on('uncaughtException', function (err) { // Do nothing with the error which is only there to test we stay on track }); d.find({}, function (err) { process.nextTick(function () { d.insert({ bar: 1 }, function (err) { for (var i = 0; i < currentUncaughtExceptionHandlers.length; i += 1) { process.on('uncaughtException', currentUncaughtExceptionHandlers[i]); } done(); }); }); throw 'Some error'; }); } // 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 function testRightOrder (d, done) { var currentUncaughtExceptionHandlers = process.listeners('uncaughtException'); process.removeAllListeners('uncaughtException'); process.on('uncaughtException', function (err) { // Do nothing with the error which is only there to test we stay on track }); d.find({}, function (err, docs) { docs.length.should.equal(0); d.insert({ a: 1 }, function () { d.update({ a: 1 }, { a: 2 }, {}, function () { d.find({}, function (err, docs) { docs[0].a.should.equal(2); process.nextTick(function () { d.update({ a: 2 }, { a: 3 }, {}, function () { d.find({}, function (err, docs) { docs[0].a.should.equal(3); done(); }); }); }); throw 'Some error'; }); }); }); }); } describe('Executor', function () { describe('With persistent database', function () { var d; beforeEach(function (done) { d = new Datastore({ filename: testDb }); d.filename.should.equal(testDb); d.inMemoryOnly.should.equal(false); async.waterfall([ function (cb) { Persistence.ensureDirectoryExists(path.dirname(testDb), function () { fs.exists(testDb, function (exists) { if (exists) { fs.unlink(testDb, cb); } else { return cb(); } }); }); } , function (cb) { d.loadDatabase(function (err) { assert.isNull(err); d.getAllData().length.should.equal(0); return cb(); }); } ], done); }); it('A throw in a callback doesnt prevent execution of next operations', function(done) { testThrowInCallback(d, done); }); it('Operations are executed in the right order', function(done) { testRightOrder(d, done); }); }); // ==== End of 'With persistent database' ==== describe('With non persistent database', function () { var d; beforeEach(function (done) { d = new Datastore({ inMemoryOnly: true }); d.inMemoryOnly.should.equal(true); d.loadDatabase(function (err) { assert.isNull(err); d.getAllData().length.should.equal(0); return done(); }); }); it('A throw in a callback doesnt prevent execution of next operations', function(done) { testThrowInCallback(d, done); }); it('Operations are executed in the right order', function(done) { testRightOrder(d, done); }); }); // ==== End of 'With non persistent database' ==== });