@qp-mongosh/service-provider-core 0.0.0-dev.5 → 0.0.0-dev.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/.eslintignore +2 -2
  2. package/.eslintrc.js +1 -1
  3. package/AUTHORS +11 -11
  4. package/LICENSE +200 -200
  5. package/lib/admin.d.ts +28 -28
  6. package/lib/admin.js +2 -2
  7. package/lib/all-fle-types.d.ts +2 -2
  8. package/lib/all-fle-types.js +2 -2
  9. package/lib/all-transport-types.d.ts +1 -1
  10. package/lib/all-transport-types.js +2 -2
  11. package/lib/cli-options.d.ts +43 -43
  12. package/lib/cli-options.js +2 -2
  13. package/lib/closable.d.ts +4 -4
  14. package/lib/closable.js +2 -2
  15. package/lib/connect-info.d.ts +19 -19
  16. package/lib/connect-info.js +34 -34
  17. package/lib/index.d.ts +31 -31
  18. package/lib/index.js +55 -55
  19. package/lib/platform.d.ts +6 -6
  20. package/lib/platform.js +10 -10
  21. package/lib/printable-bson.d.ts +3 -3
  22. package/lib/printable-bson.js +81 -81
  23. package/lib/readable.d.ts +18 -18
  24. package/lib/readable.js +2 -2
  25. package/lib/service-provider.d.ts +11 -11
  26. package/lib/service-provider.js +18 -18
  27. package/lib/shell-auth-options.d.ts +7 -7
  28. package/lib/shell-auth-options.js +2 -2
  29. package/lib/textencoder-polyfill.d.ts +2 -2
  30. package/lib/textencoder-polyfill.js +21 -21
  31. package/lib/uri-generator.d.ts +8 -8
  32. package/lib/uri-generator.js +175 -175
  33. package/lib/writable.d.ts +22 -22
  34. package/lib/writable.js +2 -2
  35. package/package.json +54 -54
  36. package/src/admin.ts +119 -119
  37. package/src/all-fle-types.ts +17 -17
  38. package/src/all-transport-types.ts +80 -80
  39. package/src/cli-options.ts +49 -49
  40. package/src/closable.ts +14 -14
  41. package/src/connect-info.spec.ts +192 -192
  42. package/src/connect-info.ts +57 -57
  43. package/src/index.ts +62 -62
  44. package/src/platform.ts +6 -6
  45. package/src/printable-bson.spec.ts +75 -75
  46. package/src/printable-bson.ts +103 -103
  47. package/src/readable.ts +242 -242
  48. package/src/service-provider.ts +23 -23
  49. package/src/shell-auth-options.ts +7 -7
  50. package/src/textencoder-polyfill.spec.ts +11 -11
  51. package/src/textencoder-polyfill.ts +30 -30
  52. package/src/uri-generator.spec.ts +481 -481
  53. package/src/uri-generator.ts +265 -265
  54. package/src/writable.ts +367 -367
  55. package/tsconfig.json +12 -12
  56. package/tsconfig.lint.json +8 -8
@@ -1,481 +1,481 @@
1
- import { CommonErrors, MongoshInvalidInputError } from '@qp-mongosh/errors';
2
- import { expect } from 'chai';
3
- import CliOptions from './cli-options';
4
- import generateUri from './uri-generator';
5
-
6
- describe('uri-generator.generate-uri', () => {
7
- context('when no arguments are provided', () => {
8
- const options = { connectionSpecifier: undefined };
9
-
10
- it('returns the default uri', () => {
11
- expect(generateUri(options)).to.equal('mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000');
12
- });
13
- });
14
-
15
- context('when no URI is provided', () => {
16
- it('handles host', () => {
17
- expect(generateUri({ connectionSpecifier: undefined, host: 'localhost' })).to.equal('mongodb://localhost:27017/?directConnection=true&serverSelectionTimeoutMS=2000');
18
- });
19
- it('handles port', () => {
20
- expect(generateUri({ connectionSpecifier: undefined, port: '27018' })).to.equal('mongodb://127.0.0.1:27018/?directConnection=true&serverSelectionTimeoutMS=2000');
21
- });
22
- it('handles both host and port', () => {
23
- expect(generateUri({ connectionSpecifier: undefined, host: 'localhost', port: '27018' })).to.equal('mongodb://localhost:27018/?directConnection=true&serverSelectionTimeoutMS=2000');
24
- });
25
- it('handles host with port included', () => {
26
- expect(generateUri({ connectionSpecifier: undefined, host: 'localhost:27018' })).to.equal('mongodb://localhost:27018/?directConnection=true&serverSelectionTimeoutMS=2000');
27
- });
28
- it('handles host with an underscore', () => {
29
- expect(generateUri({ connectionSpecifier: undefined, host: 'some_host' })).to.equal('mongodb://some_host:27017/?directConnection=true');
30
- });
31
- it('throws if host has port AND port set to other value', () => {
32
- try {
33
- generateUri({ connectionSpecifier: undefined, host: 'localhost:27018', port: '27019' });
34
- expect.fail('expected error');
35
- } catch (e: any) {
36
- expect(e).to.be.instanceOf(MongoshInvalidInputError);
37
- expect(e.code).to.equal(CommonErrors.InvalidArgument);
38
- }
39
- });
40
- it('handles host has port AND port set to equal value', () => {
41
- expect(generateUri({ connectionSpecifier: undefined, host: 'localhost:27018', port: '27018' })).to.equal('mongodb://localhost:27018/?directConnection=true&serverSelectionTimeoutMS=2000');
42
- });
43
- });
44
-
45
- context('when a full URI is provided', () => {
46
- context('when no additional options are provided', () => {
47
- const options = { connectionSpecifier: 'mongodb://192.0.0.1:27018/foo' };
48
-
49
- it('returns the uri', () => {
50
- expect(generateUri(options)).to.equal('mongodb://192.0.0.1:27018/foo?directConnection=true');
51
- });
52
- });
53
-
54
- context('when additional options are provided', () => {
55
- context('when providing host with URI', () => {
56
- const uri = 'mongodb://192.0.0.1:27018/foo';
57
- const options = { connectionSpecifier: uri, host: '127.0.0.1' };
58
-
59
- it('throws an exception', () => {
60
- try {
61
- generateUri(options);
62
- expect.fail('expected error');
63
- } catch (e: any) {
64
- expect(e).to.be.instanceOf(MongoshInvalidInputError);
65
- expect(e.code).to.equal(CommonErrors.InvalidArgument);
66
- }
67
- });
68
- });
69
-
70
- context('when providing port with URI', () => {
71
- const uri = 'mongodb://192.0.0.1:27018/foo';
72
- const options = { connectionSpecifier: uri, port: '27018' };
73
-
74
- it('throws an exception', () => {
75
- try {
76
- generateUri(options);
77
- expect.fail('expected error');
78
- } catch (e: any) {
79
- expect(e.name).to.equal('MongoshInvalidInputError');
80
- expect(e.code).to.equal(CommonErrors.InvalidArgument);
81
- }
82
- });
83
- });
84
-
85
- context('when providing gssapiServiceName', () => {
86
- context('and the URI does not include SERVICE_NAME in authMechanismProperties', () => {
87
- const uri = 'mongodb+srv://some.host/foo';
88
- const options: CliOptions = { connectionSpecifier: uri, gssapiServiceName: 'alternate' };
89
-
90
- it('does not throw an error', () => {
91
- expect(generateUri(options)).to.equal('mongodb+srv://some.host/foo');
92
- });
93
- });
94
-
95
- context('and the URI includes SERVICE_NAME in authMechanismProperties', () => {
96
- const uri = 'mongodb+srv://some.host/foo?authMechanismProperties=SERVICE_NAME:whatever';
97
- const options: CliOptions = { connectionSpecifier: uri, gssapiServiceName: 'alternate' };
98
-
99
- it('throws an error', () => {
100
- try {
101
- generateUri(options);
102
- } catch (e: any) {
103
- expect(e.name).to.equal('MongoshInvalidInputError');
104
- expect(e.code).to.equal(CommonErrors.InvalidArgument);
105
- expect(e.message).to.contain('--gssapiServiceName parameter or the SERVICE_NAME');
106
- return;
107
- }
108
- expect.fail('expected error');
109
- });
110
- });
111
- });
112
- });
113
-
114
- context('when providing a URI with query parameters', () => {
115
- context('that do not conflict with directConnection', () => {
116
- const uri = 'mongodb://192.0.0.1:27018?readPreference=primary';
117
- const options = { connectionSpecifier: uri };
118
- it('still includes directConnection', () => {
119
- expect(generateUri(options)).to.equal('mongodb://192.0.0.1:27018/?readPreference=primary&directConnection=true');
120
- });
121
- });
122
-
123
- context('including replicaSet', () => {
124
- const uri = 'mongodb://192.0.0.1:27018/db?replicaSet=replicaset';
125
- const options = { connectionSpecifier: uri };
126
- it('does not add the directConnection parameter', () => {
127
- expect(generateUri(options)).to.equal(uri);
128
- });
129
- });
130
-
131
- context('including loadBalanced', () => {
132
- const uri = 'mongodb://192.0.0.1:27018/db?loadBalanced=true';
133
- const options = { connectionSpecifier: uri };
134
- it('does not add the directConnection parameter', () => {
135
- expect(generateUri(options)).to.equal(uri);
136
- });
137
- });
138
-
139
- context('including explicit directConnection', () => {
140
- const uri = 'mongodb://192.0.0.1:27018/db?directConnection=false';
141
- const options = { connectionSpecifier: uri };
142
- it('does not change the directConnection parameter', () => {
143
- expect(generateUri(options)).to.equal(uri);
144
- });
145
- });
146
- });
147
-
148
- context('when providing a URI with SRV record', () => {
149
- const uri = 'mongodb+srv://somehost/?readPreference=primary';
150
- const options = { connectionSpecifier: uri };
151
- it('no directConnection is added', () => {
152
- expect(generateUri(options)).to.equal(uri);
153
- });
154
- });
155
-
156
- context('when providing a URI with multiple seeds', () => {
157
- const uri = 'mongodb://192.42.42.42:27017,192.0.0.1:27018/db?readPreference=primary';
158
- const options = { connectionSpecifier: uri };
159
- it('no directConnection is added', () => {
160
- expect(generateUri(options)).to.equal(uri);
161
- });
162
- });
163
-
164
- context('when providing a URI with the legacy gssapiServiceName query parameter', () => {
165
- const uri = 'mongodb://192.42.42.42:27017,192.0.0.1:27018/db?gssapiServiceName=primary';
166
- const options = { connectionSpecifier: uri };
167
-
168
- it('throws an error', () => {
169
- try {
170
- generateUri(options);
171
- } catch (e: any) {
172
- expect(e.name).to.equal('MongoshInvalidInputError');
173
- expect(e.code).to.equal(CommonErrors.InvalidArgument);
174
- expect(e.message).to.contain('gssapiServiceName query parameter is not supported');
175
- return;
176
- }
177
- expect.fail('expected error');
178
- });
179
- });
180
- });
181
-
182
- context('when a URI is provided without a scheme', () => {
183
- context('when providing host', () => {
184
- const uri = '192.0.0.1';
185
- const options = { connectionSpecifier: uri };
186
-
187
- it('returns the uri with the scheme', () => {
188
- expect(generateUri(options)).to.equal(`mongodb://${uri}:27017/test?directConnection=true`);
189
- });
190
- });
191
-
192
- context('when providing host:port', () => {
193
- const uri = '192.0.0.1:27018';
194
- const options = { connectionSpecifier: uri };
195
-
196
- it('returns the uri with the scheme', () => {
197
- expect(generateUri(options)).to.equal(`mongodb://${uri}/test?directConnection=true`);
198
- });
199
- });
200
-
201
- context('when proving host + port option', () => {
202
- const uri = '192.0.0.1';
203
- const options = { connectionSpecifier: uri, port: '27018' };
204
-
205
- it('throws an exception', () => {
206
- try {
207
- generateUri(options);
208
- expect.fail('expected error');
209
- } catch (e: any) {
210
- expect(e).to.be.instanceOf(MongoshInvalidInputError);
211
- expect(e.code).to.equal(CommonErrors.InvalidArgument);
212
- }
213
- });
214
- });
215
-
216
- context('when no additional options are provided without db', () => {
217
- const uri = '192.0.0.1:27018';
218
- const options = { connectionSpecifier: uri };
219
-
220
- it('returns the uri with the scheme', () => {
221
- expect(generateUri(options)).to.equal(`mongodb://${uri}/test?directConnection=true`);
222
- });
223
- });
224
-
225
- context('when no additional options are provided with empty db', () => {
226
- const uri = '192.0.0.1:27018/';
227
- const options = { connectionSpecifier: uri };
228
-
229
- it('returns the uri with the scheme', () => {
230
- expect(generateUri(options)).to.equal(`mongodb://${uri}test?directConnection=true`);
231
- });
232
- });
233
-
234
- context('when no additional options are provided with db', () => {
235
- const uri = '192.0.0.1:27018/foo';
236
- const options = { connectionSpecifier: uri };
237
-
238
- it('returns the uri with the scheme', () => {
239
- expect(generateUri(options)).to.equal(`mongodb://${uri}?directConnection=true`);
240
- });
241
- });
242
-
243
- context('when no additional options are provided with db with special characters', () => {
244
- const uri = '192.0.0.1:27018/föö-:?%ab💙,\'_.c';
245
- const options = { connectionSpecifier: uri };
246
-
247
- it('returns the uri with the scheme', () => {
248
- expect(generateUri(options)).to.equal('mongodb://192.0.0.1:27018/f%C3%B6%C3%B6-%3A%3F%25ab%F0%9F%92%99%2C\'_.c?directConnection=true');
249
- });
250
- });
251
-
252
- context('when the db part does not start with a slash', () => {
253
- const uri = '192.0.0.1:27018?foo=bar';
254
- const options = { connectionSpecifier: uri };
255
-
256
- it('throws an exception', () => {
257
- try {
258
- generateUri(options);
259
- expect.fail('expected error');
260
- } catch (e: any) {
261
- expect(e).to.be.instanceOf(MongoshInvalidInputError);
262
- expect(e.code).to.equal(CommonErrors.InvalidArgument);
263
- }
264
- });
265
- });
266
-
267
- context('when additional options are provided', () => {
268
- context('when providing host with URI', () => {
269
- const uri = '192.0.0.1:27018/foo';
270
- const options = { connectionSpecifier: uri, host: '127.0.0.1' };
271
-
272
- it('throws an exception', () => {
273
- try {
274
- generateUri(options);
275
- expect.fail('expected error');
276
- } catch (e: any) {
277
- expect(e).to.be.instanceOf(MongoshInvalidInputError);
278
- expect(e.code).to.equal(CommonErrors.InvalidArgument);
279
- }
280
- });
281
- });
282
-
283
- context('when providing host with db', () => {
284
- const uri = 'foo';
285
- const options = { connectionSpecifier: uri, host: '127.0.0.2' };
286
-
287
- it('uses the provided host with default port', () => {
288
- expect(generateUri(options)).to.equal('mongodb://127.0.0.2:27017/foo?directConnection=true');
289
- });
290
- });
291
-
292
- context('when providing port with URI', () => {
293
- const uri = '192.0.0.1:27018/foo';
294
- const options = { connectionSpecifier: uri, port: '27018' };
295
-
296
- it('throws an exception', () => {
297
- try {
298
- generateUri(options);
299
- expect.fail('expected error');
300
- } catch (e: any) {
301
- expect(e).to.be.instanceOf(MongoshInvalidInputError);
302
- expect(e.code).to.equal(CommonErrors.InvalidArgument);
303
- }
304
- });
305
- });
306
-
307
- context('when providing port with db', () => {
308
- const uri = 'foo';
309
- const options = { connectionSpecifier: uri, port: '27018' };
310
-
311
- it('uses the provided host with default port', () => {
312
- expect(generateUri(options)).to.equal('mongodb://127.0.0.1:27018/foo?directConnection=true&serverSelectionTimeoutMS=2000');
313
- });
314
- });
315
-
316
- context('when providing port with only a host URI', () => {
317
- const uri = '127.0.0.2/foo';
318
- const options = { connectionSpecifier: uri, port: '27018' };
319
-
320
- it('throws an exception', () => {
321
- try {
322
- generateUri(options);
323
- expect.fail('expected error');
324
- } catch (e: any) {
325
- expect(e).to.be.instanceOf(MongoshInvalidInputError);
326
- expect(e.code).to.equal(CommonErrors.InvalidArgument);
327
- }
328
- });
329
- });
330
-
331
- context('when providing nodb', () => {
332
- const uri = 'mongodb://127.0.0.2/foo';
333
- const options = { connectionSpecifier: uri, nodb: true };
334
-
335
- it('returns an empty string', () => {
336
- expect(generateUri(options)).to.equal('');
337
- });
338
- });
339
-
340
- context('when providing explicit serverSelectionTimeoutMS', () => {
341
- const uri = 'mongodb://127.0.0.2/foo?serverSelectionTimeoutMS=10';
342
- const options = { connectionSpecifier: uri };
343
-
344
- it('does not override the existing value', () => {
345
- expect(generateUri(options)).to.equal('mongodb://127.0.0.2/foo?serverSelectionTimeoutMS=10&directConnection=true');
346
- });
347
- });
348
-
349
- context('when providing explicit serverSelectionTimeoutMS (different case)', () => {
350
- const uri = 'mongodb://127.0.0.2/foo?SERVERSELECTIONTIMEOUTMS=10';
351
- const options = { connectionSpecifier: uri };
352
-
353
- it('does not override the existing value', () => {
354
- expect(generateUri(options)).to.equal('mongodb://127.0.0.2/foo?SERVERSELECTIONTIMEOUTMS=10&directConnection=true');
355
- });
356
- });
357
- });
358
-
359
- context('when providing a URI with query parameters', () => {
360
- context('that do not conflict with directConnection', () => {
361
- const uri = 'mongodb://192.0.0.1:27018/?readPreference=primary';
362
- const options = { connectionSpecifier: uri };
363
- it('still includes directConnection', () => {
364
- expect(generateUri(options)).to.equal('mongodb://192.0.0.1:27018/?readPreference=primary&directConnection=true');
365
- });
366
- });
367
-
368
- context('including replicaSet', () => {
369
- const uri = 'mongodb://192.0.0.1:27018/db?replicaSet=replicaset';
370
- const options = { connectionSpecifier: uri };
371
- it('does not add the directConnection parameter', () => {
372
- expect(generateUri(options)).to.equal(uri);
373
- });
374
- });
375
-
376
- context('including explicit directConnection', () => {
377
- const uri = 'mongodb://192.0.0.1:27018/?directConnection=false';
378
- const options = { connectionSpecifier: uri };
379
- it('does not change the directConnection parameter', () => {
380
- expect(generateUri(options)).to.equal('mongodb://192.0.0.1:27018/?directConnection=false');
381
- });
382
- });
383
- });
384
- });
385
-
386
-
387
- context('when an invalid URI is provided', () => {
388
- const uri = '/x';
389
- const options = { connectionSpecifier: uri };
390
-
391
- it('returns the uri', () => {
392
- try {
393
- generateUri(options);
394
- } catch (e: any) {
395
- expect(e.message).to.contain('Invalid URI: /x');
396
- expect(e).to.be.instanceOf(MongoshInvalidInputError);
397
- expect(e.code).to.equal(CommonErrors.InvalidArgument);
398
- return;
399
- }
400
- expect.fail('expected error');
401
- });
402
- });
403
-
404
- context('when the --host option contains invalid characters', () => {
405
- const options = { host: 'a$b,c' };
406
-
407
- it('returns the uri', () => {
408
- try {
409
- generateUri(options);
410
- } catch (e: any) {
411
- expect(e.message).to.contain('The --host argument contains an invalid character: $');
412
- expect(e).to.be.instanceOf(MongoshInvalidInputError);
413
- expect(e.code).to.equal(CommonErrors.InvalidArgument);
414
- return;
415
- }
416
- expect.fail('expected error');
417
- });
418
- });
419
-
420
- context('when the --host option contains a seed list', () => {
421
- context('without a replica set', () => {
422
- it('returns a URI for the hosts and ports specified in --host', () => {
423
- const options = { host: 'host1:123,host2,host3:456,' };
424
- expect(generateUri(options)).to.equal('mongodb://host1:123,host2,host3:456/');
425
- });
426
-
427
- it('returns a URI for the hosts and ports specified in --host and database name', () => {
428
- const options = {
429
- host: 'host1:123,host_2,host3:456,',
430
- connectionSpecifier: 'admin'
431
- };
432
- expect(generateUri(options)).to.equal('mongodb://host1:123,host_2,host3:456/admin');
433
- });
434
-
435
- it('returns a URI for the hosts in --host and fixed --port', () => {
436
- const options = {
437
- host: 'host1:1234,host_2',
438
- port: '1234',
439
- connectionSpecifier: 'admin'
440
- };
441
- expect(generateUri(options)).to.equal('mongodb://host1:1234,host_2:1234/admin');
442
- });
443
-
444
- it('throws an error if seed list in --host contains port mismatches from fixed --port', () => {
445
- const options = {
446
- host: 'host1,host_2:123',
447
- port: '1234',
448
- connectionSpecifier: 'admin'
449
- };
450
- expect(() => generateUri(options)).to.throw('The host list contains different ports than provided by --port');
451
- });
452
- });
453
-
454
- context('with a replica set', () => {
455
- it('returns a URI for the hosts and ports specified in --host', () => {
456
- const options = { host: 'replsetname/host1:123,host2,host3:456,' };
457
- expect(generateUri(options)).to.equal('mongodb://host1:123,host2,host3:456/?replicaSet=replsetname');
458
- });
459
-
460
- it('returns a URI for the hosts and ports specified in --host and database name', () => {
461
- const options = { host: 'replsetname/host1:123,host2,host3:456', connectionSpecifier: 'admin' };
462
- expect(generateUri(options)).to.equal('mongodb://host1:123,host2,host3:456/admin?replicaSet=replsetname');
463
- });
464
-
465
- it('returns a URI for the hosts and ports specified in --host and database name with escaped chars', () => {
466
- const options = { host: 'replsetname/host1:123,host2,host3:456', connectionSpecifier: 'admin?foo=bar' };
467
- expect(generateUri(options)).to.equal('mongodb://host1:123,host2,host3:456/admin%3Ffoo%3Dbar?replicaSet=replsetname');
468
- });
469
-
470
- it('returns a URI for the hosts specified in --host and explicit --port', () => {
471
- const options = { host: 'replsetname/host1:123,host2,', port: '123' };
472
- expect(generateUri(options)).to.equal('mongodb://host1:123,host2:123/?replicaSet=replsetname');
473
- });
474
-
475
- it('throws an error if the hosts contain ports that mismatch from --port', () => {
476
- const options = { host: 'replsetname/host1:1234,host2,', port: '123' };
477
- expect(() => generateUri(options)).to.throw('The host list contains different ports than provided by --port');
478
- });
479
- });
480
- });
481
- });
1
+ import { CommonErrors, MongoshInvalidInputError } from '@qp-mongosh/errors';
2
+ import { expect } from 'chai';
3
+ import CliOptions from './cli-options';
4
+ import generateUri from './uri-generator';
5
+
6
+ describe('uri-generator.generate-uri', () => {
7
+ context('when no arguments are provided', () => {
8
+ const options = { connectionSpecifier: undefined };
9
+
10
+ it('returns the default uri', () => {
11
+ expect(generateUri(options)).to.equal('mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000');
12
+ });
13
+ });
14
+
15
+ context('when no URI is provided', () => {
16
+ it('handles host', () => {
17
+ expect(generateUri({ connectionSpecifier: undefined, host: 'localhost' })).to.equal('mongodb://localhost:27017/?directConnection=true&serverSelectionTimeoutMS=2000');
18
+ });
19
+ it('handles port', () => {
20
+ expect(generateUri({ connectionSpecifier: undefined, port: '27018' })).to.equal('mongodb://127.0.0.1:27018/?directConnection=true&serverSelectionTimeoutMS=2000');
21
+ });
22
+ it('handles both host and port', () => {
23
+ expect(generateUri({ connectionSpecifier: undefined, host: 'localhost', port: '27018' })).to.equal('mongodb://localhost:27018/?directConnection=true&serverSelectionTimeoutMS=2000');
24
+ });
25
+ it('handles host with port included', () => {
26
+ expect(generateUri({ connectionSpecifier: undefined, host: 'localhost:27018' })).to.equal('mongodb://localhost:27018/?directConnection=true&serverSelectionTimeoutMS=2000');
27
+ });
28
+ it('handles host with an underscore', () => {
29
+ expect(generateUri({ connectionSpecifier: undefined, host: 'some_host' })).to.equal('mongodb://some_host:27017/?directConnection=true');
30
+ });
31
+ it('throws if host has port AND port set to other value', () => {
32
+ try {
33
+ generateUri({ connectionSpecifier: undefined, host: 'localhost:27018', port: '27019' });
34
+ expect.fail('expected error');
35
+ } catch (e: any) {
36
+ expect(e).to.be.instanceOf(MongoshInvalidInputError);
37
+ expect(e.code).to.equal(CommonErrors.InvalidArgument);
38
+ }
39
+ });
40
+ it('handles host has port AND port set to equal value', () => {
41
+ expect(generateUri({ connectionSpecifier: undefined, host: 'localhost:27018', port: '27018' })).to.equal('mongodb://localhost:27018/?directConnection=true&serverSelectionTimeoutMS=2000');
42
+ });
43
+ });
44
+
45
+ context('when a full URI is provided', () => {
46
+ context('when no additional options are provided', () => {
47
+ const options = { connectionSpecifier: 'mongodb://192.0.0.1:27018/foo' };
48
+
49
+ it('returns the uri', () => {
50
+ expect(generateUri(options)).to.equal('mongodb://192.0.0.1:27018/foo?directConnection=true');
51
+ });
52
+ });
53
+
54
+ context('when additional options are provided', () => {
55
+ context('when providing host with URI', () => {
56
+ const uri = 'mongodb://192.0.0.1:27018/foo';
57
+ const options = { connectionSpecifier: uri, host: '127.0.0.1' };
58
+
59
+ it('throws an exception', () => {
60
+ try {
61
+ generateUri(options);
62
+ expect.fail('expected error');
63
+ } catch (e: any) {
64
+ expect(e).to.be.instanceOf(MongoshInvalidInputError);
65
+ expect(e.code).to.equal(CommonErrors.InvalidArgument);
66
+ }
67
+ });
68
+ });
69
+
70
+ context('when providing port with URI', () => {
71
+ const uri = 'mongodb://192.0.0.1:27018/foo';
72
+ const options = { connectionSpecifier: uri, port: '27018' };
73
+
74
+ it('throws an exception', () => {
75
+ try {
76
+ generateUri(options);
77
+ expect.fail('expected error');
78
+ } catch (e: any) {
79
+ expect(e.name).to.equal('MongoshInvalidInputError');
80
+ expect(e.code).to.equal(CommonErrors.InvalidArgument);
81
+ }
82
+ });
83
+ });
84
+
85
+ context('when providing gssapiServiceName', () => {
86
+ context('and the URI does not include SERVICE_NAME in authMechanismProperties', () => {
87
+ const uri = 'mongodb+srv://some.host/foo';
88
+ const options: CliOptions = { connectionSpecifier: uri, gssapiServiceName: 'alternate' };
89
+
90
+ it('does not throw an error', () => {
91
+ expect(generateUri(options)).to.equal('mongodb+srv://some.host/foo');
92
+ });
93
+ });
94
+
95
+ context('and the URI includes SERVICE_NAME in authMechanismProperties', () => {
96
+ const uri = 'mongodb+srv://some.host/foo?authMechanismProperties=SERVICE_NAME:whatever';
97
+ const options: CliOptions = { connectionSpecifier: uri, gssapiServiceName: 'alternate' };
98
+
99
+ it('throws an error', () => {
100
+ try {
101
+ generateUri(options);
102
+ } catch (e: any) {
103
+ expect(e.name).to.equal('MongoshInvalidInputError');
104
+ expect(e.code).to.equal(CommonErrors.InvalidArgument);
105
+ expect(e.message).to.contain('--gssapiServiceName parameter or the SERVICE_NAME');
106
+ return;
107
+ }
108
+ expect.fail('expected error');
109
+ });
110
+ });
111
+ });
112
+ });
113
+
114
+ context('when providing a URI with query parameters', () => {
115
+ context('that do not conflict with directConnection', () => {
116
+ const uri = 'mongodb://192.0.0.1:27018?readPreference=primary';
117
+ const options = { connectionSpecifier: uri };
118
+ it('still includes directConnection', () => {
119
+ expect(generateUri(options)).to.equal('mongodb://192.0.0.1:27018/?readPreference=primary&directConnection=true');
120
+ });
121
+ });
122
+
123
+ context('including replicaSet', () => {
124
+ const uri = 'mongodb://192.0.0.1:27018/db?replicaSet=replicaset';
125
+ const options = { connectionSpecifier: uri };
126
+ it('does not add the directConnection parameter', () => {
127
+ expect(generateUri(options)).to.equal(uri);
128
+ });
129
+ });
130
+
131
+ context('including loadBalanced', () => {
132
+ const uri = 'mongodb://192.0.0.1:27018/db?loadBalanced=true';
133
+ const options = { connectionSpecifier: uri };
134
+ it('does not add the directConnection parameter', () => {
135
+ expect(generateUri(options)).to.equal(uri);
136
+ });
137
+ });
138
+
139
+ context('including explicit directConnection', () => {
140
+ const uri = 'mongodb://192.0.0.1:27018/db?directConnection=false';
141
+ const options = { connectionSpecifier: uri };
142
+ it('does not change the directConnection parameter', () => {
143
+ expect(generateUri(options)).to.equal(uri);
144
+ });
145
+ });
146
+ });
147
+
148
+ context('when providing a URI with SRV record', () => {
149
+ const uri = 'mongodb+srv://somehost/?readPreference=primary';
150
+ const options = { connectionSpecifier: uri };
151
+ it('no directConnection is added', () => {
152
+ expect(generateUri(options)).to.equal(uri);
153
+ });
154
+ });
155
+
156
+ context('when providing a URI with multiple seeds', () => {
157
+ const uri = 'mongodb://192.42.42.42:27017,192.0.0.1:27018/db?readPreference=primary';
158
+ const options = { connectionSpecifier: uri };
159
+ it('no directConnection is added', () => {
160
+ expect(generateUri(options)).to.equal(uri);
161
+ });
162
+ });
163
+
164
+ context('when providing a URI with the legacy gssapiServiceName query parameter', () => {
165
+ const uri = 'mongodb://192.42.42.42:27017,192.0.0.1:27018/db?gssapiServiceName=primary';
166
+ const options = { connectionSpecifier: uri };
167
+
168
+ it('throws an error', () => {
169
+ try {
170
+ generateUri(options);
171
+ } catch (e: any) {
172
+ expect(e.name).to.equal('MongoshInvalidInputError');
173
+ expect(e.code).to.equal(CommonErrors.InvalidArgument);
174
+ expect(e.message).to.contain('gssapiServiceName query parameter is not supported');
175
+ return;
176
+ }
177
+ expect.fail('expected error');
178
+ });
179
+ });
180
+ });
181
+
182
+ context('when a URI is provided without a scheme', () => {
183
+ context('when providing host', () => {
184
+ const uri = '192.0.0.1';
185
+ const options = { connectionSpecifier: uri };
186
+
187
+ it('returns the uri with the scheme', () => {
188
+ expect(generateUri(options)).to.equal(`mongodb://${uri}:27017/test?directConnection=true`);
189
+ });
190
+ });
191
+
192
+ context('when providing host:port', () => {
193
+ const uri = '192.0.0.1:27018';
194
+ const options = { connectionSpecifier: uri };
195
+
196
+ it('returns the uri with the scheme', () => {
197
+ expect(generateUri(options)).to.equal(`mongodb://${uri}/test?directConnection=true`);
198
+ });
199
+ });
200
+
201
+ context('when proving host + port option', () => {
202
+ const uri = '192.0.0.1';
203
+ const options = { connectionSpecifier: uri, port: '27018' };
204
+
205
+ it('throws an exception', () => {
206
+ try {
207
+ generateUri(options);
208
+ expect.fail('expected error');
209
+ } catch (e: any) {
210
+ expect(e).to.be.instanceOf(MongoshInvalidInputError);
211
+ expect(e.code).to.equal(CommonErrors.InvalidArgument);
212
+ }
213
+ });
214
+ });
215
+
216
+ context('when no additional options are provided without db', () => {
217
+ const uri = '192.0.0.1:27018';
218
+ const options = { connectionSpecifier: uri };
219
+
220
+ it('returns the uri with the scheme', () => {
221
+ expect(generateUri(options)).to.equal(`mongodb://${uri}/test?directConnection=true`);
222
+ });
223
+ });
224
+
225
+ context('when no additional options are provided with empty db', () => {
226
+ const uri = '192.0.0.1:27018/';
227
+ const options = { connectionSpecifier: uri };
228
+
229
+ it('returns the uri with the scheme', () => {
230
+ expect(generateUri(options)).to.equal(`mongodb://${uri}test?directConnection=true`);
231
+ });
232
+ });
233
+
234
+ context('when no additional options are provided with db', () => {
235
+ const uri = '192.0.0.1:27018/foo';
236
+ const options = { connectionSpecifier: uri };
237
+
238
+ it('returns the uri with the scheme', () => {
239
+ expect(generateUri(options)).to.equal(`mongodb://${uri}?directConnection=true`);
240
+ });
241
+ });
242
+
243
+ context('when no additional options are provided with db with special characters', () => {
244
+ const uri = '192.0.0.1:27018/föö-:?%ab💙,\'_.c';
245
+ const options = { connectionSpecifier: uri };
246
+
247
+ it('returns the uri with the scheme', () => {
248
+ expect(generateUri(options)).to.equal('mongodb://192.0.0.1:27018/f%C3%B6%C3%B6-%3A%3F%25ab%F0%9F%92%99%2C\'_.c?directConnection=true');
249
+ });
250
+ });
251
+
252
+ context('when the db part does not start with a slash', () => {
253
+ const uri = '192.0.0.1:27018?foo=bar';
254
+ const options = { connectionSpecifier: uri };
255
+
256
+ it('throws an exception', () => {
257
+ try {
258
+ generateUri(options);
259
+ expect.fail('expected error');
260
+ } catch (e: any) {
261
+ expect(e).to.be.instanceOf(MongoshInvalidInputError);
262
+ expect(e.code).to.equal(CommonErrors.InvalidArgument);
263
+ }
264
+ });
265
+ });
266
+
267
+ context('when additional options are provided', () => {
268
+ context('when providing host with URI', () => {
269
+ const uri = '192.0.0.1:27018/foo';
270
+ const options = { connectionSpecifier: uri, host: '127.0.0.1' };
271
+
272
+ it('throws an exception', () => {
273
+ try {
274
+ generateUri(options);
275
+ expect.fail('expected error');
276
+ } catch (e: any) {
277
+ expect(e).to.be.instanceOf(MongoshInvalidInputError);
278
+ expect(e.code).to.equal(CommonErrors.InvalidArgument);
279
+ }
280
+ });
281
+ });
282
+
283
+ context('when providing host with db', () => {
284
+ const uri = 'foo';
285
+ const options = { connectionSpecifier: uri, host: '127.0.0.2' };
286
+
287
+ it('uses the provided host with default port', () => {
288
+ expect(generateUri(options)).to.equal('mongodb://127.0.0.2:27017/foo?directConnection=true');
289
+ });
290
+ });
291
+
292
+ context('when providing port with URI', () => {
293
+ const uri = '192.0.0.1:27018/foo';
294
+ const options = { connectionSpecifier: uri, port: '27018' };
295
+
296
+ it('throws an exception', () => {
297
+ try {
298
+ generateUri(options);
299
+ expect.fail('expected error');
300
+ } catch (e: any) {
301
+ expect(e).to.be.instanceOf(MongoshInvalidInputError);
302
+ expect(e.code).to.equal(CommonErrors.InvalidArgument);
303
+ }
304
+ });
305
+ });
306
+
307
+ context('when providing port with db', () => {
308
+ const uri = 'foo';
309
+ const options = { connectionSpecifier: uri, port: '27018' };
310
+
311
+ it('uses the provided host with default port', () => {
312
+ expect(generateUri(options)).to.equal('mongodb://127.0.0.1:27018/foo?directConnection=true&serverSelectionTimeoutMS=2000');
313
+ });
314
+ });
315
+
316
+ context('when providing port with only a host URI', () => {
317
+ const uri = '127.0.0.2/foo';
318
+ const options = { connectionSpecifier: uri, port: '27018' };
319
+
320
+ it('throws an exception', () => {
321
+ try {
322
+ generateUri(options);
323
+ expect.fail('expected error');
324
+ } catch (e: any) {
325
+ expect(e).to.be.instanceOf(MongoshInvalidInputError);
326
+ expect(e.code).to.equal(CommonErrors.InvalidArgument);
327
+ }
328
+ });
329
+ });
330
+
331
+ context('when providing nodb', () => {
332
+ const uri = 'mongodb://127.0.0.2/foo';
333
+ const options = { connectionSpecifier: uri, nodb: true };
334
+
335
+ it('returns an empty string', () => {
336
+ expect(generateUri(options)).to.equal('');
337
+ });
338
+ });
339
+
340
+ context('when providing explicit serverSelectionTimeoutMS', () => {
341
+ const uri = 'mongodb://127.0.0.2/foo?serverSelectionTimeoutMS=10';
342
+ const options = { connectionSpecifier: uri };
343
+
344
+ it('does not override the existing value', () => {
345
+ expect(generateUri(options)).to.equal('mongodb://127.0.0.2/foo?serverSelectionTimeoutMS=10&directConnection=true');
346
+ });
347
+ });
348
+
349
+ context('when providing explicit serverSelectionTimeoutMS (different case)', () => {
350
+ const uri = 'mongodb://127.0.0.2/foo?SERVERSELECTIONTIMEOUTMS=10';
351
+ const options = { connectionSpecifier: uri };
352
+
353
+ it('does not override the existing value', () => {
354
+ expect(generateUri(options)).to.equal('mongodb://127.0.0.2/foo?SERVERSELECTIONTIMEOUTMS=10&directConnection=true');
355
+ });
356
+ });
357
+ });
358
+
359
+ context('when providing a URI with query parameters', () => {
360
+ context('that do not conflict with directConnection', () => {
361
+ const uri = 'mongodb://192.0.0.1:27018/?readPreference=primary';
362
+ const options = { connectionSpecifier: uri };
363
+ it('still includes directConnection', () => {
364
+ expect(generateUri(options)).to.equal('mongodb://192.0.0.1:27018/?readPreference=primary&directConnection=true');
365
+ });
366
+ });
367
+
368
+ context('including replicaSet', () => {
369
+ const uri = 'mongodb://192.0.0.1:27018/db?replicaSet=replicaset';
370
+ const options = { connectionSpecifier: uri };
371
+ it('does not add the directConnection parameter', () => {
372
+ expect(generateUri(options)).to.equal(uri);
373
+ });
374
+ });
375
+
376
+ context('including explicit directConnection', () => {
377
+ const uri = 'mongodb://192.0.0.1:27018/?directConnection=false';
378
+ const options = { connectionSpecifier: uri };
379
+ it('does not change the directConnection parameter', () => {
380
+ expect(generateUri(options)).to.equal('mongodb://192.0.0.1:27018/?directConnection=false');
381
+ });
382
+ });
383
+ });
384
+ });
385
+
386
+
387
+ context('when an invalid URI is provided', () => {
388
+ const uri = '/x';
389
+ const options = { connectionSpecifier: uri };
390
+
391
+ it('returns the uri', () => {
392
+ try {
393
+ generateUri(options);
394
+ } catch (e: any) {
395
+ expect(e.message).to.contain('Invalid URI: /x');
396
+ expect(e).to.be.instanceOf(MongoshInvalidInputError);
397
+ expect(e.code).to.equal(CommonErrors.InvalidArgument);
398
+ return;
399
+ }
400
+ expect.fail('expected error');
401
+ });
402
+ });
403
+
404
+ context('when the --host option contains invalid characters', () => {
405
+ const options = { host: 'a$b,c' };
406
+
407
+ it('returns the uri', () => {
408
+ try {
409
+ generateUri(options);
410
+ } catch (e: any) {
411
+ expect(e.message).to.contain('The --host argument contains an invalid character: $');
412
+ expect(e).to.be.instanceOf(MongoshInvalidInputError);
413
+ expect(e.code).to.equal(CommonErrors.InvalidArgument);
414
+ return;
415
+ }
416
+ expect.fail('expected error');
417
+ });
418
+ });
419
+
420
+ context('when the --host option contains a seed list', () => {
421
+ context('without a replica set', () => {
422
+ it('returns a URI for the hosts and ports specified in --host', () => {
423
+ const options = { host: 'host1:123,host2,host3:456,' };
424
+ expect(generateUri(options)).to.equal('mongodb://host1:123,host2,host3:456/');
425
+ });
426
+
427
+ it('returns a URI for the hosts and ports specified in --host and database name', () => {
428
+ const options = {
429
+ host: 'host1:123,host_2,host3:456,',
430
+ connectionSpecifier: 'admin'
431
+ };
432
+ expect(generateUri(options)).to.equal('mongodb://host1:123,host_2,host3:456/admin');
433
+ });
434
+
435
+ it('returns a URI for the hosts in --host and fixed --port', () => {
436
+ const options = {
437
+ host: 'host1:1234,host_2',
438
+ port: '1234',
439
+ connectionSpecifier: 'admin'
440
+ };
441
+ expect(generateUri(options)).to.equal('mongodb://host1:1234,host_2:1234/admin');
442
+ });
443
+
444
+ it('throws an error if seed list in --host contains port mismatches from fixed --port', () => {
445
+ const options = {
446
+ host: 'host1,host_2:123',
447
+ port: '1234',
448
+ connectionSpecifier: 'admin'
449
+ };
450
+ expect(() => generateUri(options)).to.throw('The host list contains different ports than provided by --port');
451
+ });
452
+ });
453
+
454
+ context('with a replica set', () => {
455
+ it('returns a URI for the hosts and ports specified in --host', () => {
456
+ const options = { host: 'replsetname/host1:123,host2,host3:456,' };
457
+ expect(generateUri(options)).to.equal('mongodb://host1:123,host2,host3:456/?replicaSet=replsetname');
458
+ });
459
+
460
+ it('returns a URI for the hosts and ports specified in --host and database name', () => {
461
+ const options = { host: 'replsetname/host1:123,host2,host3:456', connectionSpecifier: 'admin' };
462
+ expect(generateUri(options)).to.equal('mongodb://host1:123,host2,host3:456/admin?replicaSet=replsetname');
463
+ });
464
+
465
+ it('returns a URI for the hosts and ports specified in --host and database name with escaped chars', () => {
466
+ const options = { host: 'replsetname/host1:123,host2,host3:456', connectionSpecifier: 'admin?foo=bar' };
467
+ expect(generateUri(options)).to.equal('mongodb://host1:123,host2,host3:456/admin%3Ffoo%3Dbar?replicaSet=replsetname');
468
+ });
469
+
470
+ it('returns a URI for the hosts specified in --host and explicit --port', () => {
471
+ const options = { host: 'replsetname/host1:123,host2,', port: '123' };
472
+ expect(generateUri(options)).to.equal('mongodb://host1:123,host2:123/?replicaSet=replsetname');
473
+ });
474
+
475
+ it('throws an error if the hosts contain ports that mismatch from --port', () => {
476
+ const options = { host: 'replsetname/host1:1234,host2,', port: '123' };
477
+ expect(() => generateUri(options)).to.throw('The host list contains different ports than provided by --port');
478
+ });
479
+ });
480
+ });
481
+ });