|
1 |
| -/* eslint no-empty: ["error", { "allowEmptyCatch": true }] */ |
2 |
| -'use strict'; |
3 |
| - |
4 |
| -const expect = require('chai').expect; |
5 |
| -const mock = require('../tools/mongodb-mock/index'); |
6 |
| -const { getSymbolFrom } = require('../tools/utils'); |
7 |
| -const { ReplSetFixture } = require('../tools/common'); |
8 |
| -const { ns, isHello } = require('../../src/utils'); |
9 |
| -const { Topology } = require('../../src/sdam/topology'); |
10 |
| -const { |
11 |
| - MongoNetworkError, |
12 |
| - MongoWriteConcernError, |
| 1 | +import { expect } from 'chai'; |
| 2 | + |
| 3 | +import { |
| 4 | + PoolClosedError as MongoPoolClosedError, |
| 5 | + WaitQueueTimeoutError as MongoWaitQueueTimeoutError |
| 6 | +} from '../../src/cmap/errors'; |
| 7 | +import { |
| 8 | + isRetryableEndTransactionError, |
| 9 | + isSDAMUnrecoverableError, |
| 10 | + LEGACY_NOT_PRIMARY_OR_SECONDARY_ERROR_MESSAGE, |
| 11 | + LEGACY_NOT_WRITABLE_PRIMARY_ERROR_MESSAGE, |
| 12 | + MongoSystemError, |
| 13 | + NODE_IS_RECOVERING_ERROR_MESSAGE |
| 14 | +} from '../../src/error'; |
| 15 | +import * as importsFromErrorSrc from '../../src/error'; |
| 16 | +import { |
13 | 17 | MongoError,
|
| 18 | + MongoNetworkError, |
| 19 | + MongoParseError, |
14 | 20 | MongoServerError,
|
15 |
| - MongoParseError |
16 |
| -} = require('../../src/index'); |
17 |
| -const { |
18 |
| - LEGACY_NOT_WRITABLE_PRIMARY_ERROR_MESSAGE, |
19 |
| - LEGACY_NOT_PRIMARY_OR_SECONDARY_ERROR_MESSAGE, |
20 |
| - NODE_IS_RECOVERING_ERROR_MESSAGE, |
21 |
| - isRetryableEndTransactionError, |
22 |
| - isSDAMUnrecoverableError |
23 |
| -} = require('../../src/error'); |
24 |
| -const { |
25 |
| - PoolClosedError: MongoPoolClosedError, |
26 |
| - WaitQueueTimeoutError: MongoWaitQueueTimeoutError |
27 |
| -} = require('../../src/cmap/errors'); |
| 21 | + MongoWriteConcernError, |
| 22 | + TopologyDescription |
| 23 | +} from '../../src/index'; |
| 24 | +import * as importsFromEntryPoint from '../../src/index'; |
| 25 | +import { Topology, TopologyOptions } from '../../src/sdam/topology'; |
| 26 | +import { isHello, ns, setDifference } from '../../src/utils'; |
| 27 | +import { ReplSetFixture } from '../tools/common'; |
| 28 | +import { cleanup } from '../tools/mongodb-mock/index'; |
| 29 | +import { getSymbolFrom } from '../tools/utils'; |
28 | 30 |
|
29 | 31 | describe('MongoErrors', () => {
|
30 |
| - // import errors as object |
31 |
| - let errorClasses = Object.fromEntries( |
32 |
| - Object.entries(require('../../src/index')).filter(([key]) => key.endsWith('Error')) |
| 32 | + let errorClassesFromEntryPoint = Object.fromEntries( |
| 33 | + Object.entries(importsFromEntryPoint).filter( |
| 34 | + ([key, value]) => key.endsWith('Error') && value.toString().startsWith('class') |
| 35 | + ) |
| 36 | + ) as any; |
| 37 | + errorClassesFromEntryPoint = { |
| 38 | + ...errorClassesFromEntryPoint, |
| 39 | + MongoPoolClosedError, |
| 40 | + MongoWaitQueueTimeoutError |
| 41 | + }; |
| 42 | + |
| 43 | + const errorClassesFromErrorSrc = Object.fromEntries( |
| 44 | + Object.entries(importsFromErrorSrc).filter( |
| 45 | + ([key, value]) => key.endsWith('Error') && value.toString().startsWith('class') |
| 46 | + ) |
33 | 47 | );
|
34 |
| - errorClasses = { ...errorClasses, MongoPoolClosedError, MongoWaitQueueTimeoutError }; |
35 | 48 |
|
36 |
| - for (const errorName in errorClasses) { |
37 |
| - describe(errorName, () => { |
38 |
| - it(`name should be read-only`, () => { |
| 49 | + it('all defined errors should be public', () => { |
| 50 | + expect( |
| 51 | + setDifference(Object.keys(errorClassesFromEntryPoint), Object.keys(errorClassesFromErrorSrc)) |
| 52 | + ).to.have.property('size', 3); |
| 53 | + |
| 54 | + expect( |
| 55 | + setDifference(Object.keys(errorClassesFromErrorSrc), Object.keys(errorClassesFromEntryPoint)) |
| 56 | + ).to.have.property('size', 0); |
| 57 | + }); |
| 58 | + |
| 59 | + describe('error names should be read-only', () => { |
| 60 | + for (const [errorName, errorClass] of Object.entries(errorClassesFromEntryPoint)) { |
| 61 | + it(`${errorName} should be read-only`, () => { |
39 | 62 | // Dynamically create error class with message
|
40 |
| - let error = new errorClasses[errorName]('generated by test'); |
| 63 | + const error = new (errorClass as any)('generated by test', {}); |
41 | 64 | // expect name property to be class name
|
42 | 65 | expect(error).to.have.property('name', errorName);
|
43 | 66 |
|
44 | 67 | try {
|
45 | 68 | error.name = 'renamed by test';
|
| 69 | + // eslint-disable-next-line no-empty |
46 | 70 | } catch (err) {}
|
47 | 71 | expect(error).to.have.property('name', errorName);
|
48 | 72 | });
|
49 |
| - }); |
50 |
| - } |
| 73 | + } |
| 74 | + }); |
51 | 75 |
|
52 | 76 | describe('MongoError#constructor', () => {
|
53 | 77 | it('should accept a string', function () {
|
@@ -89,6 +113,39 @@ describe('MongoErrors', () => {
|
89 | 113 | });
|
90 | 114 | });
|
91 | 115 |
|
| 116 | + describe('MongoSystemError#constructor', () => { |
| 117 | + context('when the topology description contains an error code', () => { |
| 118 | + it('contains the specified code as a top level property', () => { |
| 119 | + const topologyDescription = { |
| 120 | + error: { |
| 121 | + code: 123 |
| 122 | + } |
| 123 | + } as TopologyDescription; |
| 124 | + |
| 125 | + const error = new MongoSystemError('something went wrong', topologyDescription); |
| 126 | + expect(error).to.haveOwnProperty('code', 123); |
| 127 | + }); |
| 128 | + }); |
| 129 | + |
| 130 | + context('when the topology description does not contain an error code', () => { |
| 131 | + it('contains the code as a top level property that is undefined', () => { |
| 132 | + const topologyDescription = { error: {} } as TopologyDescription; |
| 133 | + |
| 134 | + const error = new MongoSystemError('something went wrong', topologyDescription); |
| 135 | + expect(error).to.haveOwnProperty('code', undefined); |
| 136 | + }); |
| 137 | + }); |
| 138 | + |
| 139 | + context('when the topology description does not contain an error property', () => { |
| 140 | + it('contains the code as a top level property that is undefined', () => { |
| 141 | + const topologyDescription = {} as TopologyDescription; |
| 142 | + |
| 143 | + const error = new MongoSystemError('something went wrong', topologyDescription); |
| 144 | + expect(error).to.haveOwnProperty('code', undefined); |
| 145 | + }); |
| 146 | + }); |
| 147 | + }); |
| 148 | + |
92 | 149 | describe('#isRetryableEndTransactionError', function () {
|
93 | 150 | context('when the error has a RetryableWriteError label', function () {
|
94 | 151 | const error = new MongoNetworkError('');
|
@@ -202,7 +259,10 @@ describe('MongoErrors', () => {
|
202 | 259 | const errorWithOptionFalse = new MongoNetworkError('', { beforeHandshake: false });
|
203 | 260 | expect(getSymbolFrom(errorWithOptionFalse, 'beforeHandshake', false)).to.be.a('symbol');
|
204 | 261 |
|
205 |
| - const errorWithBadOption = new MongoNetworkError('', { beforeHandshake: 'not boolean' }); |
| 262 | + const errorWithBadOption = new MongoNetworkError('', { |
| 263 | + // @ts-expect-error: beforeHandshake must be a boolean value |
| 264 | + beforeHandshake: 'not boolean' |
| 265 | + }); |
206 | 266 | expect(getSymbolFrom(errorWithBadOption, 'beforeHandshake', false)).to.be.an('undefined');
|
207 | 267 |
|
208 | 268 | const errorWithoutOption = new MongoNetworkError('');
|
@@ -254,14 +314,14 @@ describe('MongoErrors', () => {
|
254 | 314 | };
|
255 | 315 |
|
256 | 316 | before(() => (test = new ReplSetFixture()));
|
257 |
| - afterEach(() => mock.cleanup()); |
| 317 | + afterEach(() => cleanup()); |
258 | 318 | beforeEach(() => test.setup());
|
259 | 319 |
|
260 | 320 | function makeAndConnectReplSet(cb) {
|
261 | 321 | let invoked = false;
|
262 | 322 | const replSet = new Topology(
|
263 | 323 | [test.primaryServer.hostAddress(), test.firstSecondaryServer.hostAddress()],
|
264 |
| - { replicaSet: 'rs' } |
| 324 | + { replicaSet: 'rs' } as TopologyOptions |
265 | 325 | );
|
266 | 326 |
|
267 | 327 | replSet.once('error', err => {
|
|
0 commit comments