|
7 | 7 | BSON,
|
8 | 8 | type ClientSession,
|
9 | 9 | type Collection,
|
| 10 | + type CommandStartedEvent, |
10 | 11 | Connection,
|
11 | 12 | type Db,
|
12 | 13 | type FindCursor,
|
@@ -320,4 +321,124 @@ describe('CSOT driver tests', { requires: { mongodb: '>=4.4' } }, () => {
|
320 | 321 | });
|
321 | 322 | });
|
322 | 323 | });
|
| 324 | + |
| 325 | + describe('Non-Tailable cursors', () => { |
| 326 | + let client: MongoClient; |
| 327 | + let internalClient: MongoClient; |
| 328 | + let commandStarted: CommandStartedEvent[]; |
| 329 | + const failpoint: FailPoint = { |
| 330 | + configureFailPoint: 'failCommand', |
| 331 | + mode: 'alwaysOn', |
| 332 | + data: { |
| 333 | + failCommands: ['find'], |
| 334 | + blockConnection: true, |
| 335 | + blockTimeMS: 30 |
| 336 | + } |
| 337 | + }; |
| 338 | + |
| 339 | + beforeEach(async function () { |
| 340 | + internalClient = this.configuration.newClient(undefined); |
| 341 | + await internalClient.db('db').dropCollection('coll'); |
| 342 | + await internalClient |
| 343 | + .db('db') |
| 344 | + .collection('coll') |
| 345 | + .insertMany( |
| 346 | + Array.from({ length: 3 }, () => { |
| 347 | + return { x: 1 }; |
| 348 | + }) |
| 349 | + ); |
| 350 | + |
| 351 | + await internalClient.db().admin().command(failpoint); |
| 352 | + |
| 353 | + client = this.configuration.newClient(undefined, { timeoutMS: 20, monitorCommands: true }); |
| 354 | + commandStarted = []; |
| 355 | + client.on('commandStarted', ev => commandStarted.push(ev)); |
| 356 | + }); |
| 357 | + |
| 358 | + afterEach(async function () { |
| 359 | + await internalClient |
| 360 | + .db() |
| 361 | + .admin() |
| 362 | + .command({ ...failpoint, mode: 'off' }); |
| 363 | + await internalClient.close(); |
| 364 | + await client.close(); |
| 365 | + }); |
| 366 | + |
| 367 | + context('ITERATION mode', () => { |
| 368 | + context('when executing a valid operation', () => { |
| 369 | + it('must apply the configured timeoutMS to the initial operation execution', async function () { |
| 370 | + const cursor = client |
| 371 | + .db('db') |
| 372 | + .collection('coll') |
| 373 | + .find({}, { batchSize: 3, timeoutMode: 'iteration' }) |
| 374 | + .limit(3); |
| 375 | + |
| 376 | + const maybeError = await cursor.next().then( |
| 377 | + () => null, |
| 378 | + e => e |
| 379 | + ); |
| 380 | + |
| 381 | + expect(maybeError).to.be.instanceOf(MongoOperationTimeoutError); |
| 382 | + }); |
| 383 | + |
| 384 | + it('refreshes the timeout for any getMores', async function () { |
| 385 | + const cursor = client |
| 386 | + .db('db') |
| 387 | + .collection('coll') |
| 388 | + .find({}, { batchSize: 1, timeoutMode: 'iteration' }) |
| 389 | + .project({ _id: 0 }) |
| 390 | + .limit(2); |
| 391 | + |
| 392 | + const firstDoc = await cursor.next(); |
| 393 | + expect(firstDoc).to.deep.equal({ x: 1 }); |
| 394 | + |
| 395 | + const maybeError = await cursor.next().then( |
| 396 | + () => null, |
| 397 | + e => e |
| 398 | + ); |
| 399 | + |
| 400 | + expect(maybeError).to.be.instanceOf(MongoOperationTimeoutError); |
| 401 | + }); |
| 402 | + it('does not append a maxTimeMS to the original command or getMores', async function () { |
| 403 | + const cursor = client |
| 404 | + .db('db') |
| 405 | + .collection('coll') |
| 406 | + .find({}, { batchSize: 1, timeoutMode: 'iteration' }) |
| 407 | + .project({ _id: 0 }); |
| 408 | + await cursor.toArray(); |
| 409 | + |
| 410 | + expect(commandStarted).to.have.length.gte(3); // Find and 2 getMores |
| 411 | + expect( |
| 412 | + commandStarted.filter(ev => { |
| 413 | + return ( |
| 414 | + ev.command.find != null && |
| 415 | + ev.command.getMore != null && |
| 416 | + ev.command.maxTimeMS != null |
| 417 | + ); |
| 418 | + }) |
| 419 | + ).to.have.lengthOf(0); |
| 420 | + }); |
| 421 | + }); |
| 422 | + }); |
| 423 | + |
| 424 | + context('LIFETIME mode', () => { |
| 425 | + context('when executing a next call', () => { |
| 426 | + context( |
| 427 | + 'when there are documents available from previously retrieved batch and timeout has expired', |
| 428 | + () => { |
| 429 | + it('returns documents without error'); |
| 430 | + } |
| 431 | + ); |
| 432 | + context('when a getMore is required and the timeout has expired', () => { |
| 433 | + it('throws a MongoOperationTimeoutError'); |
| 434 | + }); |
| 435 | + it('does not apply maxTimeMS to a getMore'); |
| 436 | + }); |
| 437 | + }); |
| 438 | + }); |
| 439 | + |
| 440 | + describe.skip('Tailable non-awaitData cursors').skipReason = |
| 441 | + 'TODO(NODE-6305): implement CSOT for Tailable cursors'; |
| 442 | + describe.skip('Tailable awaitData cursors').skipReason = |
| 443 | + 'TODO(NODE-6305): implement CSOT for Tailable cursors'; |
323 | 444 | });
|
0 commit comments