diff --git a/test/functional/byo_promises.test.js b/test/functional/byo_promises.test.js index b712774f80..84521ae377 100644 --- a/test/functional/byo_promises.test.js +++ b/test/functional/byo_promises.test.js @@ -1,11 +1,16 @@ 'use strict'; -var expect = require('chai').expect; +const { expect } = require('chai'); +const { PromiseProvider } = require('../../src/promise_provider'); class CustomPromise extends Promise {} CustomPromise.prototype.isCustomMongo = true; describe('Optional PromiseLibrary / maybePromise', function () { + afterEach(() => { + PromiseProvider.set(Promise); + }); + it('should correctly implement custom dependency-less promise', function (done) { const getCustomPromise = v => new CustomPromise(resolve => resolve(v)); const getNativePromise = v => new Promise(resolve => resolve(v)); diff --git a/test/functional/collations.test.js b/test/functional/collations.test.js deleted file mode 100644 index 4ab73816d0..0000000000 --- a/test/functional/collations.test.js +++ /dev/null @@ -1,580 +0,0 @@ -'use strict'; -const setupDatabase = require('./shared').setupDatabase; -const mock = require('../tools/mongodb-mock/index'); -const expect = require('chai').expect; -const { Long, Code } = require('../../src'); -const { isHello } = require('../../src/utils'); - -const testContext = {}; -describe('Collation', function () { - before(function () { - return setupDatabase(this.configuration); - }); - - afterEach(() => mock.cleanup()); - beforeEach(() => { - return mock.createServer().then(mockServer => (testContext.server = mockServer)); - }); - - it('Successfully pass through collation to count command', { - metadata: { requires: { generators: true, topology: 'single' } }, - - test: function () { - const configuration = this.configuration; - const client = configuration.newClient(`mongodb://${testContext.server.uri()}/test`); - const primary = [Object.assign({}, mock.HELLO)]; - - let commandResult; - testContext.server.setMessageHandler(request => { - const doc = request.document; - if (isHello(doc)) { - request.reply(primary[0]); - } else if (doc.count) { - commandResult = doc; - request.reply({ ok: 1, result: { n: 1 } }); - } else if (doc.endSessions) { - request.reply({ ok: 1 }); - } - }); - - return client.connect().then(() => { - const db = client.db(configuration.db); - - return db - .collection('test') - .estimatedDocumentCount({ collation: { caseLevel: true } }) - .then(() => { - expect(commandResult).to.have.property('collation'); - expect(commandResult.collation).to.eql({ caseLevel: true }); - return client.close(); - }); - }); - } - }); - - it('Successfully pass through collation to aggregation command', { - metadata: { requires: { generators: true, topology: 'single' } }, - - test: function () { - const configuration = this.configuration; - const client = configuration.newClient(`mongodb://${testContext.server.uri()}/test`); - const primary = [Object.assign({}, mock.HELLO)]; - - let commandResult; - testContext.server.setMessageHandler(request => { - const doc = request.document; - if (isHello(doc)) { - request.reply(primary[0]); - } else if (doc.aggregate) { - commandResult = doc; - request.reply({ ok: 1, cursor: { id: 0, firstBatch: [], ns: configuration.db } }); - } else if (doc.endSessions) { - request.reply({ ok: 1 }); - } - }); - - return client.connect().then(() => { - const db = client.db(configuration.db); - return db - .collection('test') - .aggregate([{ $match: {} }, { $out: 'readConcernCollectionAggregate1Output' }], { - collation: { caseLevel: true } - }) - .toArray() - .then(() => { - expect(commandResult).to.have.property('collation'); - expect(commandResult.collation).to.eql({ caseLevel: true }); - return client.close(); - }); - }); - } - }); - - it('Successfully pass through collation to distinct command', { - metadata: { requires: { generators: true, topology: 'single' } }, - - test: function () { - const configuration = this.configuration; - const client = configuration.newClient(`mongodb://${testContext.server.uri()}/test`); - const primary = [Object.assign({}, mock.HELLO)]; - - let commandResult; - testContext.server.setMessageHandler(request => { - var doc = request.document; - if (isHello(doc)) { - request.reply(primary[0]); - } else if (doc.distinct) { - commandResult = doc; - request.reply({ ok: 1 }); - } else if (doc.endSessions) { - request.reply({ ok: 1 }); - } - }); - - return client.connect().then(() => { - const db = client.db(configuration.db); - - return db - .collection('test') - .distinct('a', {}, { collation: { caseLevel: true } }) - .then(() => { - expect(commandResult).to.have.property('collation'); - expect(commandResult.collation).to.eql({ caseLevel: true }); - return client.close(); - }); - }); - } - }); - - it('Successfully pass through collation to mapReduce command', { - metadata: { requires: { generators: true, topology: 'single' } }, - - test: function () { - const configuration = this.configuration; - const client = configuration.newClient(`mongodb://${testContext.server.uri()}/test`); - const primary = [Object.assign({}, mock.HELLO)]; - - let commandResult; - testContext.server.setMessageHandler(request => { - var doc = request.document; - if (isHello(doc)) { - request.reply(primary[0]); - } else if (doc.mapReduce) { - commandResult = doc; - request.reply({ ok: 1, result: 'tempCollection' }); - } else if (doc.endSessions) { - request.reply({ ok: 1 }); - } - }); - - return client.connect().then(() => { - const db = client.db(configuration.db); - const map = new Code('function() { emit(this.user_id, 1); }'); - const reduce = new Code('function(k,vals) { return 1; }'); - - return db - .collection('test') - .mapReduce(map, reduce, { - out: { replace: 'tempCollection' }, - collation: { caseLevel: true } - }) - .then(() => { - expect(commandResult).to.have.property('collation'); - expect(commandResult.collation).to.eql({ caseLevel: true }); - return client.close(); - }); - }); - } - }); - - it('Successfully pass through collation to remove command', { - metadata: { requires: { generators: true, topology: 'single' } }, - - test: function () { - const configuration = this.configuration; - const client = configuration.newClient(`mongodb://${testContext.server.uri()}/test`); - const primary = [Object.assign({}, mock.HELLO)]; - - let commandResult; - testContext.server.setMessageHandler(request => { - var doc = request.document; - if (isHello(doc)) { - request.reply(primary[0]); - } else if (doc.delete) { - commandResult = doc; - request.reply({ ok: 1 }); - } else if (doc.endSessions) { - request.reply({ ok: 1 }); - } - }); - - return client.connect().then(() => { - const db = client.db(configuration.db); - return db - .collection('test') - .deleteMany({}, { collation: { caseLevel: true } }) - .then(() => { - expect(commandResult.deletes).to.have.length.at.least(1); - expect(commandResult.deletes[0]).to.have.property('collation'); - expect(commandResult.deletes[0].collation).to.eql({ caseLevel: true }); - return client.close(); - }); - }); - } - }); - - it('Successfully pass through collation to update command', { - metadata: { requires: { generators: true, topology: 'single' } }, - - test: function () { - const configuration = this.configuration; - const client = configuration.newClient(`mongodb://${testContext.server.uri()}/test`); - const primary = [Object.assign({}, mock.HELLO)]; - - let commandResult; - testContext.server.setMessageHandler(request => { - const doc = request.document; - if (isHello(doc)) { - request.reply(primary[0]); - } else if (doc.update) { - commandResult = doc; - request.reply({ ok: 1 }); - } else if (doc.endSessions) { - request.reply({ ok: 1 }); - } - }); - - return client.connect().then(() => { - const db = client.db(configuration.db); - - return db - .collection('test') - .updateOne({ a: 1 }, { $set: { b: 1 } }, { collation: { caseLevel: true } }) - .then(() => { - expect(commandResult.updates).to.have.length.at.least(1); - expect(commandResult.updates[0]).to.have.property('collation'); - expect(commandResult.updates[0].collation).to.eql({ caseLevel: true }); - - return client.close(); - }); - }); - } - }); - - it('Successfully pass through collation to find command via options', { - metadata: { requires: { generators: true, topology: 'single' } }, - - test: function () { - const configuration = this.configuration; - const client = configuration.newClient(`mongodb://${testContext.server.uri()}/test`); - const primary = [Object.assign({}, mock.HELLO)]; - - let commandResult; - testContext.server.setMessageHandler(request => { - const doc = request.document; - if (isHello(doc)) { - request.reply(primary[0]); - } else if (doc.find) { - commandResult = doc; - request.reply({ ok: 1, cursor: { id: 0, firstBatch: [] } }); - } else if (doc.endSessions) { - request.reply({ ok: 1 }); - } - }); - - return client.connect().then(() => { - const db = client.db(configuration.db); - - return db - .collection('test') - .find({ a: 1 }, { collation: { caseLevel: true } }) - .toArray() - .then(() => { - expect(commandResult).to.have.property('collation'); - expect(commandResult.collation).to.eql({ caseLevel: true }); - return client.close(); - }); - }); - } - }); - - it('Successfully pass through collation to find command via cursor', { - metadata: { requires: { generators: true, topology: 'single' } }, - test: function () { - const configuration = this.configuration; - const client = configuration.newClient(`mongodb://${testContext.server.uri()}/test`); - const primary = [Object.assign({}, mock.HELLO)]; - - let commandResult; - testContext.server.setMessageHandler(request => { - const doc = request.document; - if (isHello(doc)) { - request.reply(primary[0]); - } else if (doc.find) { - commandResult = doc; - request.reply({ ok: 1, cursor: { id: 0, firstBatch: [] } }); - } else if (doc.endSessions) { - request.reply({ ok: 1 }); - } - }); - - return client.connect().then(() => { - const db = client.db(configuration.db); - - return db - .collection('test') - .find({ a: 1 }) - .collation({ caseLevel: true }) - .toArray() - .then(() => { - expect(commandResult).to.have.property('collation'); - expect(commandResult.collation).to.eql({ caseLevel: true }); - - return client.close(); - }); - }); - } - }); - - it('Successfully pass through collation to findOne', { - metadata: { requires: { generators: true, topology: 'single' } }, - test: function () { - const configuration = this.configuration; - const client = configuration.newClient(`mongodb://${testContext.server.uri()}/test`); - const primary = [Object.assign({}, mock.HELLO)]; - - let commandResult; - testContext.server.setMessageHandler(request => { - const doc = request.document; - if (isHello(doc)) { - request.reply(primary[0]); - } else if (doc.find) { - commandResult = doc; - request.reply({ ok: 1, cursor: { id: 0, firstBatch: [] } }); - } else if (doc.endSessions) { - request.reply({ ok: 1 }); - } - }); - - return client.connect().then(() => { - const db = client.db(configuration.db); - - return db - .collection('test') - .findOne({ a: 1 }, { collation: { caseLevel: true } }) - .then(() => { - expect(commandResult).to.have.property('collation'); - expect(commandResult.collation).to.eql({ caseLevel: true }); - - return client.close(); - }); - }); - } - }); - - it('Successfully pass through collation to createCollection', { - metadata: { requires: { generators: true, topology: 'single' } }, - test: function () { - const configuration = this.configuration; - const client = configuration.newClient(`mongodb://${testContext.server.uri()}/test`); - const primary = [Object.assign({}, mock.HELLO)]; - - let commandResult; - testContext.server.setMessageHandler(request => { - const doc = request.document; - if (isHello(doc)) { - request.reply(primary[0]); - } else if (doc.listCollections) { - request.reply({ - ok: 1, - cursor: { - id: Long.fromNumber(0), - ns: 'test.cmd$.listCollections', - firstBatch: [] - } - }); - } else if (doc.create) { - commandResult = doc; - request.reply({ ok: 1 }); - } else if (doc.endSessions) { - request.reply({ ok: 1 }); - } - }); - - return client.connect().then(() => { - const db = client.db(configuration.db); - - return db.createCollection('test', { collation: { caseLevel: true } }).then(() => { - expect(commandResult).to.have.property('collation'); - expect(commandResult.collation).to.eql({ caseLevel: true }); - - return client.close(); - }); - }); - } - }); - - it('Successfully pass through collation to bulkWrite command', { - metadata: { requires: { generators: true, topology: 'single' } }, - test: function () { - const configuration = this.configuration; - const client = configuration.newClient(`mongodb://${testContext.server.uri()}/test`); - const primary = [Object.assign({}, mock.HELLO)]; - - let commandResult; - testContext.server.setMessageHandler(request => { - const doc = request.document; - if (isHello(doc)) { - request.reply(primary[0]); - } else if (doc.update) { - commandResult = doc; - request.reply({ ok: 1 }); - } else if (doc.delete) { - request.reply({ ok: 1 }); - } else if (doc.endSessions) { - request.reply({ ok: 1 }); - } - }); - - return client.connect().then(() => { - const db = client.db(configuration.db); - - return db - .collection('test') - .bulkWrite( - [ - { - updateOne: { - filter: { a: 2 }, - update: { $set: { a: 2 } }, - upsert: true, - collation: { caseLevel: true } - } - }, - { deleteOne: { filter: { c: 1 } } } - ], - { ordered: true } - ) - .then(() => { - expect(commandResult).to.exist; - expect(commandResult).to.have.property('updates'); - expect(commandResult.updates).to.have.length.at.least(1); - expect(commandResult.updates[0]).to.have.property('collation'); - expect(commandResult.updates[0].collation).to.eql({ caseLevel: true }); - - return client.close(); - }); - }); - } - }); - - it('Successfully create index with collation', { - metadata: { requires: { generators: true, topology: 'single' } }, - test: function () { - const configuration = this.configuration; - const client = configuration.newClient(`mongodb://${testContext.server.uri()}/test`); - const primary = [Object.assign({}, mock.HELLO)]; - - let commandResult; - testContext.server.setMessageHandler(request => { - const doc = request.document; - if (isHello(doc)) { - request.reply(primary[0]); - } else if (doc.createIndexes) { - commandResult = doc; - request.reply({ ok: 1 }); - } else if (doc.endSessions) { - request.reply({ ok: 1 }); - } - }); - - return client.connect().then(() => { - const db = client.db(configuration.db); - - return db - .collection('test') - .createIndex({ a: 1 }, { collation: { caseLevel: true } }) - .then(() => { - expect(commandResult).to.containSubset({ - createIndexes: 'test', - indexes: [{ name: 'a_1', key: { a: 1 }, collation: { caseLevel: true } }] - }); - - return client.close(); - }); - }); - } - }); - - it('cursor count method should return the correct number when used with collation set', { - metadata: { requires: { mongodb: '>=3.4.0' } }, - test: function (done) { - const configuration = this.configuration; - const client = configuration.newClient({ w: 1 }, { maxPoolSize: 1 }); - - client.connect().then(() => { - const db = client.db(configuration.db); - const docs = [ - { _id: 0, name: 'foo' }, - { _id: 1, name: 'Foo' } - ]; - const collation = { locale: 'en_US', strength: 2 }; - let collection, cursor; - const close = e => cursor.close(() => client.close(() => done(e))); - - Promise.resolve() - .then(() => db.createCollection('cursor_collation_count')) - .then(() => (collection = db.collection('cursor_collation_count'))) - .then(() => collection.insertMany(docs)) - .then(() => collection.find({ name: 'foo' }).collation(collation)) - .then(_cursor => (cursor = _cursor)) - .then(() => cursor.count()) - .then(val => expect(val).to.equal(2)) - .then(() => close()) - .catch(e => close(e)); - }); - } - }); - - /****************************************************************************** - .___ __ __ .__ - | | _____/ |_ ____ ________________ _/ |_|__| ____ ____ - | |/ \ __\/ __ \ / ___\_ __ \__ \\ __\ |/ _ \ / \ - | | | \ | \ ___// /_/ > | \// __ \| | | ( <_> ) | \ - |___|___| /__| \___ >___ /|__| (____ /__| |__|\____/|___| / - \/ \/_____/ \/ \/ - ******************************************************************************/ - it('Should correctly create index with collation', { - metadata: { requires: { topology: 'single', mongodb: '>=3.3.12' } }, - - test: function () { - const configuration = this.configuration; - const client = configuration.newClient(); - - return client.connect().then(() => { - const db = client.db(configuration.db); - const col = db.collection('collation_test'); - - return col - .createIndexes([ - { - key: { a: 1 }, - collation: { locale: 'nn' }, - name: 'collation_test' - } - ]) - .then(() => col.listIndexes().toArray()) - .then(r => { - const indexes = r.filter(i => i.name === 'collation_test'); - expect(indexes).to.have.length(1); - expect(indexes[0]).to.have.property('collation'); - expect(indexes[0].collation).to.exist; - return client.close(); - }); - }); - } - }); - - it('Should correctly create collection with collation', { - metadata: { requires: { topology: 'single', mongodb: '>=3.3.12' } }, - - test: function () { - const configuration = this.configuration; - const client = configuration.newClient(); - - return client.connect().then(() => { - const db = client.db(configuration.db); - - return db - .createCollection('collation_test2', { collation: { locale: 'nn' } }) - .then(() => db.listCollections({ name: 'collation_test2' }).toArray()) - .then(collections => { - expect(collections).to.have.length(1); - expect(collections[0].name).to.equal('collation_test2'); - expect(collections[0].options.collation).to.exist; - return client.close(); - }); - }); - } - }); -}); diff --git a/test/functional/cursor_async_iterator.test.js b/test/functional/cursor_async_iterator.test.js index 944235b92d..c4580350e6 100644 --- a/test/functional/cursor_async_iterator.test.js +++ b/test/functional/cursor_async_iterator.test.js @@ -3,6 +3,7 @@ const { expect } = require('chai'); const Sinon = require('sinon'); const { Promise: BluebirdPromise } = require('bluebird'); +const { PromiseProvider } = require('../../src/promise_provider'); describe('Cursor Async Iterator Tests', function () { context('default promise library', function () { @@ -87,7 +88,7 @@ describe('Cursor Async Iterator Tests', function () { }); context('custom promise library', () => { let client, collection, promiseSpy; - before(async function () { + beforeEach(async function () { promiseSpy = Sinon.spy(BluebirdPromise.prototype, 'then'); client = this.configuration.newClient({}, { promiseLibrary: BluebirdPromise }); @@ -111,6 +112,7 @@ describe('Cursor Async Iterator Tests', function () { afterEach(() => { promiseSpy.restore(); + PromiseProvider.set(Promise); return client.close(); }); diff --git a/test/functional/decimal128.test.js b/test/integration/bson-decimal128/decimal128.test.js similarity index 90% rename from test/functional/decimal128.test.js rename to test/integration/bson-decimal128/decimal128.test.js index 1de7aa82ac..0e2a39da3d 100644 --- a/test/functional/decimal128.test.js +++ b/test/integration/bson-decimal128/decimal128.test.js @@ -1,8 +1,8 @@ 'use strict'; -var test = require('./shared').assert; +const { assert: test } = require('../shared'); const { expect } = require('chai'); -var setupDatabase = require('./shared').setupDatabase; -const { Decimal128 } = require('../../src'); +const { setupDatabase } = require('../shared'); +const { Decimal128 } = require('../../../src'); describe('Decimal128', function () { before(function () { diff --git a/test/integration/collation/collations.test.js b/test/integration/collation/collations.test.js new file mode 100644 index 0000000000..4649e92121 --- /dev/null +++ b/test/integration/collation/collations.test.js @@ -0,0 +1,101 @@ +'use strict'; +const { setupDatabase } = require('../shared'); +const { expect } = require('chai'); + +describe('Collation', function () { + before(function () { + return setupDatabase(this.configuration); + }); + + it('cursor count method should return the correct number when used with collation set', { + metadata: { requires: { mongodb: '>=3.4.0' } }, + test: function (done) { + const configuration = this.configuration; + const client = configuration.newClient({ w: 1 }, { maxPoolSize: 1 }); + + client.connect().then(() => { + const db = client.db(configuration.db); + const docs = [ + { _id: 0, name: 'foo' }, + { _id: 1, name: 'Foo' } + ]; + const collation = { locale: 'en_US', strength: 2 }; + let collection, cursor; + const close = e => cursor.close(() => client.close(() => done(e))); + + Promise.resolve() + .then(() => db.createCollection('cursor_collation_count')) + .then(() => (collection = db.collection('cursor_collation_count'))) + .then(() => collection.insertMany(docs)) + .then(() => collection.find({ name: 'foo' }).collation(collation)) + .then(_cursor => (cursor = _cursor)) + .then(() => cursor.count()) + .then(val => expect(val).to.equal(2)) + .then(() => close()) + .catch(e => close(e)); + }); + } + }); + + /****************************************************************************** + .___ __ __ .__ + | | _____/ |_ ____ ________________ _/ |_|__| ____ ____ + | |/ \ __\/ __ \ / ___\_ __ \__ \\ __\ |/ _ \ / \ + | | | \ | \ ___// /_/ > | \// __ \| | | ( <_> ) | \ + |___|___| /__| \___ >___ /|__| (____ /__| |__|\____/|___| / + \/ \/_____/ \/ \/ + ******************************************************************************/ + it('Should correctly create index with collation', { + metadata: { requires: { topology: 'single', mongodb: '>=3.3.12' } }, + + test: function () { + const configuration = this.configuration; + const client = configuration.newClient(); + + return client.connect().then(() => { + const db = client.db(configuration.db); + const col = db.collection('collation_test'); + + return col + .createIndexes([ + { + key: { a: 1 }, + collation: { locale: 'nn' }, + name: 'collation_test' + } + ]) + .then(() => col.listIndexes().toArray()) + .then(r => { + const indexes = r.filter(i => i.name === 'collation_test'); + expect(indexes).to.have.length(1); + expect(indexes[0]).to.have.property('collation'); + expect(indexes[0].collation).to.exist; + return client.close(); + }); + }); + } + }); + + it('Should correctly create collection with collation', { + metadata: { requires: { topology: 'single', mongodb: '>=3.3.12' } }, + + test: function () { + const configuration = this.configuration; + const client = configuration.newClient(); + + return client.connect().then(() => { + const db = client.db(configuration.db); + + return db + .createCollection('collation_test2', { collation: { locale: 'nn' } }) + .then(() => db.listCollections({ name: 'collation_test2' }).toArray()) + .then(collections => { + expect(collections).to.have.length(1); + expect(collections[0].name).to.equal('collation_test2'); + expect(collections[0].options.collation).to.exist; + return client.close(); + }); + }); + } + }); +}); diff --git a/test/functional/collection.test.js b/test/integration/collection-management/collection.test.js similarity index 99% rename from test/functional/collection.test.js rename to test/integration/collection-management/collection.test.js index 6f1f0d5214..db2fbe5630 100644 --- a/test/functional/collection.test.js +++ b/test/integration/collection-management/collection.test.js @@ -1,13 +1,13 @@ 'use strict'; -const setupDatabase = require('./shared').setupDatabase; +const { setupDatabase } = require('../shared'); const chai = require('chai'); const expect = chai.expect; const sinonChai = require('sinon-chai'); -const mock = require('../tools/mongodb-mock/index'); +const mock = require('../../tools/mongodb-mock/index'); chai.use(sinonChai); -const { isHello } = require('../../src/utils'); +const { isHello } = require('../../../src/utils'); describe('Collection', function () { let configuration; diff --git a/test/functional/find.test.js b/test/integration/crud/find.test.js similarity index 99% rename from test/functional/find.test.js rename to test/integration/crud/find.test.js index c337a0f766..7b68434149 100644 --- a/test/functional/find.test.js +++ b/test/integration/crud/find.test.js @@ -1,9 +1,8 @@ 'use strict'; -const test = require('./shared').assert; -const { setupDatabase, withMonitoredClient } = require('./shared'); +const { assert: test, setupDatabase, withMonitoredClient } = require('../shared'); const { expect } = require('chai'); const sinon = require('sinon'); -const { Code, ObjectId, Long, Binary, ReturnDocument } = require('../../src'); +const { Code, ObjectId, Long, Binary, ReturnDocument } = require('../../../src'); describe('Find', function () { before(function () { diff --git a/test/functional/find_and_modify.test.js b/test/integration/crud/find_and_modify.test.js similarity index 98% rename from test/functional/find_and_modify.test.js rename to test/integration/crud/find_and_modify.test.js index 0739c8f8a1..c47f72ac73 100644 --- a/test/functional/find_and_modify.test.js +++ b/test/integration/crud/find_and_modify.test.js @@ -1,8 +1,7 @@ 'use strict'; var f = require('util').format; -var test = require('./shared').assert; -const { setupDatabase, withClient } = require(`./shared`); +const { setupDatabase, withClient, assert: test } = require(`../shared`); const { expect } = require('chai'); describe('Find and Modify', function () { diff --git a/test/functional/remove.test.js b/test/integration/crud/remove.test.js similarity index 99% rename from test/functional/remove.test.js rename to test/integration/crud/remove.test.js index 70fdfcc255..9283f0c5d9 100644 --- a/test/functional/remove.test.js +++ b/test/integration/crud/remove.test.js @@ -1,6 +1,6 @@ 'use strict'; const { expect } = require('chai'); -const { setupDatabase } = require('./shared'); +const { setupDatabase } = require('../shared'); describe('Remove', function () { before(function () { diff --git a/test/functional/index.test.js b/test/integration/index_management.test.js similarity index 99% rename from test/functional/index.test.js rename to test/integration/index_management.test.js index bab7a9caff..12ce5acbf2 100644 --- a/test/functional/index.test.js +++ b/test/integration/index_management.test.js @@ -1,6 +1,7 @@ 'use strict'; const { expect } = require('chai'); const { assert: test, setupDatabase, withClient, withMonitoredClient } = require('./shared'); +const shared = require('../tools/contexts'); describe('Indexes', function () { before(function () { @@ -640,7 +641,6 @@ describe('Indexes', function () { var client = configuration.newClient(configuration.writeConcernMax(), { maxPoolSize: 1 }); client.connect(function (err, client) { var db = client.db(configuration.db); - var shared = require('./contexts'); db.collection('indexcontext').createIndex( shared.object, diff --git a/test/functional/readconcern.test.js b/test/integration/read-write-concern/readconcern.test.js similarity index 99% rename from test/functional/readconcern.test.js rename to test/integration/read-write-concern/readconcern.test.js index b923c48696..765ba7d8da 100644 --- a/test/functional/readconcern.test.js +++ b/test/integration/read-write-concern/readconcern.test.js @@ -1,6 +1,5 @@ 'use strict'; -const setupDatabase = require('./shared').setupDatabase; -const filterForCommands = require('./shared').filterForCommands; +const { setupDatabase, filterForCommands } = require('../shared'); const expect = require('chai').expect; describe('ReadConcern', function () { diff --git a/test/functional/contexts/index.js b/test/tools/contexts/index.js similarity index 100% rename from test/functional/contexts/index.js rename to test/tools/contexts/index.js diff --git a/test/functional/contexts/other.js b/test/tools/contexts/other.js similarity index 100% rename from test/functional/contexts/other.js rename to test/tools/contexts/other.js diff --git a/test/functional/contexts/shared.js b/test/tools/contexts/shared.js similarity index 100% rename from test/functional/contexts/shared.js rename to test/tools/contexts/shared.js diff --git a/test/unit/_MISC_collations.test.js b/test/unit/_MISC_collations.test.js new file mode 100644 index 0000000000..a0ae64fea6 --- /dev/null +++ b/test/unit/_MISC_collations.test.js @@ -0,0 +1,429 @@ +'use strict'; +const mock = require('../tools/mongodb-mock/index'); +const { expect } = require('chai'); +const { Long, Code } = require('../../src'); +const { isHello } = require('../../src/utils'); +const { MongoClient } = require('../../src'); + +const testContext = {}; +describe('Collation', function () { + afterEach(() => mock.cleanup()); + beforeEach(() => { + return mock.createServer().then(mockServer => (testContext.server = mockServer)); + }); + + it('Successfully pass through collation to count command', () => { + const client = new MongoClient(`mongodb://${testContext.server.uri()}/test`); + const primary = [Object.assign({}, mock.HELLO)]; + + let commandResult; + testContext.server.setMessageHandler(request => { + const doc = request.document; + if (isHello(doc)) { + request.reply(primary[0]); + } else if (doc.count) { + commandResult = doc; + request.reply({ ok: 1, result: { n: 1 } }); + } else if (doc.endSessions) { + request.reply({ ok: 1 }); + } + }); + + return client.connect().then(() => { + const db = client.db('collation_test'); + + return db + .collection('test') + .estimatedDocumentCount({ collation: { caseLevel: true } }) + .then(() => { + expect(commandResult).to.have.property('collation'); + expect(commandResult.collation).to.eql({ caseLevel: true }); + return client.close(); + }); + }); + }); + + it('Successfully pass through collation to aggregation command', () => { + const client = new MongoClient(`mongodb://${testContext.server.uri()}/test`); + const primary = [Object.assign({}, mock.HELLO)]; + + let commandResult; + testContext.server.setMessageHandler(request => { + const doc = request.document; + if (isHello(doc)) { + request.reply(primary[0]); + } else if (doc.aggregate) { + commandResult = doc; + request.reply({ ok: 1, cursor: { id: 0, firstBatch: [], ns: 'collation_test' } }); + } else if (doc.endSessions) { + request.reply({ ok: 1 }); + } + }); + + return client.connect().then(() => { + const db = client.db('collation_test'); + return db + .collection('test') + .aggregate([{ $match: {} }, { $out: 'readConcernCollectionAggregate1Output' }], { + collation: { caseLevel: true } + }) + .toArray() + .then(() => { + expect(commandResult).to.have.property('collation'); + expect(commandResult.collation).to.eql({ caseLevel: true }); + return client.close(); + }); + }); + }); + + it('Successfully pass through collation to distinct command', () => { + const client = new MongoClient(`mongodb://${testContext.server.uri()}/test`); + const primary = [Object.assign({}, mock.HELLO)]; + + let commandResult; + testContext.server.setMessageHandler(request => { + var doc = request.document; + if (isHello(doc)) { + request.reply(primary[0]); + } else if (doc.distinct) { + commandResult = doc; + request.reply({ ok: 1 }); + } else if (doc.endSessions) { + request.reply({ ok: 1 }); + } + }); + + return client.connect().then(() => { + const db = client.db('collation_db'); + + return db + .collection('test') + .distinct('a', {}, { collation: { caseLevel: true } }) + .then(() => { + expect(commandResult).to.have.property('collation'); + expect(commandResult.collation).to.eql({ caseLevel: true }); + return client.close(); + }); + }); + }); + + it('Successfully pass through collation to mapReduce command', () => { + const client = new MongoClient(`mongodb://${testContext.server.uri()}/test`); + const primary = [Object.assign({}, mock.HELLO)]; + + let commandResult; + testContext.server.setMessageHandler(request => { + var doc = request.document; + if (isHello(doc)) { + request.reply(primary[0]); + } else if (doc.mapReduce) { + commandResult = doc; + request.reply({ ok: 1, result: 'tempCollection' }); + } else if (doc.endSessions) { + request.reply({ ok: 1 }); + } + }); + + return client.connect().then(() => { + const db = client.db('collation_db'); + const map = new Code('function() { emit(this.user_id, 1); }'); + const reduce = new Code('function(k,vals) { return 1; }'); + + return db + .collection('test') + .mapReduce(map, reduce, { + out: { replace: 'tempCollection' }, + collation: { caseLevel: true } + }) + .then(() => { + expect(commandResult).to.have.property('collation'); + expect(commandResult.collation).to.eql({ caseLevel: true }); + return client.close(); + }); + }); + }); + + it('Successfully pass through collation to remove command', () => { + const client = new MongoClient(`mongodb://${testContext.server.uri()}/test`); + const primary = [Object.assign({}, mock.HELLO)]; + + let commandResult; + testContext.server.setMessageHandler(request => { + var doc = request.document; + if (isHello(doc)) { + request.reply(primary[0]); + } else if (doc.delete) { + commandResult = doc; + request.reply({ ok: 1 }); + } else if (doc.endSessions) { + request.reply({ ok: 1 }); + } + }); + + return client.connect().then(() => { + const db = client.db('collation_db'); + return db + .collection('test') + .deleteMany({}, { collation: { caseLevel: true } }) + .then(() => { + expect(commandResult.deletes).to.have.length.at.least(1); + expect(commandResult.deletes[0]).to.have.property('collation'); + expect(commandResult.deletes[0].collation).to.eql({ caseLevel: true }); + return client.close(); + }); + }); + }); + + it('Successfully pass through collation to update command', () => { + const client = new MongoClient(`mongodb://${testContext.server.uri()}/test`); + const primary = [Object.assign({}, mock.HELLO)]; + + let commandResult; + testContext.server.setMessageHandler(request => { + const doc = request.document; + if (isHello(doc)) { + request.reply(primary[0]); + } else if (doc.update) { + commandResult = doc; + request.reply({ ok: 1 }); + } else if (doc.endSessions) { + request.reply({ ok: 1 }); + } + }); + + return client.connect().then(() => { + const db = client.db('collation_db'); + + return db + .collection('test') + .updateOne({ a: 1 }, { $set: { b: 1 } }, { collation: { caseLevel: true } }) + .then(() => { + expect(commandResult.updates).to.have.length.at.least(1); + expect(commandResult.updates[0]).to.have.property('collation'); + expect(commandResult.updates[0].collation).to.eql({ caseLevel: true }); + + return client.close(); + }); + }); + }); + + it('Successfully pass through collation to find command via options', () => { + const client = new MongoClient(`mongodb://${testContext.server.uri()}/test`); + const primary = [Object.assign({}, mock.HELLO)]; + + let commandResult; + testContext.server.setMessageHandler(request => { + const doc = request.document; + if (isHello(doc)) { + request.reply(primary[0]); + } else if (doc.find) { + commandResult = doc; + request.reply({ ok: 1, cursor: { id: 0, firstBatch: [] } }); + } else if (doc.endSessions) { + request.reply({ ok: 1 }); + } + }); + + return client.connect().then(() => { + const db = client.db('collation_db'); + + return db + .collection('test') + .find({ a: 1 }, { collation: { caseLevel: true } }) + .toArray() + .then(() => { + expect(commandResult).to.have.property('collation'); + expect(commandResult.collation).to.eql({ caseLevel: true }); + return client.close(); + }); + }); + }); + + it('Successfully pass through collation to find command via cursor', () => { + const client = new MongoClient(`mongodb://${testContext.server.uri()}/test`); + const primary = [Object.assign({}, mock.HELLO)]; + + let commandResult; + testContext.server.setMessageHandler(request => { + const doc = request.document; + if (isHello(doc)) { + request.reply(primary[0]); + } else if (doc.find) { + commandResult = doc; + request.reply({ ok: 1, cursor: { id: 0, firstBatch: [] } }); + } else if (doc.endSessions) { + request.reply({ ok: 1 }); + } + }); + + return client.connect().then(() => { + const db = client.db('collation_db'); + + return db + .collection('test') + .find({ a: 1 }) + .collation({ caseLevel: true }) + .toArray() + .then(() => { + expect(commandResult).to.have.property('collation'); + expect(commandResult.collation).to.eql({ caseLevel: true }); + + return client.close(); + }); + }); + }); + + it('Successfully pass through collation to findOne', () => { + const client = new MongoClient(`mongodb://${testContext.server.uri()}/test`); + const primary = [Object.assign({}, mock.HELLO)]; + + let commandResult; + testContext.server.setMessageHandler(request => { + const doc = request.document; + if (isHello(doc)) { + request.reply(primary[0]); + } else if (doc.find) { + commandResult = doc; + request.reply({ ok: 1, cursor: { id: 0, firstBatch: [] } }); + } else if (doc.endSessions) { + request.reply({ ok: 1 }); + } + }); + + return client.connect().then(() => { + const db = client.db('collation_db'); + + return db + .collection('test') + .findOne({ a: 1 }, { collation: { caseLevel: true } }) + .then(() => { + expect(commandResult).to.have.property('collation'); + expect(commandResult.collation).to.eql({ caseLevel: true }); + + return client.close(); + }); + }); + }); + + it('Successfully pass through collation to createCollection', () => { + const client = new MongoClient(`mongodb://${testContext.server.uri()}/test`); + const primary = [Object.assign({}, mock.HELLO)]; + + let commandResult; + testContext.server.setMessageHandler(request => { + const doc = request.document; + if (isHello(doc)) { + request.reply(primary[0]); + } else if (doc.listCollections) { + request.reply({ + ok: 1, + cursor: { + id: Long.fromNumber(0), + ns: 'test.cmd$.listCollections', + firstBatch: [] + } + }); + } else if (doc.create) { + commandResult = doc; + request.reply({ ok: 1 }); + } else if (doc.endSessions) { + request.reply({ ok: 1 }); + } + }); + + return client.connect().then(() => { + const db = client.db('collation_db'); + + return db.createCollection('test', { collation: { caseLevel: true } }).then(() => { + expect(commandResult).to.have.property('collation'); + expect(commandResult.collation).to.eql({ caseLevel: true }); + + return client.close(); + }); + }); + }); + + it('Successfully pass through collation to bulkWrite command', () => { + const client = new MongoClient(`mongodb://${testContext.server.uri()}/test`); + const primary = [Object.assign({}, mock.HELLO)]; + + let commandResult; + testContext.server.setMessageHandler(request => { + const doc = request.document; + if (isHello(doc)) { + request.reply(primary[0]); + } else if (doc.update) { + commandResult = doc; + request.reply({ ok: 1 }); + } else if (doc.delete) { + request.reply({ ok: 1 }); + } else if (doc.endSessions) { + request.reply({ ok: 1 }); + } + }); + + return client.connect().then(() => { + const db = client.db('collation_db'); + + return db + .collection('test') + .bulkWrite( + [ + { + updateOne: { + filter: { a: 2 }, + update: { $set: { a: 2 } }, + upsert: true, + collation: { caseLevel: true } + } + }, + { deleteOne: { filter: { c: 1 } } } + ], + { ordered: true } + ) + .then(() => { + expect(commandResult).to.exist; + expect(commandResult).to.have.property('updates'); + expect(commandResult.updates).to.have.length.at.least(1); + expect(commandResult.updates[0]).to.have.property('collation'); + expect(commandResult.updates[0].collation).to.eql({ caseLevel: true }); + + return client.close(); + }); + }); + }); + + it('Successfully create index with collation', () => { + const client = new MongoClient(`mongodb://${testContext.server.uri()}/test`); + const primary = [Object.assign({}, mock.HELLO)]; + + let commandResult; + testContext.server.setMessageHandler(request => { + const doc = request.document; + if (isHello(doc)) { + request.reply(primary[0]); + } else if (doc.createIndexes) { + commandResult = doc; + request.reply({ ok: 1 }); + } else if (doc.endSessions) { + request.reply({ ok: 1 }); + } + }); + + return client.connect().then(() => { + const db = client.db('collation_db'); + + return db + .collection('test') + .createIndex({ a: 1 }, { collation: { caseLevel: true } }) + .then(() => { + expect(commandResult).to.containSubset({ + createIndexes: 'test', + indexes: [{ name: 'a_1', key: { a: 1 }, collation: { caseLevel: true } }] + }); + + return client.close(); + }); + }); + }); +}); diff --git a/test/functional/command_write_concern.test.js b/test/unit/_MISC_write_concern.test.js similarity index 78% rename from test/functional/command_write_concern.test.js rename to test/unit/_MISC_write_concern.test.js index 72317ebab1..aa266b4a86 100644 --- a/test/functional/command_write_concern.test.js +++ b/test/unit/_MISC_write_concern.test.js @@ -1,15 +1,14 @@ 'use strict'; const mock = require('../tools/mongodb-mock/index'); const expect = require('chai').expect; -const { ObjectId, Code } = require('../../src'); +const { ObjectId, Code, MongoClient } = require('../../src'); const { LEGACY_HELLO_COMMAND } = require('../../src/constants'); const { isHello } = require('../../src/utils'); const TEST_OPTIONS = { writeConcern: { w: 2, wtimeoutMS: 1000 } }; class WriteConcernTest { - constructor(configuration) { - this.configuration = configuration; + constructor() { this.responseDecoration = {}; const electionIds = [new ObjectId(), new ObjectId()]; const defaultFields = Object.assign({}, mock.HELLO, { @@ -86,21 +85,21 @@ class WriteConcernTest { } }); - const client = self.configuration.newClient( + const client = new MongoClient( 'mongodb://localhost:32000,localhost:32001,localhost:32002/test?replicaSet=rs' ); await client.connect(); - await testFn(client, client.db(self.configuration.db)); + await testFn(client, client.db('write_concern_db')); } } function writeConcernTest(command, testFn) { return async function () { - const t = new WriteConcernTest(this.configuration); + const t = new WriteConcernTest(); switch (command) { case 'aggregate': - t.decorateResponse({ cursor: { id: 0, firstBatch: [], ns: this.configuration.db } }); + t.decorateResponse({ cursor: { id: 0, firstBatch: [], ns: 'write_concern_db' } }); break; case 'mapReduce': t.decorateResponse({ result: 'tempCollection' }); @@ -119,11 +118,9 @@ function writeConcernTest(command, testFn) { describe('Command Write Concern', function () { afterEach(() => mock.cleanup()); - const metadata = { requires: { generators: true, topology: 'single' } }; - it('successfully pass through writeConcern to aggregate command', { - metadata, - test: writeConcernTest('aggregate', (db, writeConcernTestOptions) => + it('successfully pass through writeConcern to aggregate command', () => + writeConcernTest('aggregate', (db, writeConcernTestOptions) => db .collection('test') .aggregate( @@ -131,52 +128,40 @@ describe('Command Write Concern', function () { writeConcernTestOptions ) .toArray() - ) - }); + )); - it('successfully pass through writeConcern to create command', { - metadata, - test: writeConcernTest('create', (db, writeConcernTestOptions) => + it('successfully pass through writeConcern to create command', () => + writeConcernTest('create', (db, writeConcernTestOptions) => db.createCollection('test_collection_methods', writeConcernTestOptions) - ) - }); + )); - it('successfully pass through writeConcern to createIndexes command', { - metadata, - test: writeConcernTest('createIndexes', (db, writeConcernTestOptions) => + it('successfully pass through writeConcern to createIndexes command', () => + writeConcernTest('createIndexes', (db, writeConcernTestOptions) => db .collection('indexOptionDefault') .createIndex( { a: 1 }, Object.assign({ indexOptionDefaults: true }, writeConcernTestOptions) ) - ) - }); + )); - it('successfully pass through writeConcern to drop command', { - metadata, - test: writeConcernTest('drop', (db, writeConcernTestOptions) => + it('successfully pass through writeConcern to drop command', () => + writeConcernTest('drop', (db, writeConcernTestOptions) => db.collection('indexOptionDefault').drop(writeConcernTestOptions) - ) - }); + )); - it('successfully pass through writeConcern to dropDatabase command', { - metadata, - test: writeConcernTest('dropDatabase', (db, writeConcernTestOptions) => + it('successfully pass through writeConcern to dropDatabase command', () => + writeConcernTest('dropDatabase', (db, writeConcernTestOptions) => db.dropDatabase(writeConcernTestOptions) - ) - }); + )); - it('successfully pass through writeConcern to dropIndexes command', { - metadata, - test: writeConcernTest('dropIndexes', (db, writeConcernTestOptions) => + it('successfully pass through writeConcern to dropIndexes command', () => + writeConcernTest('dropIndexes', (db, writeConcernTestOptions) => db.collection('test').dropIndexes(writeConcernTestOptions) - ) - }); + )); - it('successfully pass through writeConcern to mapReduce command', { - metadata, - test: writeConcernTest('mapReduce', function (db, writeConcernTestOptions) { + it('successfully pass through writeConcern to mapReduce command', () => + writeConcernTest('mapReduce', function (db, writeConcernTestOptions) { const map = new Code('function() { emit(this.user_id, 1); }'); const reduce = new Code('function(k,vals) { return 1; }'); return db @@ -186,20 +171,15 @@ describe('Command Write Concern', function () { reduce, Object.assign({ out: { replace: 'tempCollection' } }, writeConcernTestOptions) ); - }) - }); + })); - it('successfully pass through writeConcern to createUser command', { - metadata, - test: writeConcernTest('createUser', (db, writeConcernTestOptions) => + it('successfully pass through writeConcern to createUser command', () => + writeConcernTest('createUser', (db, writeConcernTestOptions) => db.admin().addUser('kay:kay', 'abc123', writeConcernTestOptions) - ) - }); + )); - it('successfully pass through writeConcern to dropUser command', { - metadata, - test: writeConcernTest('dropUser', (db, writeConcernTestOptions) => + it('successfully pass through writeConcern to dropUser command', () => + writeConcernTest('dropUser', (db, writeConcernTestOptions) => db.admin().removeUser('kay:kay', writeConcernTestOptions) - ) - }); + )); });