From 70e6d4066c2fd8b95746ed47edaf5081f1add077 Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Wed, 7 Jun 2023 11:11:01 -0400 Subject: [PATCH 01/24] changed to typescript --- test/integration/crud/{explain.test.js => explain.test.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/integration/crud/{explain.test.js => explain.test.ts} (100%) diff --git a/test/integration/crud/explain.test.js b/test/integration/crud/explain.test.ts similarity index 100% rename from test/integration/crud/explain.test.js rename to test/integration/crud/explain.test.ts From 7224009a993d38bac8c7ec14dbd91286f0a675b2 Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Wed, 7 Jun 2023 11:17:22 -0400 Subject: [PATCH 02/24] fixed formatting --- test/integration/crud/explain.test.ts | 68 +++++++++++++-------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index aa9c6a2ff5..ca74b4ce26 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -1,9 +1,7 @@ -'use strict'; -const { setupDatabase } = require('../shared'); -const { MongoServerError } = require('../../mongodb'); -const chai = require('chai'); +import { expect } from 'chai'; -const expect = chai.expect; +import { MongoServerError } from '../../mongodb'; +import { setupDatabase } from '../shared'; describe('Explain', function () { let client; @@ -27,8 +25,8 @@ describe('Explain', function () { } }, test: function (done) { - var db = client.db('shouldHonorBooleanExplainWithDeleteOne'); - var collection = db.collection('test'); + const db = client.db('shouldHonorBooleanExplainWithDeleteOne'); + const collection = db.collection('test'); collection.insertOne({ a: 1 }, (err, res) => { expect(err).to.not.exist; @@ -51,8 +49,8 @@ describe('Explain', function () { } }, test: function (done) { - var db = client.db('shouldHonorBooleanExplainWithDeleteMany'); - var collection = db.collection('test'); + const db = client.db('shouldHonorBooleanExplainWithDeleteMany'); + const collection = db.collection('test'); collection.insertOne({ a: 1 }, (err, res) => { expect(err).to.not.exist; @@ -75,8 +73,8 @@ describe('Explain', function () { } }, test: function (done) { - var db = client.db('shouldHonorBooleanExplainWithUpdateOne'); - var collection = db.collection('test'); + const db = client.db('shouldHonorBooleanExplainWithUpdateOne'); + const collection = db.collection('test'); collection.insertOne({ a: 1 }, (err, res) => { expect(err).to.not.exist; @@ -104,8 +102,8 @@ describe('Explain', function () { } }, test: function (done) { - var db = client.db('shouldHonorBooleanExplainWithUpdateMany'); - var collection = db.collection('test'); + const db = client.db('shouldHonorBooleanExplainWithUpdateMany'); + const collection = db.collection('test'); collection.insertOne({ a: 1 }, (err, res) => { expect(err).to.not.exist; @@ -133,8 +131,8 @@ describe('Explain', function () { } }, test: function (done) { - var db = client.db('shouldHonorBooleanExplainWithRemoveOne'); - var collection = db.collection('test'); + const db = client.db('shouldHonorBooleanExplainWithRemoveOne'); + const collection = db.collection('test'); collection.insertOne({ a: 1 }, (err, res) => { expect(err).to.not.exist; @@ -157,8 +155,8 @@ describe('Explain', function () { } }, test: function (done) { - var db = client.db('shouldHonorBooleanExplainWithRemoveMany'); - var collection = db.collection('test'); + const db = client.db('shouldHonorBooleanExplainWithRemoveMany'); + const collection = db.collection('test'); collection.insertOne({ a: 1 }, (err, res) => { expect(err).to.not.exist; @@ -181,8 +179,8 @@ describe('Explain', function () { } }, test: function (done) { - var db = client.db('shouldHonorBooleanExplainWithDistinct'); - var collection = db.collection('test'); + const db = client.db('shouldHonorBooleanExplainWithDistinct'); + const collection = db.collection('test'); collection.insertOne({ a: 1 }, (err, res) => { expect(err).to.not.exist; @@ -205,8 +203,8 @@ describe('Explain', function () { } }, test: function (done) { - var db = client.db('shouldHonorBooleanExplainWithFindOneAndModify'); - var collection = db.collection('test'); + const db = client.db('shouldHonorBooleanExplainWithFindOneAndModify'); + const collection = db.collection('test'); collection.insertOne({ a: 1 }, (err, res) => { expect(err).to.not.exist; @@ -229,8 +227,8 @@ describe('Explain', function () { } }, test: function (done) { - var db = client.db('shouldUseAllPlansExecutionAsTrueExplainVerbosity'); - var collection = db.collection('test'); + const db = client.db('shouldUseAllPlansExecutionAsTrueExplainVerbosity'); + const collection = db.collection('test'); collection.insertOne({ a: 1 }, (err, res) => { expect(err).to.not.exist; @@ -255,8 +253,8 @@ describe('Explain', function () { } }, test: function (done) { - var db = client.db('shouldUseQueryPlannerAsFalseExplainVerbosity'); - var collection = db.collection('test'); + const db = client.db('shouldUseQueryPlannerAsFalseExplainVerbosity'); + const collection = db.collection('test'); collection.insertOne({ a: 1 }, (err, res) => { expect(err).to.not.exist; @@ -281,8 +279,8 @@ describe('Explain', function () { } }, test: function (done) { - var db = client.db('shouldHonorQueryPlannerStringExplain'); - var collection = db.collection('test'); + const db = client.db('shouldHonorQueryPlannerStringExplain'); + const collection = db.collection('test'); collection.insertOne({ a: 1 }, (err, res) => { expect(err).to.not.exist; @@ -307,8 +305,8 @@ describe('Explain', function () { } }, test: function (done) { - var db = client.db('shouldHonorExecutionStatsStringExplain'); - var collection = db.collection('test'); + const db = client.db('shouldHonorExecutionStatsStringExplain'); + const collection = db.collection('test'); collection.insertOne({ a: 1 }, (err, res) => { expect(err).to.not.exist; @@ -334,8 +332,8 @@ describe('Explain', function () { } }, test: function (done) { - var db = client.db('shouldHonorAllPlansStringExplain'); - var collection = db.collection('test'); + const db = client.db('shouldHonorAllPlansStringExplain'); + const collection = db.collection('test'); collection.insertOne({ a: 1 }, (err, res) => { expect(err).to.not.exist; @@ -360,8 +358,8 @@ describe('Explain', function () { } }, test: function (done) { - var db = client.db('shouldHonorStringExplainWithDistinct'); - var collection = db.collection('test'); + const db = client.db('shouldHonorStringExplainWithDistinct'); + const collection = db.collection('test'); collection.insertOne({ a: 1 }, (err, res) => { expect(err).to.not.exist; @@ -385,8 +383,8 @@ describe('Explain', function () { } }, test: function (done) { - var db = client.db('shouldHonorStringExplainWithFindOneAndModify'); - var collection = db.collection('test'); + const db = client.db('shouldHonorStringExplainWithFindOneAndModify'); + const collection = db.collection('test'); collection.insertOne({ a: 1 }, (err, res) => { expect(err).to.not.exist; From 1d80c77cb42684587dba062fb9557ec8efa2e26c Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Fri, 9 Jun 2023 16:13:13 -0400 Subject: [PATCH 03/24] test(NODE-5342): modernize explain tests --- test/integration/crud/explain.test.ts | 766 ++++++-------------------- 1 file changed, 172 insertions(+), 594 deletions(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index ca74b4ce26..8f706a9283 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -1,567 +1,168 @@ import { expect } from 'chai'; -import { MongoServerError } from '../../mongodb'; -import { setupDatabase } from '../shared'; +import { + type Collection, + type CommandStartedEvent, + type Db, + type MongoClient, + MongoServerError +} from '../../mongodb'; describe('Explain', function () { - let client; + let client: MongoClient; + let db: Db; + let collection: Collection; + let commandsStarted: CommandStartedEvent[]; beforeEach(async function () { - client = this.configuration.newClient(); + client = this.configuration.newClient({ monitorCommands: true }); + db = client.db('queryPlannerExplainResult'); + collection = db.collection('test'); + commandsStarted = []; + + await collection.insertOne({ a: 1 }); + client.on('commandStarted', event => commandsStarted.push(event)); }); afterEach(async function () { + await collection.drop(); await client.close(); + commandsStarted = []; }); - before(function () { - return setupDatabase(this.configuration); + context('when explain is set to true', () => { + it('deleteOne returns queryPlanner explain result', async function () { + const explanation = await collection.deleteOne({ a: 1 }, { explain: true }); + expect(explanation).property('queryPlanner').to.exist; + expect(commandsStarted[0]).to.have.nested.property('command.explain.delete'); + }); + + it('deleteMany returns queryPlanner explain result', async function () { + const explanation = await collection.deleteMany({ a: 1 }, { explain: true }); + expect(explanation).property('queryPlanner').to.exist; + }); + + it('updateOne returns queryPlanner explain result', async function () { + const explanation = await collection.updateOne( + { a: 1 }, + { $inc: { a: 2 } }, + { explain: true } + ); + expect(explanation).property('queryPlanner').to.exist; + }); + + it('updateMany returns queryPlanner explain result', async function () { + const explanation = await collection.updateMany( + { a: 1 }, + { $inc: { a: 2 } }, + { explain: true } + ); + expect(explanation).property('queryPlanner').to.exist; + }); + + it('distinct returns queryPlanner explain result', async function () { + const explanation = await collection.distinct('a', {}, { explain: true }); + expect(explanation).property('queryPlanner').to.exist; + }); + + it('findOneAndDelete returns queryPlanner explain result', async function () { + const explanation = await collection.findOneAndDelete({ a: 1 }, { explain: true }); + expect(explanation).property('queryPlanner').to.exist; + }); + + it('allPlansExecution returns verbose queryPlanner explain result', async function () { + const explanation = await collection.deleteOne({ a: 1 }, { explain: true }); + expect(explanation).property('queryPlanner').to.exist; + expect(explanation).nested.property('executionStats.allPlansExecution').to.exist; + }); + + it('findOne returns queryPlanner explain result', async function () { + const explanation = await collection.findOne({ a: 1 }, { explain: true }); + expect(explanation).property('queryPlanner').to.exist; + }); }); - it('should honor boolean explain with delete one', { - metadata: { - requires: { - mongodb: '>=3.0' - } - }, - test: function (done) { - const db = client.db('shouldHonorBooleanExplainWithDeleteOne'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - collection.deleteOne({ a: 1 }, { explain: true }, (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - done(); - }); + context('when explain is not set to true', () => { + context('when explain is set to false', () => { + it('only queryPlanner property is used in explain result', async function () { + const explanation = await collection.deleteOne({ a: 1 }, { explain: false }); + expect(explanation).property('queryPlanner').to.exist; + expect(explanation).to.not.have.property('executionStats'); }); - } - }); - it('should honor boolean explain with delete many', { - metadata: { - requires: { - mongodb: '>=3.0' - } - }, - test: function (done) { - const db = client.db('shouldHonorBooleanExplainWithDeleteMany'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - collection.deleteMany({ a: 1 }, { explain: true }, (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - done(); - }); + it('find returns queryPlanner explain result specified on cursor', async function () { + const explanation = await collection.find({ a: 1 }).explain(false); + expect(explanation).property('queryPlanner').to.exist; }); - } - }); + }); - it('should honor boolean explain with update one', { - metadata: { - requires: { - mongodb: '>=3.0' - } - }, - test: function (done) { - const db = client.db('shouldHonorBooleanExplainWithUpdateOne'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - collection.updateOne( - { a: 1 }, - { $inc: { a: 2 } }, - { explain: true }, - (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - done(); - } - ); + context('when explain is set to queryPlanner', () => { + it('only queryPlanner property is used in explain result', async function () { + const explanation = await collection.deleteOne({ a: 1 }, { explain: 'queryPlanner' }); + expect(explanation).property('queryPlanner').to.exist; + expect(explanation).to.not.have.property('executionStats'); }); - } - }); - it('should honor boolean explain with update many', { - metadata: { - requires: { - mongodb: '>=3.0' - } - }, - test: function (done) { - const db = client.db('shouldHonorBooleanExplainWithUpdateMany'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - collection.updateMany( + it('findOneAndReplace returns queryPlanner explain result', async function () { + const explanation = await collection.findOneAndReplace( { a: 1 }, - { $inc: { a: 2 } }, - { explain: true }, - (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).nested.property('queryPlanner').to.exist; - done(); - } + { a: 2 }, + { explain: 'queryPlanner' } ); + expect(explanation).property('queryPlanner').to.exist; }); - } - }); - - it('should honor boolean explain with remove one', { - metadata: { - requires: { - mongodb: '>=3.0' - } - }, - test: function (done) { - const db = client.db('shouldHonorBooleanExplainWithRemoveOne'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - collection.deleteOne({ a: 1 }, { explain: true }, (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - done(); - }); - }); - } - }); - - it('should honor boolean explain with remove many', { - metadata: { - requires: { - mongodb: '>=3.0' - } - }, - test: function (done) { - const db = client.db('shouldHonorBooleanExplainWithRemoveMany'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - collection.deleteMany({ a: 1 }, { explain: true }, (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - done(); - }); - }); - } - }); - - it('should honor boolean explain with distinct', { - metadata: { - requires: { - mongodb: '>=3.2' - } - }, - test: function (done) { - const db = client.db('shouldHonorBooleanExplainWithDistinct'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - collection.distinct('a', {}, { explain: true }, (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - done(); - }); - }); - } - }); - - it('should honor boolean explain with findOneAndModify', { - metadata: { - requires: { - mongodb: '>=3.2' - } - }, - test: function (done) { - const db = client.db('shouldHonorBooleanExplainWithFindOneAndModify'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - collection.findOneAndDelete({ a: 1 }, { explain: true }, (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - done(); - }); - }); - } - }); - - it('should use allPlansExecution as true explain verbosity', { - metadata: { - requires: { - mongodb: '>=3.0' - } - }, - test: function (done) { - const db = client.db('shouldUseAllPlansExecutionAsTrueExplainVerbosity'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - // Verify explanation result contains properties of allPlansExecution output - collection.deleteOne({ a: 1 }, { explain: true }, (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).nested.property('executionStats.allPlansExecution').to.exist; - done(); - }); + }); + + context('when explain is set to executionStats', () => { + it('executionStats property is used in explain result', async function () { + const explanation = await collection.deleteMany({ a: 1 }, { explain: 'executionStats' }); + expect(explanation).property('queryPlanner').to.exist; + expect(explanation).property('executionStats').to.exist; + expect(explanation).to.not.have.nested.property('executionStats.allPlansExecution'); }); - } - }); - it('should use queryPlanner as false explain verbosity', { - metadata: { - requires: { - mongodb: '>=3.0' - } - }, - test: function (done) { - const db = client.db('shouldUseQueryPlannerAsFalseExplainVerbosity'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - // Verify explanation result contains properties of queryPlanner output - collection.deleteOne({ a: 1 }, { explain: false }, (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).to.not.have.property('executionStats'); - done(); - }); + it('distinct returns executionStats explain result', async function () { + const explanation = await collection.distinct('a', {}, { explain: 'executionStats' }); + expect(explanation).property('queryPlanner').to.exist; + expect(explanation).property('executionStats').to.exist; }); - } - }); - it('should honor queryPlanner string explain', { - metadata: { - requires: { - mongodb: '>=3.0' - } - }, - test: function (done) { - const db = client.db('shouldHonorQueryPlannerStringExplain'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - // Verify explanation result contains properties of queryPlanner output - collection.deleteOne({ a: 1 }, { explain: 'queryPlanner' }, (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).to.not.have.property('executionStats'); - done(); - }); + it('find returns executionStats explain result', async function () { + const [explanation] = await collection + .find({ a: 1 }, { explain: 'executionStats' }) + .toArray(); + expect(explanation).property('queryPlanner').to.exist; + expect(explanation).property('executionStats').to.exist; }); - } - }); - it('should honor executionStats string explain', { - metadata: { - requires: { - mongodb: '>=3.0' - } - }, - test: function (done) { - const db = client.db('shouldHonorExecutionStatsStringExplain'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - // Verify explanation result contains properties of executionStats output - collection.deleteMany({ a: 1 }, { explain: 'executionStats' }, (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).property('executionStats').to.exist; - expect(explanation.executionStats).to.not.have.property('allPlansExecution'); - done(); - }); + it('findOne returns executionStats explain result', async function () { + const explanation = await collection.findOne({ a: 1 }, { explain: 'executionStats' }); + expect(explanation).property('queryPlanner').to.exist; + expect(explanation).property('executionStats').to.exist; }); - } - }); - - it('should honor allPlansExecution string explain', { - metadata: { - requires: { - mongodb: '>=3.0' - } - }, - test: function (done) { - const db = client.db('shouldHonorAllPlansStringExplain'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - // Verify explanation result contains properties of allPlansExecution output - collection.deleteOne({ a: 1 }, { explain: 'allPlansExecution' }, (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).nested.property('executionStats.allPlansExecution').to.exist; - done(); - }); + }); + + context('when explain is set to allPlansExecution', () => { + it('allPlansExecution property is used in explain result', async function () { + const explanation = await collection.deleteOne({ a: 1 }, { explain: 'allPlansExecution' }); + expect(explanation).property('queryPlanner').to.exist; + expect(explanation).property('executionStats').to.exist; + expect(explanation).nested.property('executionStats.allPlansExecution').to.exist; }); - } - }); - it('should honor string explain with distinct', { - metadata: { - requires: { - mongodb: '>=3.2' - } - }, - test: function (done) { - const db = client.db('shouldHonorStringExplainWithDistinct'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - collection.distinct('a', {}, { explain: 'executionStats' }, (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).property('executionStats').to.exist; - done(); - }); + it('find returns allPlansExecution explain result specified on cursor', async function () { + const explanation = await collection.find({ a: 1 }).explain('allPlansExecution'); + expect(explanation).property('queryPlanner').to.exist; + expect(explanation).property('executionStats').to.exist; }); - } + }); }); - it('should honor string explain with findOneAndModify', { - metadata: { - requires: { - mongodb: '>=3.2' - } - }, - test: function (done) { - const db = client.db('shouldHonorStringExplainWithFindOneAndModify'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - collection.findOneAndReplace( - { a: 1 }, - { a: 2 }, - { explain: 'queryPlanner' }, - (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - done(); - } - ); - }); - } - }); - - it('should honor boolean explain with find', async () => { - const db = client.db('shouldHonorBooleanExplainWithFind'); - const collection = db.collection('test'); - - await collection.insertOne({ a: 1 }); + it('find returns queryPlanner explain result', async () => { const [explanation] = await collection.find({ a: 1 }, { explain: true }).toArray(); - expect(explanation).to.exist; expect(explanation).property('queryPlanner').to.exist; }); - it('should honor string explain with find', { - metadata: { - requires: { - mongodb: '>=3.0' - } - }, - test: function (done) { - const db = client.db('shouldHonorStringExplainWithFind'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - collection.find({ a: 1 }, { explain: 'executionStats' }).toArray((err, docs) => { - expect(err).to.not.exist; - const explanation = docs[0]; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).property('executionStats').to.exist; - done(); - }); - }); - } - }); - - it('should honor boolean explain with findOne', { - metadata: { - requires: { - mongodb: '>=3.0' - } - }, - test: function (done) { - const db = client.db('shouldHonorBooleanExplainWithFindOne'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - collection.findOne({ a: 1 }, { explain: true }, (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - done(); - }); - }); - } - }); - - it('should honor string explain with findOne', { - metadata: { - requires: { - mongodb: '>=3.0' - } - }, - test: function (done) { - const db = client.db('shouldHonorStringExplainWithFindOne'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - collection.findOne({ a: 1 }, { explain: 'executionStats' }, (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).property('executionStats').to.exist; - done(); - }); - }); - } - }); - - it('should honor boolean explain specified on cursor with find', { - metadata: { - requires: { - mongodb: '>=3.0' - } - }, - test: function (done) { - const db = client.db('shouldHonorBooleanExplainSpecifiedOnCursor'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - collection.find({ a: 1 }).explain(false, (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - done(); - }); - }); - } - }); - - it('should honor string explain specified on cursor with find', { - metadata: { - requires: { - mongodb: '>=3.0' - } - }, - test: function (done) { - const db = client.db('shouldHonorStringExplainSpecifiedOnCursor'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - collection.find({ a: 1 }).explain('allPlansExecution', (err, explanation) => { - expect(err).to.not.exist; - expect(explanation).to.exist; - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).property('executionStats').to.exist; - done(); - }); - }); - } - }); - - it('should honor legacy explain with find', { - metadata: { - requires: { - mongodb: '<3.0' - } - }, - test: function (done) { - const db = client.db('shouldHonorLegacyExplainWithFind'); - const collection = db.collection('test'); - - collection.insertOne({ a: 1 }, (err, res) => { - expect(err).to.not.exist; - expect(res).to.exist; - - collection.find({ a: 1 }).explain((err, result) => { - expect(err).to.not.exist; - expect(result).to.have.property('allPlans'); - done(); - }); - }); - } - }); - it('should honor boolean explain with aggregate', async function () { const db = client.db('shouldHonorBooleanExplainWithAggregate'); const collection = db.collection('test'); @@ -584,34 +185,27 @@ describe('Explain', function () { } }); - it('should honor string explain with aggregate', { - metadata: { - requires: { - mongodb: '>=3.6.0' - } - }, - test: async function () { - const db = client.db('shouldHonorStringExplainWithAggregate'); - const collection = db.collection('test'); - - await collection.insertOne({ a: 1 }); - const aggResult = await collection - .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }], { - explain: 'executionStats' - }) - .toArray(); - if (aggResult[0].stages) { - expect(aggResult[0].stages).to.have.length.gte(1); - expect(aggResult[0].stages[0]).to.have.property('$cursor'); - expect(aggResult[0].stages[0].$cursor).to.have.property('queryPlanner'); - expect(aggResult[0].stages[0].$cursor).to.have.property('executionStats'); - } else if (aggResult[0].$cursor) { - expect(aggResult[0].$cursor).to.have.property('queryPlanner'); - expect(aggResult[0].$cursor).to.have.property('executionStats'); - } else { - expect(aggResult[0]).to.have.property('queryPlanner'); - expect(aggResult[0]).to.have.property('executionStats'); - } + it('should honor string explain with aggregate', async function () { + const db = client.db('shouldHonorStringExplainWithAggregate'); + const collection = db.collection('test'); + + await collection.insertOne({ a: 1 }); + const aggResult = await collection + .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }], { + explain: 'executionStats' + }) + .toArray(); + if (aggResult[0].stages) { + expect(aggResult[0].stages).to.have.length.gte(1); + expect(aggResult[0].stages[0]).to.have.property('$cursor'); + expect(aggResult[0].stages[0].$cursor).to.have.property('queryPlanner'); + expect(aggResult[0].stages[0].$cursor).to.have.property('executionStats'); + } else if (aggResult[0].$cursor) { + expect(aggResult[0].$cursor).to.have.property('queryPlanner'); + expect(aggResult[0].$cursor).to.have.property('executionStats'); + } else { + expect(aggResult[0]).to.have.property('queryPlanner'); + expect(aggResult[0]).to.have.property('executionStats'); } }); @@ -637,30 +231,23 @@ describe('Explain', function () { } }); - it('should honor string explain specified on cursor with aggregate', { - metadata: { - requires: { - mongodb: '>=3.6' - } - }, - test: async function () { - const db = client.db('shouldHonorStringExplainSpecifiedOnCursor'); - const collection = db.collection('test'); - - await collection.insertOne({ a: 1 }); - const aggResult = await collection - .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }]) - .explain('allPlansExecution'); - - if (aggResult && aggResult.stages) { - expect(aggResult.stages).to.have.length.gte(1); - expect(aggResult.stages[0]).to.have.property('$cursor'); - expect(aggResult.stages[0].$cursor).to.have.property('queryPlanner'); - expect(aggResult.stages[0].$cursor).to.have.property('executionStats'); - } else { - expect(aggResult).to.have.property('queryPlanner'); - expect(aggResult).to.have.property('executionStats'); - } + it('should honor string explain specified on cursor with aggregate', async function () { + const db = client.db('shouldHonorStringExplainSpecifiedOnCursor'); + const collection = db.collection('test'); + + await collection.insertOne({ a: 1 }); + const aggResult = await collection + .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }]) + .explain('allPlansExecution'); + + if (aggResult && aggResult.stages) { + expect(aggResult.stages).to.have.length.gte(1); + expect(aggResult.stages[0]).to.have.property('$cursor'); + expect(aggResult.stages[0].$cursor).to.have.property('queryPlanner'); + expect(aggResult.stages[0].$cursor).to.have.property('executionStats'); + } else { + expect(aggResult).to.have.property('queryPlanner'); + expect(aggResult).to.have.property('executionStats'); } }); @@ -683,22 +270,13 @@ describe('Explain', function () { } }); - it('should throw a catchable error with invalid explain string', { - metadata: { - requires: { - mongodb: '>=3.4' - } - }, - test: async function () { - const db = client.db('shouldThrowCatchableError'); - const collection = db.collection('test'); - try { - await collection.find({ a: 1 }).explain('invalidExplain'); - expect.fail(new Error('Expected explain to fail but it succeeded')); - } catch (e) { - expect(e).to.exist; - expect(e).to.be.instanceOf(MongoServerError); - } - } + it('should throw a catchable error with invalid explain string', async function () { + const db = client.db('shouldThrowCatchableError'); + const collection = db.collection('test'); + const error = await collection + .find({ a: 1 }) + .explain('invalidExplain') + .catch(error => error); + expect(error).to.be.instanceOf(MongoServerError); }); }); From 2fbe5384d9abc0c73fba640c05158a0ccf5dba0f Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Tue, 13 Jun 2023 13:19:54 -0400 Subject: [PATCH 04/24] grouped aggregates under context block --- test/integration/crud/explain.test.ts | 332 ++++++++++++-------------- 1 file changed, 153 insertions(+), 179 deletions(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index 8f706a9283..12fa3b3617 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -12,29 +12,24 @@ describe('Explain', function () { let client: MongoClient; let db: Db; let collection: Collection; - let commandsStarted: CommandStartedEvent[]; beforeEach(async function () { client = this.configuration.newClient({ monitorCommands: true }); db = client.db('queryPlannerExplainResult'); collection = db.collection('test'); - commandsStarted = []; await collection.insertOne({ a: 1 }); - client.on('commandStarted', event => commandsStarted.push(event)); }); afterEach(async function () { await collection.drop(); await client.close(); - commandsStarted = []; }); context('when explain is set to true', () => { it('deleteOne returns queryPlanner explain result', async function () { const explanation = await collection.deleteOne({ a: 1 }, { explain: true }); expect(explanation).property('queryPlanner').to.exist; - expect(commandsStarted[0]).to.have.nested.property('command.explain.delete'); }); it('deleteMany returns queryPlanner explain result', async function () { @@ -80,203 +75,182 @@ describe('Explain', function () { const explanation = await collection.findOne({ a: 1 }, { explain: true }); expect(explanation).property('queryPlanner').to.exist; }); + + it('find returns queryPlanner explain result', async () => { + const [explanation] = await collection.find({ a: 1 }, { explain: true }).toArray(); + expect(explanation).property('queryPlanner').to.exist; + }); }); - context('when explain is not set to true', () => { - context('when explain is set to false', () => { - it('only queryPlanner property is used in explain result', async function () { - const explanation = await collection.deleteOne({ a: 1 }, { explain: false }); - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).to.not.have.property('executionStats'); - }); - - it('find returns queryPlanner explain result specified on cursor', async function () { - const explanation = await collection.find({ a: 1 }).explain(false); - expect(explanation).property('queryPlanner').to.exist; - }); + context('when explain is set to false', () => { + it('only queryPlanner property is used in explain result', async function () { + const explanation = await collection.deleteOne({ a: 1 }, { explain: false }); + expect(explanation).property('queryPlanner').to.exist; }); - context('when explain is set to queryPlanner', () => { - it('only queryPlanner property is used in explain result', async function () { - const explanation = await collection.deleteOne({ a: 1 }, { explain: 'queryPlanner' }); - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).to.not.have.property('executionStats'); - }); - - it('findOneAndReplace returns queryPlanner explain result', async function () { - const explanation = await collection.findOneAndReplace( - { a: 1 }, - { a: 2 }, - { explain: 'queryPlanner' } - ); - expect(explanation).property('queryPlanner').to.exist; - }); + it('find returns "queryPlanner" explain result specified on cursor', async function () { + const explanation = await collection.find({ a: 1 }).explain(false); + expect(explanation).property('queryPlanner').to.exist; }); + }); - context('when explain is set to executionStats', () => { - it('executionStats property is used in explain result', async function () { - const explanation = await collection.deleteMany({ a: 1 }, { explain: 'executionStats' }); - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).property('executionStats').to.exist; - expect(explanation).to.not.have.nested.property('executionStats.allPlansExecution'); - }); - - it('distinct returns executionStats explain result', async function () { - const explanation = await collection.distinct('a', {}, { explain: 'executionStats' }); - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).property('executionStats').to.exist; - }); - - it('find returns executionStats explain result', async function () { - const [explanation] = await collection - .find({ a: 1 }, { explain: 'executionStats' }) - .toArray(); - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).property('executionStats').to.exist; - }); - - it('findOne returns executionStats explain result', async function () { - const explanation = await collection.findOne({ a: 1 }, { explain: 'executionStats' }); - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).property('executionStats').to.exist; - }); + context('when explain is set to "queryPlanner"', () => { + it('only queryPlanner property is used in explain result', async function () { + const explanation = await collection.deleteOne({ a: 1 }, { explain: 'queryPlanner' }); + expect(explanation).property('queryPlanner').to.exist; }); - context('when explain is set to allPlansExecution', () => { - it('allPlansExecution property is used in explain result', async function () { - const explanation = await collection.deleteOne({ a: 1 }, { explain: 'allPlansExecution' }); - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).property('executionStats').to.exist; - expect(explanation).nested.property('executionStats.allPlansExecution').to.exist; - }); - - it('find returns allPlansExecution explain result specified on cursor', async function () { - const explanation = await collection.find({ a: 1 }).explain('allPlansExecution'); - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).property('executionStats').to.exist; - }); + it('findOneAndReplace returns queryPlanner explain result', async function () { + const explanation = await collection.findOneAndReplace( + { a: 1 }, + { a: 2 }, + { explain: 'queryPlanner' } + ); + expect(explanation).property('queryPlanner').to.exist; }); }); - it('find returns queryPlanner explain result', async () => { - const [explanation] = await collection.find({ a: 1 }, { explain: true }).toArray(); - expect(explanation).property('queryPlanner').to.exist; - }); + context('when explain is set to "executionStats"', () => { + it('"executionStats" property is used in explain result', async function () { + const explanation = await collection.deleteMany({ a: 1 }, { explain: 'executionStats' }); + expect(explanation).property('queryPlanner').to.exist; + expect(explanation).property('executionStats').to.exist; + expect(explanation).to.not.have.nested.property('executionStats.allPlansExecution'); + }); - it('should honor boolean explain with aggregate', async function () { - const db = client.db('shouldHonorBooleanExplainWithAggregate'); - const collection = db.collection('test'); - await collection.insertOne({ a: 1 }); - const aggResult = await collection - .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }], { explain: true }) - .toArray(); - - if (aggResult[0].stages) { - expect(aggResult[0].stages).to.have.length.gte(1); - expect(aggResult[0].stages[0]).to.have.property('$cursor'); - expect(aggResult[0].stages[0].$cursor).to.have.property('queryPlanner'); - expect(aggResult[0].stages[0].$cursor).to.have.property('executionStats'); - } else if (aggResult[0].$cursor) { - expect(aggResult[0].$cursor).to.have.property('queryPlanner'); - expect(aggResult[0].$cursor).to.have.property('executionStats'); - } else { - expect(aggResult[0]).to.have.property('queryPlanner'); - expect(aggResult[0]).to.have.property('executionStats'); - } - }); + it('distinct returns executionStats explain result', async function () { + const explanation = await collection.distinct('a', {}, { explain: 'executionStats' }); + expect(explanation).property('queryPlanner').to.exist; + expect(explanation).property('executionStats').to.exist; + }); - it('should honor string explain with aggregate', async function () { - const db = client.db('shouldHonorStringExplainWithAggregate'); - const collection = db.collection('test'); + it('find returns executionStats explain result', async function () { + const [explanation] = await collection + .find({ a: 1 }, { explain: 'executionStats' }) + .toArray(); + expect(explanation).property('queryPlanner').to.exist; + expect(explanation).property('executionStats').to.exist; + }); - await collection.insertOne({ a: 1 }); - const aggResult = await collection - .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }], { - explain: 'executionStats' - }) - .toArray(); - if (aggResult[0].stages) { - expect(aggResult[0].stages).to.have.length.gte(1); - expect(aggResult[0].stages[0]).to.have.property('$cursor'); - expect(aggResult[0].stages[0].$cursor).to.have.property('queryPlanner'); - expect(aggResult[0].stages[0].$cursor).to.have.property('executionStats'); - } else if (aggResult[0].$cursor) { - expect(aggResult[0].$cursor).to.have.property('queryPlanner'); - expect(aggResult[0].$cursor).to.have.property('executionStats'); - } else { - expect(aggResult[0]).to.have.property('queryPlanner'); - expect(aggResult[0]).to.have.property('executionStats'); - } + it('findOne returns executionStats explain result', async function () { + const explanation = await collection.findOne({ a: 1 }, { explain: 'executionStats' }); + expect(explanation).property('queryPlanner').to.exist; + expect(explanation).property('executionStats').to.exist; + }); }); - it('should honor boolean explain specified on cursor with aggregate', async function () { - const db = client.db('shouldHonorBooleanExplainSpecifiedOnCursor'); - const collection = db.collection('test'); + context('when explain is set to "allPlansExecution"', () => { + it('allPlansExecution property is used in explain result', async function () { + const explanation = await collection.deleteOne({ a: 1 }, { explain: 'allPlansExecution' }); + expect(explanation).property('queryPlanner').to.exist; + expect(explanation).property('executionStats').to.exist; + expect(explanation).nested.property('executionStats.allPlansExecution').to.exist; + }); - await collection.insertOne({ a: 1 }); - const aggResult = await collection - .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }]) - .explain(false); - if (aggResult && aggResult.stages) { - expect(aggResult.stages).to.have.length.gte(1); - expect(aggResult.stages[0]).to.have.property('$cursor'); - expect(aggResult.stages[0].$cursor).to.have.property('queryPlanner'); - expect(aggResult.stages[0].$cursor).to.not.have.property('executionStats'); - } else if (aggResult.$cursor) { - expect(aggResult.$cursor).to.have.property('queryPlanner'); - expect(aggResult.$cursor).to.not.have.property('executionStats'); - } else { - expect(aggResult).to.have.property('queryPlanner'); - expect(aggResult).to.not.have.property('executionStats'); - } + it('find returns allPlansExecution explain result specified on cursor', async function () { + const explanation = await collection.find({ a: 1 }).explain('allPlansExecution'); + expect(explanation).property('queryPlanner').to.exist; + expect(explanation).property('executionStats').to.exist; + }); }); - it('should honor string explain specified on cursor with aggregate', async function () { - const db = client.db('shouldHonorStringExplainSpecifiedOnCursor'); - const collection = db.collection('test'); + context('aggregate()', () => { + it('when explain is set to true, aggregate result returns queryPlanner and executionStats properties', async function () { + const aggResult = await collection + .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }], { explain: true }) + .toArray(); + + if (aggResult[0].stages) { + expect(aggResult[0].stages).to.have.length.gte(1); + expect(aggResult[0].stages[0]).to.have.property('$cursor'); + expect(aggResult[0].stages[0].$cursor).to.have.property('queryPlanner'); + expect(aggResult[0].stages[0].$cursor).to.have.property('executionStats'); + } else if (aggResult[0].$cursor) { + expect(aggResult[0].$cursor).to.have.property('queryPlanner'); + expect(aggResult[0].$cursor).to.have.property('executionStats'); + } else { + expect(aggResult[0]).to.have.property('queryPlanner'); + expect(aggResult[0]).to.have.property('executionStats'); + } + }); - await collection.insertOne({ a: 1 }); - const aggResult = await collection - .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }]) - .explain('allPlansExecution'); - - if (aggResult && aggResult.stages) { - expect(aggResult.stages).to.have.length.gte(1); - expect(aggResult.stages[0]).to.have.property('$cursor'); - expect(aggResult.stages[0].$cursor).to.have.property('queryPlanner'); - expect(aggResult.stages[0].$cursor).to.have.property('executionStats'); - } else { - expect(aggResult).to.have.property('queryPlanner'); - expect(aggResult).to.have.property('executionStats'); - } - }); + it('when explain is set to "executionStats", aggregate result returns queryPlanner and executionStats properties', async function () { + const aggResult = await collection + .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }], { + explain: 'executionStats' + }) + .toArray(); + if (aggResult[0].stages) { + expect(aggResult[0].stages).to.have.length.gte(1); + expect(aggResult[0].stages[0]).to.have.property('$cursor'); + expect(aggResult[0].stages[0].$cursor).to.have.property('queryPlanner'); + expect(aggResult[0].stages[0].$cursor).to.have.property('executionStats'); + } else if (aggResult[0].$cursor) { + expect(aggResult[0].$cursor).to.have.property('queryPlanner'); + expect(aggResult[0].$cursor).to.have.property('executionStats'); + } else { + expect(aggResult[0]).to.have.property('queryPlanner'); + expect(aggResult[0]).to.have.property('executionStats'); + } + }); - it('should honor legacy explain with aggregate', async function () { - const db = client.db('shouldHonorLegacyExplainWithAggregate'); - const collection = db.collection('test'); + it('when explain is set to false, aggregate result returns queryPlanner property', async function () { + const aggResult = await collection + .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }]) + .explain(false); + if (aggResult && aggResult.stages) { + expect(aggResult.stages).to.have.length.gte(1); + expect(aggResult.stages[0]).to.have.property('$cursor'); + expect(aggResult.stages[0].$cursor).to.have.property('queryPlanner'); + expect(aggResult.stages[0].$cursor).to.not.have.property('executionStats'); + } else if (aggResult.$cursor) { + expect(aggResult.$cursor).to.have.property('queryPlanner'); + expect(aggResult.$cursor).to.not.have.property('executionStats'); + } else { + expect(aggResult).to.have.property('queryPlanner'); + expect(aggResult).to.not.have.property('executionStats'); + } + }); - await collection.insertOne({ a: 1 }); - const aggResult = await collection - .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }]) - .explain(); - if (aggResult && aggResult.stages) { - expect(aggResult.stages).to.have.length.gte(1); - expect(aggResult.stages[0]).to.have.property('$cursor'); - expect(aggResult.stages[0].$cursor).to.have.property('queryPlanner'); - expect(aggResult.stages[0].$cursor).to.have.property('executionStats'); - } else { - expect(aggResult).to.have.property('queryPlanner'); - expect(aggResult).to.have.property('executionStats'); - } + it('when explain is set to "allPlansExecution", aggregate result returns queryPlanner and executionStats properties', async function () { + const aggResult = await collection + .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }]) + .explain('allPlansExecution'); + + if (aggResult && aggResult.stages) { + expect(aggResult.stages).to.have.length.gte(1); + expect(aggResult.stages[0]).to.have.property('$cursor'); + expect(aggResult.stages[0].$cursor).to.have.property('queryPlanner'); + expect(aggResult.stages[0].$cursor).to.have.property('executionStats'); + } else { + expect(aggResult).to.have.property('queryPlanner'); + expect(aggResult).to.have.property('executionStats'); + } + }); + + it('when explain is not set, aggregate result returns queryPlanner and executionStats properties', async function () { + const aggResult = await collection + .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }]) + .explain(); + if (aggResult && aggResult.stages) { + expect(aggResult.stages).to.have.length.gte(1); + expect(aggResult.stages[0]).to.have.property('$cursor'); + expect(aggResult.stages[0].$cursor).to.have.property('queryPlanner'); + expect(aggResult.stages[0].$cursor).to.have.property('executionStats'); + } else { + expect(aggResult).to.have.property('queryPlanner'); + expect(aggResult).to.have.property('executionStats'); + } + }); }); - it('should throw a catchable error with invalid explain string', async function () { - const db = client.db('shouldThrowCatchableError'); - const collection = db.collection('test'); - const error = await collection - .find({ a: 1 }) - .explain('invalidExplain') - .catch(error => error); - expect(error).to.be.instanceOf(MongoServerError); + context('when explain is set to "invalidExplain", result returns MongoServerError', () => { + it('should throw a catchable error with invalid explain string', async function () { + const error = await collection + .find({ a: 1 }) + .explain('invalidExplain') + .catch(error => error); + expect(error).to.be.instanceOf(MongoServerError); + }); }); }); From a0f5d101dee1b0819d3f11c5b156dc263a48c03f Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Tue, 13 Jun 2023 13:27:57 -0400 Subject: [PATCH 05/24] fixed formatting --- test/integration/crud/explain.test.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index 12fa3b3617..68389d044c 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -1,12 +1,6 @@ import { expect } from 'chai'; -import { - type Collection, - type CommandStartedEvent, - type Db, - type MongoClient, - MongoServerError -} from '../../mongodb'; +import { type Collection, type Db, type MongoClient, MongoServerError } from '../../mongodb'; describe('Explain', function () { let client: MongoClient; From 9705cc6735b31d64c79aa7faad568c01eb7b1ac2 Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Wed, 14 Jun 2023 11:48:09 -0400 Subject: [PATCH 06/24] fixed catchable error context block description --- test/integration/crud/explain.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index 68389d044c..3c3e27261a 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -238,8 +238,8 @@ describe('Explain', function () { }); }); - context('when explain is set to "invalidExplain", result returns MongoServerError', () => { - it('should throw a catchable error with invalid explain string', async function () { + context('when explain is set to an unexpected value', () => { + it('result throws a catchable error with invalid explain string', async function () { const error = await collection .find({ a: 1 }) .explain('invalidExplain') From 8cd25f1393d017477cce53acff79d93c74b63cf6 Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Wed, 14 Jun 2023 11:50:35 -0400 Subject: [PATCH 07/24] fixed it clause --- test/integration/crud/explain.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index 3c3e27261a..0cfd999aac 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -239,7 +239,7 @@ describe('Explain', function () { }); context('when explain is set to an unexpected value', () => { - it('result throws a catchable error with invalid explain string', async function () { + it('should throw a catchable error with invalid explain string', async function () { const error = await collection .find({ a: 1 }) .explain('invalidExplain') From 2601c7bbca6d1617c37e0934b5b460653ba37739 Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Thu, 15 Jun 2023 13:45:27 -0400 Subject: [PATCH 08/24] fixed identical test cases --- test/integration/crud/explain.test.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index 0cfd999aac..f9af6d9dd8 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -77,21 +77,24 @@ describe('Explain', function () { }); context('when explain is set to false', () => { - it('only queryPlanner property is used in explain result', async function () { + it('deleteOne only returns queryPlanner property in explain result', async function () { const explanation = await collection.deleteOne({ a: 1 }, { explain: false }); expect(explanation).property('queryPlanner').to.exist; + expect(explanation).to.not.have.property('executionStats'); }); it('find returns "queryPlanner" explain result specified on cursor', async function () { const explanation = await collection.find({ a: 1 }).explain(false); expect(explanation).property('queryPlanner').to.exist; + expect(explanation).to.not.have.property('executionStats'); }); }); context('when explain is set to "queryPlanner"', () => { - it('only queryPlanner property is used in explain result', async function () { + it('deleteOne returns only queryPlanner property in explain result', async function () { const explanation = await collection.deleteOne({ a: 1 }, { explain: 'queryPlanner' }); expect(explanation).property('queryPlanner').to.exist; + expect(explanation).to.not.have.property('executionStats'); }); it('findOneAndReplace returns queryPlanner explain result', async function () { From dcc57424089a284909e1ffc54733a910ab54279f Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Tue, 20 Jun 2023 15:10:52 -0400 Subject: [PATCH 09/24] changed true and false context titles to verbosity --- test/integration/crud/explain.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index f9af6d9dd8..00086730c6 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -20,7 +20,7 @@ describe('Explain', function () { await client.close(); }); - context('when explain is set to true', () => { + context('highest verbosity explain', () => { it('deleteOne returns queryPlanner explain result', async function () { const explanation = await collection.deleteOne({ a: 1 }, { explain: true }); expect(explanation).property('queryPlanner').to.exist; @@ -76,7 +76,7 @@ describe('Explain', function () { }); }); - context('when explain is set to false', () => { + context('lowest verbosity explain', () => { it('deleteOne only returns queryPlanner property in explain result', async function () { const explanation = await collection.deleteOne({ a: 1 }, { explain: false }); expect(explanation).property('queryPlanner').to.exist; From 116d04dea55dd9caf7f55f90127521f2a9622089 Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Fri, 23 Jun 2023 13:53:03 -0400 Subject: [PATCH 10/24] Added all operations, is still giving test errors --- test/integration/crud/explain.test.ts | 89 ++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index 00086730c6..0a71737abb 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -1,17 +1,58 @@ import { expect } from 'chai'; +import { once } from 'events'; import { type Collection, type Db, type MongoClient, MongoServerError } from '../../mongodb'; -describe('Explain', function () { +const explain = [true, false, 'queryPlanner', 'allPlansExecution', 'executionStats', 'invalid']; + +describe.only('Explain', function () { let client: MongoClient; let db: Db; let collection: Collection; + const ops = [ + async (explain: boolean | string) => collection.deleteOne({ a: 1 }, { explain }), + async (explain: boolean | string) => collection.deleteMany({ a: 1 }, { explain }), + async (explain: boolean | string) => + collection.updateOne({ a: 1 }, { $inc: { a: 2 } }, { explain }), + async (explain: boolean | string) => + collection.updateMany({ a: 1 }, { $inc: { a: 2 } }, { explain }), + async (explain: boolean | string) => collection.distinct('a', {}, { explain }), + async (explain: boolean | string) => collection.findOneAndDelete({ a: 1 }, { explain }), + async (explain: boolean | string) => collection.findOne({ a: 1 }, { explain }), + async (explain: boolean | string) => collection.find({ a: 1 }, { explain }), + async (explain: boolean | string) => + collection.findOneAndReplace({ a: 1 }, { a: 2 }, { explain }), + async (explain: boolean | string) => + collection + .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }], { explain }) + .toArray() + ]; + + const opNames = [ + 'deleteOne', + 'deleteMany', + 'updateOne', + 'updateMany', + 'distinct', + 'findOneAndDelete', + 'findOne', + 'find', + 'aggregate' + ]; + + const testTable: { + op: (explain: boolean | string) => Promise; + explainValue: string | boolean; + }[] = explain.flatMap(explainValue => { + return ops.flatMap(op => { + return { op, explainValue }; + }); + }); beforeEach(async function () { client = this.configuration.newClient({ monitorCommands: true }); db = client.db('queryPlannerExplainResult'); collection = db.collection('test'); - await collection.insertOne({ a: 1 }); }); @@ -20,6 +61,41 @@ describe('Explain', function () { await client.close(); }); + testTable.forEach(function (test) { + context(`When explain is ${test.explainValue}`, function () { + it(`${ + opNames[ops.indexOf(test.op)] + } returns ${explainValueToExpectation(test.op, test.explainValue)}`, async function () { + const commandStartedPromise = once(client, 'commandStartedEvent'); + const response = await test.op(test.explainValue); + const commandStartedEvent = await commandStartedPromise; + expect(commandStartedEvent[0].explain).to.have.property(`${test.op.name}`); + switch (test.explainValue) { + case true: + case 'allPlansExecution': + expect(commandStartedEvent[0].verbosity).to.be.equal('allPlansExecution'); + expect(response).to.have.property('queryPlanner'); + expect(response).nested.property('executionStats.allPlansExecution').to.exist; + break; + case false: + case 'queryPlanner': + expect(commandStartedEvent[0].verbosity).to.be.equal('queryPlanner'); + expect(response).to.have.property('queryPlanner'); + break; + case 'executionStats': + expect(commandStartedEvent[0].verbosity).to.be.equal('executionStats'); + expect(response).to.have.property('queryPlanner'); + expect(response).to.have.property('executionStats'); + expect(response).nested.property('allPlansExecution').to.not.exist; + break; + default: + expect(response).to.be.instanceOf(MongoServerError); + break; + } + }); + }); + }); + /* context('highest verbosity explain', () => { it('deleteOne returns queryPlanner explain result', async function () { const explanation = await collection.deleteOne({ a: 1 }, { explain: true }); @@ -250,4 +326,13 @@ describe('Explain', function () { expect(error).to.be.instanceOf(MongoServerError); }); }); + */ }); + +async function explainValueToExpectation( + op: (explain: boolean | string) => Promise, + explainValue: boolean | string +) { + const opResult = await op(explainValue); + return opResult; +} From 479de7184db468a76512b476ebe3befaab19c614 Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Fri, 23 Jun 2023 16:15:26 -0400 Subject: [PATCH 11/24] missing aggregate --- test/integration/crud/explain.test.ts | 128 ++++++++++++++------------ 1 file changed, 68 insertions(+), 60 deletions(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index 0a71737abb..499a5b6303 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -1,29 +1,36 @@ import { expect } from 'chai'; import { once } from 'events'; -import { type Collection, type Db, type MongoClient, MongoServerError } from '../../mongodb'; +import { + type Collection, + type CommandStartedEvent, + type Db, + type MongoClient, + MongoServerError +} from '../../mongodb'; const explain = [true, false, 'queryPlanner', 'allPlansExecution', 'executionStats', 'invalid']; -describe.only('Explain', function () { +describe('Explain', function () { let client: MongoClient; let db: Db; let collection: Collection; + let commandStartedPromise: Promise; const ops = [ - async (explain: boolean | string) => collection.deleteOne({ a: 1 }, { explain }), - async (explain: boolean | string) => collection.deleteMany({ a: 1 }, { explain }), + async (explain: boolean | string) => await collection.deleteOne({ a: 1 }, { explain }), + async (explain: boolean | string) => await collection.deleteMany({ a: 1 }, { explain }), async (explain: boolean | string) => - collection.updateOne({ a: 1 }, { $inc: { a: 2 } }, { explain }), + await collection.updateOne({ a: 1 }, { $inc: { a: 2 } }, { explain }), async (explain: boolean | string) => - collection.updateMany({ a: 1 }, { $inc: { a: 2 } }, { explain }), - async (explain: boolean | string) => collection.distinct('a', {}, { explain }), - async (explain: boolean | string) => collection.findOneAndDelete({ a: 1 }, { explain }), - async (explain: boolean | string) => collection.findOne({ a: 1 }, { explain }), - async (explain: boolean | string) => collection.find({ a: 1 }, { explain }), + await collection.updateMany({ a: 1 }, { $inc: { a: 2 } }, { explain }), + async (explain: boolean | string) => await collection.distinct('a', {}, { explain }), + async (explain: boolean | string) => await collection.findOneAndDelete({ a: 1 }, { explain }), + async (explain: boolean | string) => await collection.findOne({ a: 1 }, { explain }), + (explain: boolean | string) => collection.find({ a: 1 }).explain(explain), async (explain: boolean | string) => - collection.findOneAndReplace({ a: 1 }, { a: 2 }, { explain }), + await collection.findOneAndReplace({ a: 1 }, { a: 2 }, { explain }), async (explain: boolean | string) => - collection + await collection .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }], { explain }) .toArray() ]; @@ -37,23 +44,16 @@ describe.only('Explain', function () { 'findOneAndDelete', 'findOne', 'find', + 'findOneAndReplace', 'aggregate' ]; - const testTable: { - op: (explain: boolean | string) => Promise; - explainValue: string | boolean; - }[] = explain.flatMap(explainValue => { - return ops.flatMap(op => { - return { op, explainValue }; - }); - }); - beforeEach(async function () { client = this.configuration.newClient({ monitorCommands: true }); db = client.db('queryPlannerExplainResult'); collection = db.collection('test'); await collection.insertOne({ a: 1 }); + commandStartedPromise = once(client, 'commandStarted'); }); afterEach(async function () { @@ -61,40 +61,41 @@ describe.only('Explain', function () { await client.close(); }); - testTable.forEach(function (test) { - context(`When explain is ${test.explainValue}`, function () { - it(`${ - opNames[ops.indexOf(test.op)] - } returns ${explainValueToExpectation(test.op, test.explainValue)}`, async function () { - const commandStartedPromise = once(client, 'commandStartedEvent'); - const response = await test.op(test.explainValue); - const commandStartedEvent = await commandStartedPromise; - expect(commandStartedEvent[0].explain).to.have.property(`${test.op.name}`); - switch (test.explainValue) { - case true: - case 'allPlansExecution': - expect(commandStartedEvent[0].verbosity).to.be.equal('allPlansExecution'); - expect(response).to.have.property('queryPlanner'); - expect(response).nested.property('executionStats.allPlansExecution').to.exist; - break; - case false: - case 'queryPlanner': - expect(commandStartedEvent[0].verbosity).to.be.equal('queryPlanner'); - expect(response).to.have.property('queryPlanner'); - break; - case 'executionStats': - expect(commandStartedEvent[0].verbosity).to.be.equal('executionStats'); - expect(response).to.have.property('queryPlanner'); - expect(response).to.have.property('executionStats'); - expect(response).nested.property('allPlansExecution').to.not.exist; - break; - default: - expect(response).to.be.instanceOf(MongoServerError); - break; - } - }); + for (const explainValue of explain) { + context(`When explain is ${explainValue}`, function () { + for (const op of ops) { + it(`${opNames[ops.indexOf(op)]} returns ${explainValueToExpectation( + explainValue + )}`, async function () { + const response = await op(explainValue).catch(error => error); + const commandStartedEvent = await commandStartedPromise; + switch (explainValue) { + case true: + case 'allPlansExecution': + expect(commandStartedEvent[0].command.verbosity).to.be.equal('allPlansExecution'); + expect(response).to.have.property('queryPlanner'); + expect(response).nested.property('executionStats.allPlansExecution').to.exist; + break; + case false: + case 'queryPlanner': + expect(commandStartedEvent[0].command.verbosity).to.be.equal('queryPlanner'); + expect(response).to.have.property('queryPlanner'); + expect(response).to.not.have.property('executionStats'); + break; + case 'executionStats': + expect(commandStartedEvent[0].command.verbosity).to.be.equal('executionStats'); + expect(response).to.have.property('queryPlanner'); + expect(response).to.have.property('executionStats'); + expect(response).to.not.have.nested.property('allPlansExecution'); + break; + default: + expect(response).to.be.instanceOf(MongoServerError); + break; + } + }); + } }); - }); + } /* context('highest verbosity explain', () => { it('deleteOne returns queryPlanner explain result', async function () { @@ -329,10 +330,17 @@ describe.only('Explain', function () { */ }); -async function explainValueToExpectation( - op: (explain: boolean | string) => Promise, - explainValue: boolean | string -) { - const opResult = await op(explainValue); - return opResult; +function explainValueToExpectation(explainValue: boolean | string) { + switch (explainValue) { + case true: + case 'allPlansExecution': + return 'allPlansExecution property'; + case false: + case 'queryPlanner': + return 'queryPlanner property'; + case 'executionStats': + return 'executionStats property'; + default: + return 'error'; + } } From 5cd0b2eb7082e58a4ea8cd7e0a28e938ff4b47d0 Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Mon, 26 Jun 2023 15:22:20 -0400 Subject: [PATCH 12/24] added aggregate testing --- test/integration/crud/explain.test.ts | 267 +++----------------------- 1 file changed, 25 insertions(+), 242 deletions(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index 499a5b6303..e1263ec60b 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -64,29 +64,44 @@ describe('Explain', function () { for (const explainValue of explain) { context(`When explain is ${explainValue}`, function () { for (const op of ops) { - it(`${opNames[ops.indexOf(op)]} returns ${explainValueToExpectation( - explainValue - )}`, async function () { + const name = opNames[ops.indexOf(op)]; + it(`${name} returns ${explainValueToExpectation(explainValue)}`, async function () { const response = await op(explainValue).catch(error => error); const commandStartedEvent = await commandStartedPromise; switch (explainValue) { case true: case 'allPlansExecution': expect(commandStartedEvent[0].command.verbosity).to.be.equal('allPlansExecution'); - expect(response).to.have.property('queryPlanner'); - expect(response).nested.property('executionStats.allPlansExecution').to.exist; + if (name === 'aggregate') { + expect(response[0]).to.have.property('queryPlanner'); + expect(response[0]).nested.property('executionStats.allPlansExecution').to.exist; + } else { + expect(response).to.have.property('queryPlanner'); + expect(response).nested.property('executionStats.allPlansExecution').to.exist; + } break; case false: case 'queryPlanner': expect(commandStartedEvent[0].command.verbosity).to.be.equal('queryPlanner'); - expect(response).to.have.property('queryPlanner'); - expect(response).to.not.have.property('executionStats'); + if (name === 'aggregate') { + expect(response[0]).to.have.property('queryPlanner'); + expect(response[0]).to.not.have.property('executionStats'); + } else { + expect(response).to.have.property('queryPlanner'); + expect(response).to.not.have.property('executionStats'); + } break; case 'executionStats': expect(commandStartedEvent[0].command.verbosity).to.be.equal('executionStats'); - expect(response).to.have.property('queryPlanner'); - expect(response).to.have.property('executionStats'); - expect(response).to.not.have.nested.property('allPlansExecution'); + if (name === 'aggregate') { + expect(response[0]).to.have.property('queryPlanner'); + expect(response[0]).to.have.property('executionStats'); + expect(response[0]).to.not.have.nested.property('executionStats.allPlansExecution'); + } else { + expect(response).to.have.property('queryPlanner'); + expect(response).to.have.property('executionStats'); + expect(response).to.not.have.nested.property('executionStats.allPlansExecution'); + } break; default: expect(response).to.be.instanceOf(MongoServerError); @@ -96,238 +111,6 @@ describe('Explain', function () { } }); } - /* - context('highest verbosity explain', () => { - it('deleteOne returns queryPlanner explain result', async function () { - const explanation = await collection.deleteOne({ a: 1 }, { explain: true }); - expect(explanation).property('queryPlanner').to.exist; - }); - - it('deleteMany returns queryPlanner explain result', async function () { - const explanation = await collection.deleteMany({ a: 1 }, { explain: true }); - expect(explanation).property('queryPlanner').to.exist; - }); - - it('updateOne returns queryPlanner explain result', async function () { - const explanation = await collection.updateOne( - { a: 1 }, - { $inc: { a: 2 } }, - { explain: true } - ); - expect(explanation).property('queryPlanner').to.exist; - }); - - it('updateMany returns queryPlanner explain result', async function () { - const explanation = await collection.updateMany( - { a: 1 }, - { $inc: { a: 2 } }, - { explain: true } - ); - expect(explanation).property('queryPlanner').to.exist; - }); - - it('distinct returns queryPlanner explain result', async function () { - const explanation = await collection.distinct('a', {}, { explain: true }); - expect(explanation).property('queryPlanner').to.exist; - }); - - it('findOneAndDelete returns queryPlanner explain result', async function () { - const explanation = await collection.findOneAndDelete({ a: 1 }, { explain: true }); - expect(explanation).property('queryPlanner').to.exist; - }); - - it('allPlansExecution returns verbose queryPlanner explain result', async function () { - const explanation = await collection.deleteOne({ a: 1 }, { explain: true }); - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).nested.property('executionStats.allPlansExecution').to.exist; - }); - - it('findOne returns queryPlanner explain result', async function () { - const explanation = await collection.findOne({ a: 1 }, { explain: true }); - expect(explanation).property('queryPlanner').to.exist; - }); - - it('find returns queryPlanner explain result', async () => { - const [explanation] = await collection.find({ a: 1 }, { explain: true }).toArray(); - expect(explanation).property('queryPlanner').to.exist; - }); - }); - - context('lowest verbosity explain', () => { - it('deleteOne only returns queryPlanner property in explain result', async function () { - const explanation = await collection.deleteOne({ a: 1 }, { explain: false }); - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).to.not.have.property('executionStats'); - }); - - it('find returns "queryPlanner" explain result specified on cursor', async function () { - const explanation = await collection.find({ a: 1 }).explain(false); - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).to.not.have.property('executionStats'); - }); - }); - - context('when explain is set to "queryPlanner"', () => { - it('deleteOne returns only queryPlanner property in explain result', async function () { - const explanation = await collection.deleteOne({ a: 1 }, { explain: 'queryPlanner' }); - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).to.not.have.property('executionStats'); - }); - - it('findOneAndReplace returns queryPlanner explain result', async function () { - const explanation = await collection.findOneAndReplace( - { a: 1 }, - { a: 2 }, - { explain: 'queryPlanner' } - ); - expect(explanation).property('queryPlanner').to.exist; - }); - }); - - context('when explain is set to "executionStats"', () => { - it('"executionStats" property is used in explain result', async function () { - const explanation = await collection.deleteMany({ a: 1 }, { explain: 'executionStats' }); - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).property('executionStats').to.exist; - expect(explanation).to.not.have.nested.property('executionStats.allPlansExecution'); - }); - - it('distinct returns executionStats explain result', async function () { - const explanation = await collection.distinct('a', {}, { explain: 'executionStats' }); - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).property('executionStats').to.exist; - }); - - it('find returns executionStats explain result', async function () { - const [explanation] = await collection - .find({ a: 1 }, { explain: 'executionStats' }) - .toArray(); - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).property('executionStats').to.exist; - }); - - it('findOne returns executionStats explain result', async function () { - const explanation = await collection.findOne({ a: 1 }, { explain: 'executionStats' }); - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).property('executionStats').to.exist; - }); - }); - - context('when explain is set to "allPlansExecution"', () => { - it('allPlansExecution property is used in explain result', async function () { - const explanation = await collection.deleteOne({ a: 1 }, { explain: 'allPlansExecution' }); - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).property('executionStats').to.exist; - expect(explanation).nested.property('executionStats.allPlansExecution').to.exist; - }); - - it('find returns allPlansExecution explain result specified on cursor', async function () { - const explanation = await collection.find({ a: 1 }).explain('allPlansExecution'); - expect(explanation).property('queryPlanner').to.exist; - expect(explanation).property('executionStats').to.exist; - }); - }); - - context('aggregate()', () => { - it('when explain is set to true, aggregate result returns queryPlanner and executionStats properties', async function () { - const aggResult = await collection - .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }], { explain: true }) - .toArray(); - - if (aggResult[0].stages) { - expect(aggResult[0].stages).to.have.length.gte(1); - expect(aggResult[0].stages[0]).to.have.property('$cursor'); - expect(aggResult[0].stages[0].$cursor).to.have.property('queryPlanner'); - expect(aggResult[0].stages[0].$cursor).to.have.property('executionStats'); - } else if (aggResult[0].$cursor) { - expect(aggResult[0].$cursor).to.have.property('queryPlanner'); - expect(aggResult[0].$cursor).to.have.property('executionStats'); - } else { - expect(aggResult[0]).to.have.property('queryPlanner'); - expect(aggResult[0]).to.have.property('executionStats'); - } - }); - - it('when explain is set to "executionStats", aggregate result returns queryPlanner and executionStats properties', async function () { - const aggResult = await collection - .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }], { - explain: 'executionStats' - }) - .toArray(); - if (aggResult[0].stages) { - expect(aggResult[0].stages).to.have.length.gte(1); - expect(aggResult[0].stages[0]).to.have.property('$cursor'); - expect(aggResult[0].stages[0].$cursor).to.have.property('queryPlanner'); - expect(aggResult[0].stages[0].$cursor).to.have.property('executionStats'); - } else if (aggResult[0].$cursor) { - expect(aggResult[0].$cursor).to.have.property('queryPlanner'); - expect(aggResult[0].$cursor).to.have.property('executionStats'); - } else { - expect(aggResult[0]).to.have.property('queryPlanner'); - expect(aggResult[0]).to.have.property('executionStats'); - } - }); - - it('when explain is set to false, aggregate result returns queryPlanner property', async function () { - const aggResult = await collection - .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }]) - .explain(false); - if (aggResult && aggResult.stages) { - expect(aggResult.stages).to.have.length.gte(1); - expect(aggResult.stages[0]).to.have.property('$cursor'); - expect(aggResult.stages[0].$cursor).to.have.property('queryPlanner'); - expect(aggResult.stages[0].$cursor).to.not.have.property('executionStats'); - } else if (aggResult.$cursor) { - expect(aggResult.$cursor).to.have.property('queryPlanner'); - expect(aggResult.$cursor).to.not.have.property('executionStats'); - } else { - expect(aggResult).to.have.property('queryPlanner'); - expect(aggResult).to.not.have.property('executionStats'); - } - }); - - it('when explain is set to "allPlansExecution", aggregate result returns queryPlanner and executionStats properties', async function () { - const aggResult = await collection - .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }]) - .explain('allPlansExecution'); - - if (aggResult && aggResult.stages) { - expect(aggResult.stages).to.have.length.gte(1); - expect(aggResult.stages[0]).to.have.property('$cursor'); - expect(aggResult.stages[0].$cursor).to.have.property('queryPlanner'); - expect(aggResult.stages[0].$cursor).to.have.property('executionStats'); - } else { - expect(aggResult).to.have.property('queryPlanner'); - expect(aggResult).to.have.property('executionStats'); - } - }); - - it('when explain is not set, aggregate result returns queryPlanner and executionStats properties', async function () { - const aggResult = await collection - .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }]) - .explain(); - if (aggResult && aggResult.stages) { - expect(aggResult.stages).to.have.length.gte(1); - expect(aggResult.stages[0]).to.have.property('$cursor'); - expect(aggResult.stages[0].$cursor).to.have.property('queryPlanner'); - expect(aggResult.stages[0].$cursor).to.have.property('executionStats'); - } else { - expect(aggResult).to.have.property('queryPlanner'); - expect(aggResult).to.have.property('executionStats'); - } - }); - }); - - context('when explain is set to an unexpected value', () => { - it('should throw a catchable error with invalid explain string', async function () { - const error = await collection - .find({ a: 1 }) - .explain('invalidExplain') - .catch(error => error); - expect(error).to.be.instanceOf(MongoServerError); - }); - }); - */ }); function explainValueToExpectation(explainValue: boolean | string) { From 39a29b6e625d82d1af0c9bdd06f32656e638770c Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Mon, 26 Jun 2023 15:44:45 -0400 Subject: [PATCH 13/24] combined names and ops --- test/integration/crud/explain.test.ts | 78 ++++++++++++++++----------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index e1263ec60b..c17fb363ef 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -17,35 +17,50 @@ describe('Explain', function () { let collection: Collection; let commandStartedPromise: Promise; const ops = [ - async (explain: boolean | string) => await collection.deleteOne({ a: 1 }, { explain }), - async (explain: boolean | string) => await collection.deleteMany({ a: 1 }, { explain }), - async (explain: boolean | string) => - await collection.updateOne({ a: 1 }, { $inc: { a: 2 } }, { explain }), - async (explain: boolean | string) => - await collection.updateMany({ a: 1 }, { $inc: { a: 2 } }, { explain }), - async (explain: boolean | string) => await collection.distinct('a', {}, { explain }), - async (explain: boolean | string) => await collection.findOneAndDelete({ a: 1 }, { explain }), - async (explain: boolean | string) => await collection.findOne({ a: 1 }, { explain }), - (explain: boolean | string) => collection.find({ a: 1 }).explain(explain), - async (explain: boolean | string) => - await collection.findOneAndReplace({ a: 1 }, { a: 2 }, { explain }), - async (explain: boolean | string) => - await collection - .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }], { explain }) - .toArray() - ]; - - const opNames = [ - 'deleteOne', - 'deleteMany', - 'updateOne', - 'updateMany', - 'distinct', - 'findOneAndDelete', - 'findOne', - 'find', - 'findOneAndReplace', - 'aggregate' + { + name: 'deleteOne', + op: async (explain: boolean | string) => await collection.deleteOne({ a: 1 }, { explain }) + }, + { + name: 'deleteMany', + op: async (explain: boolean | string) => await collection.deleteMany({ a: 1 }, { explain }) + }, + { + name: 'updateOne', + op: async (explain: boolean | string) => + await collection.updateOne({ a: 1 }, { $inc: { a: 2 } }, { explain }) + }, + { + name: 'updateMany', + op: async (explain: boolean | string) => + await collection.updateMany({ a: 1 }, { $inc: { a: 2 } }, { explain }) + }, + { + name: 'distinct', + op: async (explain: boolean | string) => await collection.distinct('a', {}, { explain }) + }, + { + name: 'findOneAndDelete', + op: async (explain: boolean | string) => + await collection.findOneAndDelete({ a: 1 }, { explain }) + }, + { + name: 'findOne', + op: async (explain: boolean | string) => await collection.findOne({ a: 1 }, { explain }) + }, + { name: 'find', op: (explain: boolean | string) => collection.find({ a: 1 }).explain(explain) }, + { + name: 'findOneAndReplace', + op: async (explain: boolean | string) => + await collection.findOneAndReplace({ a: 1 }, { a: 2 }, { explain }) + }, + { + name: 'aggregate', + op: async (explain: boolean | string) => + await collection + .aggregate([{ $project: { a: 1 } }, { $group: { _id: '$a' } }], { explain }) + .toArray() + } ]; beforeEach(async function () { @@ -64,9 +79,9 @@ describe('Explain', function () { for (const explainValue of explain) { context(`When explain is ${explainValue}`, function () { for (const op of ops) { - const name = opNames[ops.indexOf(op)]; + const name = op.name; it(`${name} returns ${explainValueToExpectation(explainValue)}`, async function () { - const response = await op(explainValue).catch(error => error); + const response = await op.op(explainValue).catch(error => error); const commandStartedEvent = await commandStartedPromise; switch (explainValue) { case true: @@ -104,6 +119,7 @@ describe('Explain', function () { } break; default: + // for invalid values of explain expect(response).to.be.instanceOf(MongoServerError); break; } From 880ad395e9ee2ba00ac0823625854a9d28ccce68 Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Tue, 27 Jun 2023 13:40:58 -0400 Subject: [PATCH 14/24] fixed server version error for aggregate --- test/integration/crud/explain.test.ts | 37 +++++++++++++++++++++------ 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index c17fb363ef..1f8734c4cb 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -11,7 +11,7 @@ import { const explain = [true, false, 'queryPlanner', 'allPlansExecution', 'executionStats', 'invalid']; -describe('Explain', function () { +describe.only('Explain', function () { let client: MongoClient; let db: Db; let collection: Collection; @@ -88,8 +88,14 @@ describe('Explain', function () { case 'allPlansExecution': expect(commandStartedEvent[0].command.verbosity).to.be.equal('allPlansExecution'); if (name === 'aggregate') { - expect(response[0]).to.have.property('queryPlanner'); - expect(response[0]).nested.property('executionStats.allPlansExecution').to.exist; + if (response.stages) { + expect(response.stages[0]).to.have.property('queryPlanner'); + expect(response.stages[0]).nested.property('executionStats.allPlansExecution').to + .exist; + } else { + expect(response[0]).to.have.property('queryPlanner'); + expect(response[0]).nested.property('executionStats.allPlansExecution').to.exist; + } } else { expect(response).to.have.property('queryPlanner'); expect(response).nested.property('executionStats.allPlansExecution').to.exist; @@ -99,8 +105,13 @@ describe('Explain', function () { case 'queryPlanner': expect(commandStartedEvent[0].command.verbosity).to.be.equal('queryPlanner'); if (name === 'aggregate') { - expect(response[0]).to.have.property('queryPlanner'); - expect(response[0]).to.not.have.property('executionStats'); + if (response.stages) { + expect(response.stages[0]).to.have.property('queryPlanner'); + expect(response.stages[0]).to.not.have.property('executionStats'); + } else { + expect(response[0]).to.have.property('queryPlanner'); + expect(response[0]).to.not.have.property('executionStats'); + } } else { expect(response).to.have.property('queryPlanner'); expect(response).to.not.have.property('executionStats'); @@ -109,9 +120,19 @@ describe('Explain', function () { case 'executionStats': expect(commandStartedEvent[0].command.verbosity).to.be.equal('executionStats'); if (name === 'aggregate') { - expect(response[0]).to.have.property('queryPlanner'); - expect(response[0]).to.have.property('executionStats'); - expect(response[0]).to.not.have.nested.property('executionStats.allPlansExecution'); + if (response.stages) { + expect(response.stages[0]).to.have.property('queryPlanner'); + expect(response.stages[0]).to.have.property('executionStats'); + expect(response.stages[0]).to.not.have.nested.property( + 'executionStats.allPlansExecution' + ); + } else { + expect(response[0]).to.have.property('queryPlanner'); + expect(response[0]).to.have.property('executionStats'); + expect(response[0]).to.not.have.nested.property( + 'executionStats.allPlansExecution' + ); + } } else { expect(response).to.have.property('queryPlanner'); expect(response).to.have.property('executionStats'); From 862f3f8c4984ff6ebc066b04d9b58ba70f9ea608 Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Tue, 27 Jun 2023 14:00:54 -0400 Subject: [PATCH 15/24] fixed more aggregate errors --- test/integration/crud/explain.test.ts | 42 ++++++++++++++++++++------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index 1f8734c4cb..ebb56e6a2d 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -11,7 +11,7 @@ import { const explain = [true, false, 'queryPlanner', 'allPlansExecution', 'executionStats', 'invalid']; -describe.only('Explain', function () { +describe('Explain', function () { let client: MongoClient; let db: Db; let collection: Collection; @@ -89,9 +89,16 @@ describe.only('Explain', function () { expect(commandStartedEvent[0].command.verbosity).to.be.equal('allPlansExecution'); if (name === 'aggregate') { if (response.stages) { - expect(response.stages[0]).to.have.property('queryPlanner'); - expect(response.stages[0]).nested.property('executionStats.allPlansExecution').to - .exist; + if (response.stages[0].$cursor) { + expect(response.stages[0].$cursor).to.have.property('queryPlanner'); + expect(response.stages[0].$cursor).nested.property( + 'executionStats.allPlansExecution' + ).to.exist; + } else { + expect(response.stages[0]).to.have.property('queryPlanner'); + expect(response.stages[0]).nested.property('executionStats.allPlansExecution') + .to.exist; + } } else { expect(response[0]).to.have.property('queryPlanner'); expect(response[0]).nested.property('executionStats.allPlansExecution').to.exist; @@ -106,8 +113,13 @@ describe.only('Explain', function () { expect(commandStartedEvent[0].command.verbosity).to.be.equal('queryPlanner'); if (name === 'aggregate') { if (response.stages) { - expect(response.stages[0]).to.have.property('queryPlanner'); - expect(response.stages[0]).to.not.have.property('executionStats'); + if (response.stages[0].$cursor) { + expect(response.stages[0].$cursor).to.have.property('queryPlanner'); + expect(response.stages[0].$cursor).to.not.have.property('executionStats'); + } else { + expect(response.stages[0]).to.have.property('queryPlanner'); + expect(response.stages[0]).to.not.have.property('executionStats'); + } } else { expect(response[0]).to.have.property('queryPlanner'); expect(response[0]).to.not.have.property('executionStats'); @@ -121,11 +133,19 @@ describe.only('Explain', function () { expect(commandStartedEvent[0].command.verbosity).to.be.equal('executionStats'); if (name === 'aggregate') { if (response.stages) { - expect(response.stages[0]).to.have.property('queryPlanner'); - expect(response.stages[0]).to.have.property('executionStats'); - expect(response.stages[0]).to.not.have.nested.property( - 'executionStats.allPlansExecution' - ); + if (response.stages[0].$cursor) { + expect(response.stages[0].$cursor).to.have.property('queryPlanner'); + expect(response.stages[0].$cursor).to.have.property('executionStats'); + expect(response.stages[0].$cursor).to.not.have.nested.property( + 'executionStats.allPlansExecution' + ); + } else { + expect(response.stages[0]).to.have.property('queryPlanner'); + expect(response.stages[0]).to.have.property('executionStats'); + expect(response.stages[0]).to.not.have.nested.property( + 'executionStats.allPlansExecution' + ); + } } else { expect(response[0]).to.have.property('queryPlanner'); expect(response[0]).to.have.property('executionStats'); From 211ecdfe0ed8055c5b9d795c5ef7c62868ac96bf Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Tue, 27 Jun 2023 15:26:20 -0400 Subject: [PATCH 16/24] aggregate --- test/integration/crud/explain.test.ts | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index ebb56e6a2d..c6e9342355 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -90,10 +90,13 @@ describe('Explain', function () { if (name === 'aggregate') { if (response.stages) { if (response.stages[0].$cursor) { - expect(response.stages[0].$cursor).to.have.property('queryPlanner'); + expect(response.stages[0].$cursor).to.have.property('queryPlanner') || + expect(response.stages[0]).to.have.property('queryPlanner'); expect(response.stages[0].$cursor).nested.property( 'executionStats.allPlansExecution' - ).to.exist; + ).to.exist || + expect(response.stages[0]).nested.property('executionStats.allPlansExecution') + .to.exist; } else { expect(response.stages[0]).to.have.property('queryPlanner'); expect(response.stages[0]).nested.property('executionStats.allPlansExecution') @@ -114,8 +117,10 @@ describe('Explain', function () { if (name === 'aggregate') { if (response.stages) { if (response.stages[0].$cursor) { - expect(response.stages[0].$cursor).to.have.property('queryPlanner'); - expect(response.stages[0].$cursor).to.not.have.property('executionStats'); + expect(response.stages[0].$cursor).to.have.property('queryPlanner') || + expect(response.stages[0]).to.have.property('queryPlanner'); + expect(response.stages[0].$cursor).to.not.have.property('executionStats') || + expect(response.stages[0]).to.not.have.property('executionStats'); } else { expect(response.stages[0]).to.have.property('queryPlanner'); expect(response.stages[0]).to.not.have.property('executionStats'); @@ -134,11 +139,16 @@ describe('Explain', function () { if (name === 'aggregate') { if (response.stages) { if (response.stages[0].$cursor) { - expect(response.stages[0].$cursor).to.have.property('queryPlanner'); - expect(response.stages[0].$cursor).to.have.property('executionStats'); + expect(response.stages[0].$cursor).to.have.property('queryPlanner') || + expect(response.stages[0]).to.have.property('queryPlanner'); + expect(response.stages[0].$cursor).to.have.property('executionStats') || + expect(response.stages[0]).to.have.property('executionStats'); expect(response.stages[0].$cursor).to.not.have.nested.property( 'executionStats.allPlansExecution' - ); + ) || + expect(response.stages[0]).to.not.have.nested.property( + 'executionStats.allPlansExecution' + ); } else { expect(response.stages[0]).to.have.property('queryPlanner'); expect(response.stages[0]).to.have.property('executionStats'); From 3b9e57f792a8a68dbb1dd0d109b0ee2e9b7b8fce Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Tue, 27 Jun 2023 16:18:36 -0400 Subject: [PATCH 17/24] fixed aggregate errors --- test/integration/crud/explain.test.ts | 97 ++++++++++----------------- 1 file changed, 37 insertions(+), 60 deletions(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index c6e9342355..45cb62ecd8 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -11,7 +11,7 @@ import { const explain = [true, false, 'queryPlanner', 'allPlansExecution', 'executionStats', 'invalid']; -describe('Explain', function () { +describe.only('CRUD API explain option', function () { let client: MongoClient; let db: Db; let collection: Collection; @@ -77,97 +77,74 @@ describe('Explain', function () { }); for (const explainValue of explain) { - context(`When explain is ${explainValue}`, function () { - for (const op of ops) { - const name = op.name; - it(`${name} returns ${explainValueToExpectation(explainValue)}`, async function () { + for (const op of ops) { + const name = op.name; + context(`When explain is ${explainValue}, operation ${name}`, function () { + it(`returns ${explainValueToExpectation(explainValue)}`, async function () { const response = await op.op(explainValue).catch(error => error); const commandStartedEvent = await commandStartedPromise; + let responsePropertyToCheck; switch (explainValue) { case true: case 'allPlansExecution': expect(commandStartedEvent[0].command.verbosity).to.be.equal('allPlansExecution'); if (name === 'aggregate') { - if (response.stages) { - if (response.stages[0].$cursor) { - expect(response.stages[0].$cursor).to.have.property('queryPlanner') || - expect(response.stages[0]).to.have.property('queryPlanner'); - expect(response.stages[0].$cursor).nested.property( - 'executionStats.allPlansExecution' - ).to.exist || - expect(response.stages[0]).nested.property('executionStats.allPlansExecution') - .to.exist; + if (response[0].stages) { + if (response[0].stages[0].$cursor) { + responsePropertyToCheck = response[0].stages[0].$cursor; } else { - expect(response.stages[0]).to.have.property('queryPlanner'); - expect(response.stages[0]).nested.property('executionStats.allPlansExecution') - .to.exist; + responsePropertyToCheck = response[0].stages[0]; } } else { - expect(response[0]).to.have.property('queryPlanner'); - expect(response[0]).nested.property('executionStats.allPlansExecution').to.exist; + responsePropertyToCheck = response[0]; } } else { - expect(response).to.have.property('queryPlanner'); - expect(response).nested.property('executionStats.allPlansExecution').to.exist; + responsePropertyToCheck = response; } + expect(responsePropertyToCheck).to.have.property('queryPlanner'); + expect(responsePropertyToCheck).nested.property( + 'executionStats.allPlansExecution' + ).to.exist; break; case false: case 'queryPlanner': expect(commandStartedEvent[0].command.verbosity).to.be.equal('queryPlanner'); if (name === 'aggregate') { - if (response.stages) { - if (response.stages[0].$cursor) { - expect(response.stages[0].$cursor).to.have.property('queryPlanner') || - expect(response.stages[0]).to.have.property('queryPlanner'); - expect(response.stages[0].$cursor).to.not.have.property('executionStats') || - expect(response.stages[0]).to.not.have.property('executionStats'); + if (response[0].stages) { + if (response[0].stages[0].$cursor) { + responsePropertyToCheck = response[0].stages[0].$cursor; } else { - expect(response.stages[0]).to.have.property('queryPlanner'); - expect(response.stages[0]).to.not.have.property('executionStats'); + responsePropertyToCheck = response[0].stages[0]; } } else { - expect(response[0]).to.have.property('queryPlanner'); - expect(response[0]).to.not.have.property('executionStats'); + responsePropertyToCheck = response[0]; } } else { - expect(response).to.have.property('queryPlanner'); - expect(response).to.not.have.property('executionStats'); + responsePropertyToCheck = response; } + expect(responsePropertyToCheck).to.have.property('queryPlanner'); + expect(responsePropertyToCheck).to.not.have.property('executionStats'); break; case 'executionStats': expect(commandStartedEvent[0].command.verbosity).to.be.equal('executionStats'); if (name === 'aggregate') { - if (response.stages) { - if (response.stages[0].$cursor) { - expect(response.stages[0].$cursor).to.have.property('queryPlanner') || - expect(response.stages[0]).to.have.property('queryPlanner'); - expect(response.stages[0].$cursor).to.have.property('executionStats') || - expect(response.stages[0]).to.have.property('executionStats'); - expect(response.stages[0].$cursor).to.not.have.nested.property( - 'executionStats.allPlansExecution' - ) || - expect(response.stages[0]).to.not.have.nested.property( - 'executionStats.allPlansExecution' - ); + if (response[0].stages) { + if (response[0].stages[0].$cursor) { + responsePropertyToCheck = response[0].stages[0].$cursor; } else { - expect(response.stages[0]).to.have.property('queryPlanner'); - expect(response.stages[0]).to.have.property('executionStats'); - expect(response.stages[0]).to.not.have.nested.property( - 'executionStats.allPlansExecution' - ); + responsePropertyToCheck = response[0].stages[0]; } } else { - expect(response[0]).to.have.property('queryPlanner'); - expect(response[0]).to.have.property('executionStats'); - expect(response[0]).to.not.have.nested.property( - 'executionStats.allPlansExecution' - ); + responsePropertyToCheck = response[0]; } } else { - expect(response).to.have.property('queryPlanner'); - expect(response).to.have.property('executionStats'); - expect(response).to.not.have.nested.property('executionStats.allPlansExecution'); + responsePropertyToCheck = response; } + expect(responsePropertyToCheck).to.have.property('queryPlanner'); + expect(responsePropertyToCheck).to.have.property('executionStats'); + expect(responsePropertyToCheck).to.not.have.nested.property( + 'executionStats.allPlansExecution' + ); break; default: // for invalid values of explain @@ -175,8 +152,8 @@ describe('Explain', function () { break; } }); - } - }); + }); + } } }); From 29e8736935fb8193dc31413c2cd4d190dd32a1c2 Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Tue, 27 Jun 2023 16:18:59 -0400 Subject: [PATCH 18/24] removed .only --- test/integration/crud/explain.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index 45cb62ecd8..d0a02f02a4 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -11,7 +11,7 @@ import { const explain = [true, false, 'queryPlanner', 'allPlansExecution', 'executionStats', 'invalid']; -describe.only('CRUD API explain option', function () { +describe('CRUD API explain option', function () { let client: MongoClient; let db: Db; let collection: Collection; From 783f17f1aa2b39a4d2f0c3369087446a4429e1ad Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Wed, 28 Jun 2023 11:37:22 -0400 Subject: [PATCH 19/24] cleaned up explainDocument check --- test/integration/crud/explain.test.ts | 63 ++++++--------------------- 1 file changed, 14 insertions(+), 49 deletions(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index d0a02f02a4..8f32dc58da 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -83,66 +83,31 @@ describe('CRUD API explain option', function () { it(`returns ${explainValueToExpectation(explainValue)}`, async function () { const response = await op.op(explainValue).catch(error => error); const commandStartedEvent = await commandStartedPromise; - let responsePropertyToCheck; + let explainDocument; + if (name !== 'aggregate') { + // value changes depending on server version + explainDocument = response[0].stages[0].$cursor ?? response[0].stages[0] ?? response[0]; + } else { + explainDocument = response; + } switch (explainValue) { case true: case 'allPlansExecution': expect(commandStartedEvent[0].command.verbosity).to.be.equal('allPlansExecution'); - if (name === 'aggregate') { - if (response[0].stages) { - if (response[0].stages[0].$cursor) { - responsePropertyToCheck = response[0].stages[0].$cursor; - } else { - responsePropertyToCheck = response[0].stages[0]; - } - } else { - responsePropertyToCheck = response[0]; - } - } else { - responsePropertyToCheck = response; - } - expect(responsePropertyToCheck).to.have.property('queryPlanner'); - expect(responsePropertyToCheck).nested.property( - 'executionStats.allPlansExecution' - ).to.exist; + expect(explainDocument).to.have.property('queryPlanner'); + expect(explainDocument).nested.property('executionStats.allPlansExecution').to.exist; break; case false: case 'queryPlanner': expect(commandStartedEvent[0].command.verbosity).to.be.equal('queryPlanner'); - if (name === 'aggregate') { - if (response[0].stages) { - if (response[0].stages[0].$cursor) { - responsePropertyToCheck = response[0].stages[0].$cursor; - } else { - responsePropertyToCheck = response[0].stages[0]; - } - } else { - responsePropertyToCheck = response[0]; - } - } else { - responsePropertyToCheck = response; - } - expect(responsePropertyToCheck).to.have.property('queryPlanner'); - expect(responsePropertyToCheck).to.not.have.property('executionStats'); + expect(explainDocument).to.have.property('queryPlanner'); + expect(explainDocument).to.not.have.property('executionStats'); break; case 'executionStats': expect(commandStartedEvent[0].command.verbosity).to.be.equal('executionStats'); - if (name === 'aggregate') { - if (response[0].stages) { - if (response[0].stages[0].$cursor) { - responsePropertyToCheck = response[0].stages[0].$cursor; - } else { - responsePropertyToCheck = response[0].stages[0]; - } - } else { - responsePropertyToCheck = response[0]; - } - } else { - responsePropertyToCheck = response; - } - expect(responsePropertyToCheck).to.have.property('queryPlanner'); - expect(responsePropertyToCheck).to.have.property('executionStats'); - expect(responsePropertyToCheck).to.not.have.nested.property( + expect(explainDocument).to.have.property('queryPlanner'); + expect(explainDocument).to.have.property('executionStats'); + expect(explainDocument).to.not.have.nested.property( 'executionStats.allPlansExecution' ); break; From 074d075ec77452607b5fc46a3dc6e02ddbdb7644 Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Wed, 28 Jun 2023 12:10:00 -0400 Subject: [PATCH 20/24] bug fix --- test/integration/crud/explain.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index 8f32dc58da..496d5b4008 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -84,7 +84,7 @@ describe('CRUD API explain option', function () { const response = await op.op(explainValue).catch(error => error); const commandStartedEvent = await commandStartedPromise; let explainDocument; - if (name !== 'aggregate') { + if (name === 'aggregate' && explainValue !== 'invalid') { // value changes depending on server version explainDocument = response[0].stages[0].$cursor ?? response[0].stages[0] ?? response[0]; } else { From 2439c8ce535772303516d854d62fc6396a509a94 Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Wed, 28 Jun 2023 13:10:41 -0400 Subject: [PATCH 21/24] added optional chaining --- test/integration/crud/explain.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index 496d5b4008..7d294a2e3e 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -11,7 +11,7 @@ import { const explain = [true, false, 'queryPlanner', 'allPlansExecution', 'executionStats', 'invalid']; -describe('CRUD API explain option', function () { +describe.only('CRUD API explain option', function () { let client: MongoClient; let db: Db; let collection: Collection; @@ -86,7 +86,8 @@ describe('CRUD API explain option', function () { let explainDocument; if (name === 'aggregate' && explainValue !== 'invalid') { // value changes depending on server version - explainDocument = response[0].stages[0].$cursor ?? response[0].stages[0] ?? response[0]; + explainDocument = + response[0].stages?.[0]?.$cursor ?? response[0]?.stages ?? response[0]; } else { explainDocument = response; } From baeab10b7f5c2d0ee92cbe3da7be890479be933c Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Wed, 28 Jun 2023 13:22:58 -0400 Subject: [PATCH 22/24] removed .only --- test/integration/crud/explain.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index 7d294a2e3e..eac1c634e1 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -11,7 +11,7 @@ import { const explain = [true, false, 'queryPlanner', 'allPlansExecution', 'executionStats', 'invalid']; -describe.only('CRUD API explain option', function () { +describe('CRUD API explain option', function () { let client: MongoClient; let db: Db; let collection: Collection; From d05b2cc167f6a02cb17e2c8b18dfc98d4107a218 Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Wed, 28 Jun 2023 15:14:23 -0400 Subject: [PATCH 23/24] specified it blocks --- test/integration/crud/explain.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index eac1c634e1..b3c50bd521 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -11,7 +11,7 @@ import { const explain = [true, false, 'queryPlanner', 'allPlansExecution', 'executionStats', 'invalid']; -describe('CRUD API explain option', function () { +describe.only('CRUD API explain option', function () { let client: MongoClient; let db: Db; let collection: Collection; @@ -80,7 +80,7 @@ describe('CRUD API explain option', function () { for (const op of ops) { const name = op.name; context(`When explain is ${explainValue}, operation ${name}`, function () { - it(`returns ${explainValueToExpectation(explainValue)}`, async function () { + it(`sets command verbosity to ${explainValue} and includes ${explainValueToExpectation(explainValue)} in the return response`, async function () { const response = await op.op(explainValue).catch(error => error); const commandStartedEvent = await commandStartedPromise; let explainDocument; @@ -127,12 +127,12 @@ function explainValueToExpectation(explainValue: boolean | string) { switch (explainValue) { case true: case 'allPlansExecution': - return 'allPlansExecution property'; + return 'queryPlanner, executionStats, and nested allPlansExecution properties'; case false: case 'queryPlanner': - return 'queryPlanner property'; + return 'only queryPlanner property'; case 'executionStats': - return 'executionStats property'; + return 'queryPlanner and executionStats property'; default: return 'error'; } From 3ce249b8a6e03e3a322112329ecd6cfb1a7bd17f Mon Sep 17 00:00:00 2001 From: Malik Javaid Date: Wed, 28 Jun 2023 15:21:52 -0400 Subject: [PATCH 24/24] removed .only --- test/integration/crud/explain.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/crud/explain.test.ts b/test/integration/crud/explain.test.ts index b3c50bd521..d00caff025 100644 --- a/test/integration/crud/explain.test.ts +++ b/test/integration/crud/explain.test.ts @@ -11,7 +11,7 @@ import { const explain = [true, false, 'queryPlanner', 'allPlansExecution', 'executionStats', 'invalid']; -describe.only('CRUD API explain option', function () { +describe('CRUD API explain option', function () { let client: MongoClient; let db: Db; let collection: Collection;