mongo 2.5.0.beta → 2.5.0

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 (172) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/mongo/address.rb +1 -1
  5. data/lib/mongo/address/unix.rb +1 -1
  6. data/lib/mongo/auth/user.rb +0 -5
  7. data/lib/mongo/auth/user/view.rb +4 -4
  8. data/lib/mongo/bulk_write.rb +60 -32
  9. data/lib/mongo/client.rb +44 -8
  10. data/lib/mongo/cluster.rb +14 -12
  11. data/lib/mongo/cluster/periodic_executor.rb +106 -0
  12. data/lib/mongo/cluster/{cursor_reaper.rb → reapers/cursor_reaper.rb} +5 -37
  13. data/lib/mongo/cluster/reapers/socket_reaper.rb +59 -0
  14. data/lib/mongo/collection.rb +9 -6
  15. data/lib/mongo/collection/view.rb +2 -2
  16. data/lib/mongo/collection/view/builder/aggregation.rb +2 -1
  17. data/lib/mongo/collection/view/builder/find_command.rb +1 -1
  18. data/lib/mongo/collection/view/change_stream.rb +14 -1
  19. data/lib/mongo/collection/view/map_reduce.rb +30 -13
  20. data/lib/mongo/collection/view/readable.rb +5 -5
  21. data/lib/mongo/collection/view/writable.rb +98 -51
  22. data/lib/mongo/error.rb +3 -0
  23. data/lib/mongo/error/invalid_txt_record.rb +27 -0
  24. data/lib/mongo/error/invalid_uri.rb +7 -6
  25. data/lib/mongo/error/mismatched_domain.rb +27 -0
  26. data/lib/mongo/error/no_srv_records.rb +26 -0
  27. data/lib/mongo/error/unsupported_features.rb +0 -18
  28. data/lib/mongo/index/view.rb +2 -2
  29. data/lib/mongo/operation.rb +1 -0
  30. data/lib/mongo/operation/causally_consistent.rb +33 -0
  31. data/lib/mongo/operation/commands.rb +2 -1
  32. data/lib/mongo/operation/commands/aggregate.rb +2 -7
  33. data/lib/mongo/operation/commands/count.rb +27 -0
  34. data/lib/mongo/operation/commands/distinct.rb +27 -0
  35. data/lib/mongo/operation/commands/find.rb +3 -1
  36. data/lib/mongo/operation/commands/map_reduce.rb +1 -0
  37. data/lib/mongo/operation/commands/parallel_scan.rb +1 -0
  38. data/lib/mongo/operation/specifiable.rb +12 -0
  39. data/lib/mongo/operation/uses_command_op_msg.rb +36 -5
  40. data/lib/mongo/operation/write.rb +0 -5
  41. data/lib/mongo/operation/write/bulk/bulkable.rb +4 -8
  42. data/lib/mongo/operation/write/bulk/mergable.rb +2 -0
  43. data/lib/mongo/operation/write/command/create_index.rb +19 -0
  44. data/lib/mongo/operation/write/command/create_user.rb +19 -0
  45. data/lib/mongo/operation/write/command/delete.rb +1 -2
  46. data/lib/mongo/operation/write/command/drop_index.rb +19 -0
  47. data/lib/mongo/operation/write/command/insert.rb +1 -2
  48. data/lib/mongo/operation/write/command/remove_user.rb +19 -0
  49. data/lib/mongo/operation/write/command/update.rb +1 -2
  50. data/lib/mongo/operation/write/command/update_user.rb +19 -0
  51. data/lib/mongo/operation/write/write_command_enabled.rb +1 -3
  52. data/lib/mongo/protocol/compressed.rb +2 -1
  53. data/lib/mongo/protocol/serializers.rb +6 -6
  54. data/lib/mongo/retryable.rb +48 -5
  55. data/lib/mongo/server.rb +15 -0
  56. data/lib/mongo/server/connection.rb +21 -1
  57. data/lib/mongo/server/connection_pool.rb +3 -0
  58. data/lib/mongo/server/connection_pool/queue.rb +50 -5
  59. data/lib/mongo/server/description.rb +11 -3
  60. data/lib/mongo/server/description/features.rb +26 -7
  61. data/lib/mongo/session.rb +133 -6
  62. data/lib/mongo/session/server_session.rb +30 -0
  63. data/lib/mongo/session/session_pool.rb +20 -20
  64. data/lib/mongo/uri.rb +88 -44
  65. data/lib/mongo/uri/srv_protocol.rb +158 -0
  66. data/lib/mongo/version.rb +1 -1
  67. data/lib/mongo/write_concern/normalizable.rb +12 -0
  68. data/mongo.gemspec +1 -2
  69. data/spec/mongo/address_spec.rb +12 -0
  70. data/spec/mongo/auth/user/view_spec.rb +1 -5
  71. data/spec/mongo/bulk_write_spec.rb +232 -401
  72. data/spec/mongo/change_stream_examples_spec.rb +150 -0
  73. data/spec/mongo/client_spec.rb +142 -2
  74. data/spec/mongo/cluster/cursor_reaper_spec.rb +0 -70
  75. data/spec/mongo/cluster/socket_reaper_spec.rb +32 -0
  76. data/spec/mongo/cluster_spec.rb +11 -7
  77. data/spec/mongo/collection/view/aggregation_spec.rb +46 -1
  78. data/spec/mongo/collection/view/builder/find_command_spec.rb +15 -0
  79. data/spec/mongo/collection/view/change_stream_spec.rb +79 -12
  80. data/spec/mongo/collection/view/map_reduce_spec.rb +120 -4
  81. data/spec/mongo/collection/view/readable_spec.rb +23 -5
  82. data/spec/mongo/collection_spec.rb +292 -102
  83. data/spec/mongo/command_monitoring_spec.rb +26 -32
  84. data/spec/mongo/crud_spec.rb +1 -1
  85. data/spec/mongo/cursor_spec.rb +2 -3
  86. data/spec/mongo/database_spec.rb +30 -14
  87. data/spec/mongo/dns_seedlist_discovery_spec.rb +94 -0
  88. data/spec/mongo/grid/fs_bucket_spec.rb +1 -1
  89. data/spec/mongo/grid/stream/write_spec.rb +1 -1
  90. data/spec/mongo/index/view_spec.rb +8 -46
  91. data/spec/mongo/operation/write/bulk/delete_spec.rb +2 -2
  92. data/spec/mongo/operation/write/bulk/insert_spec.rb +2 -10
  93. data/spec/mongo/operation/write/{create_index_spec.rb → command/create_index_spec.rb} +2 -6
  94. data/spec/mongo/operation/write/command/delete_spec.rb +35 -7
  95. data/spec/mongo/operation/write/{drop_index_spec.rb → command/drop_index_spec.rb} +1 -1
  96. data/spec/mongo/operation/write/command/insert_spec.rb +37 -6
  97. data/spec/mongo/operation/write/{remove_user_spec.rb → command/remove_user_spec.rb} +2 -6
  98. data/spec/mongo/operation/write/command/update_spec.rb +34 -7
  99. data/spec/mongo/operation/write/{update_user_spec.rb → command/update_user_spec.rb} +1 -1
  100. data/spec/mongo/operation/write/create_user_spec.rb +1 -1
  101. data/spec/mongo/operation/write/delete_spec.rb +1 -1
  102. data/spec/mongo/operation/write/insert_spec.rb +2 -10
  103. data/spec/mongo/operation/write/update_spec.rb +3 -15
  104. data/spec/mongo/retryable_spec.rb +1 -1
  105. data/spec/mongo/retryable_writes_spec.rb +815 -0
  106. data/spec/mongo/server/connection_pool/queue_spec.rb +35 -2
  107. data/spec/mongo/server/connection_pool_spec.rb +234 -1
  108. data/spec/mongo/server/connection_spec.rb +10 -6
  109. data/spec/mongo/server/description/features_spec.rb +51 -37
  110. data/spec/mongo/server/description_spec.rb +6 -3
  111. data/spec/mongo/server_spec.rb +87 -0
  112. data/spec/mongo/session/server_session_spec.rb +43 -0
  113. data/spec/mongo/session/session_pool_spec.rb +63 -27
  114. data/spec/mongo/session_spec.rb +247 -0
  115. data/spec/mongo/shell_examples_spec.rb +2 -2
  116. data/spec/mongo/uri/srv_protocol_spec.rb +933 -0
  117. data/spec/mongo/uri_spec.rb +42 -3
  118. data/spec/mongo/write_concern/acknowledged_spec.rb +11 -0
  119. data/spec/mongo/write_concern/unacknowledged_spec.rb +11 -0
  120. data/spec/spec_helper.rb +11 -25
  121. data/spec/support/authorization.rb +2 -1
  122. data/spec/support/connection_string.rb +8 -4
  123. data/spec/support/crud.rb +38 -24
  124. data/spec/support/crud/write.rb +30 -3
  125. data/spec/support/crud_tests/read/aggregate-out.yml +21 -0
  126. data/spec/support/crud_tests/write/bulkWrite-arrayFilters.yml +44 -0
  127. data/spec/support/crud_tests/write/findOneAndUpdate-arrayFilters.yml +1 -1
  128. data/spec/support/crud_tests/write/insertMany.yml +1 -3
  129. data/spec/support/crud_tests/write/replaceOne.yml +1 -1
  130. data/spec/support/crud_tests/write/updateMany-arrayFilters.yml +1 -1
  131. data/spec/support/crud_tests/write/updateOne-arrayFilters.yml +1 -1
  132. data/spec/support/dns_seedlist_discovery_tests/longer-parent-in-return.yml +11 -0
  133. data/spec/support/dns_seedlist_discovery_tests/misformatted-option.yml +5 -0
  134. data/spec/support/dns_seedlist_discovery_tests/no-results.yml +5 -0
  135. data/spec/support/dns_seedlist_discovery_tests/not-enough-parts.yml +5 -0
  136. data/spec/support/dns_seedlist_discovery_tests/one-result-default-port.yml +10 -0
  137. data/spec/support/dns_seedlist_discovery_tests/one-txt-record-multiple-strings.yml +10 -0
  138. data/spec/support/dns_seedlist_discovery_tests/one-txt-record.yml +11 -0
  139. data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch1.yml +5 -0
  140. data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch2.yml +5 -0
  141. data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch3.yml +5 -0
  142. data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch4.yml +5 -0
  143. data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch5.yml +5 -0
  144. data/spec/support/dns_seedlist_discovery_tests/returned-parent-too-short.yml +5 -0
  145. data/spec/support/dns_seedlist_discovery_tests/returned-parent-wrong.yml +5 -0
  146. data/spec/support/dns_seedlist_discovery_tests/two-results-default-port.yml +11 -0
  147. data/spec/support/dns_seedlist_discovery_tests/two-results-nonstandard-port.yml +11 -0
  148. data/spec/support/dns_seedlist_discovery_tests/two-txt-records.yml +5 -0
  149. data/spec/support/dns_seedlist_discovery_tests/txt-record-not-allowed-option.yml +5 -0
  150. data/spec/support/dns_seedlist_discovery_tests/txt-record-with-overridden-ssl-option.yml +11 -0
  151. data/spec/support/dns_seedlist_discovery_tests/txt-record-with-overridden-uri-option.yml +11 -0
  152. data/spec/support/dns_seedlist_discovery_tests/txt-record-with-unallowed-option.yml +5 -0
  153. data/spec/support/dns_seedlist_discovery_tests/uri-with-port.yml +5 -0
  154. data/spec/support/dns_seedlist_discovery_tests/uri-with-two-hosts.yml +5 -0
  155. data/spec/support/retryable_writes_tests/bulkWrite.yml +305 -0
  156. data/spec/support/retryable_writes_tests/deleteOne.yml +51 -0
  157. data/spec/support/retryable_writes_tests/findOneAndDelete.yml +52 -0
  158. data/spec/support/retryable_writes_tests/findOneAndReplace.yml +57 -0
  159. data/spec/support/retryable_writes_tests/findOneAndUpdate.yml +56 -0
  160. data/spec/support/retryable_writes_tests/insertMany.yml +72 -0
  161. data/spec/support/retryable_writes_tests/insertOne.yml +55 -0
  162. data/spec/support/retryable_writes_tests/replaceOne.yml +60 -0
  163. data/spec/support/retryable_writes_tests/updateOne.yml +120 -0
  164. data/spec/support/shared/session.rb +525 -24
  165. metadata +437 -350
  166. metadata.gz.sig +0 -0
  167. data/lib/mongo/operation/commands/user_query.rb +0 -72
  168. data/lib/mongo/operation/write/create_index.rb +0 -67
  169. data/lib/mongo/operation/write/create_user.rb +0 -50
  170. data/lib/mongo/operation/write/drop_index.rb +0 -63
  171. data/lib/mongo/operation/write/remove_user.rb +0 -48
  172. data/lib/mongo/operation/write/update_user.rb +0 -50
@@ -845,7 +845,7 @@ describe 'shell examples in Ruby' do
845
845
  # End Example 51
846
846
  end
847
847
 
848
- context 'example 52', if: write_command_enabled? do
848
+ context 'example 52' do
849
849
 
850
850
  let!(:example) do
851
851
  # Start Example 52
@@ -862,7 +862,7 @@ describe 'shell examples in Ruby' do
862
862
  end
863
863
  end
864
864
 
865
- context 'example 53', if: write_command_enabled? do
865
+ context 'example 53' do
866
866
 
867
867
  let!(:example) do
868
868
  # Start Example 53
@@ -0,0 +1,933 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::URI::SRVProtocol do
4
+
5
+ let(:scheme) { 'mongodb+srv://' }
6
+ let(:uri) { described_class.new(string) }
7
+
8
+ describe 'invalid uris' do
9
+
10
+ context 'when there is more than one hostname' do
11
+
12
+ let(:string) { "#{scheme}#{hosts}" }
13
+ let(:hosts) { 'test5.test.build.10gen.cc,test6.test.build.10gen.cc' }
14
+
15
+ it 'raises an error' do
16
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
17
+ end
18
+ end
19
+
20
+ context 'when the the hostname has a port' do
21
+
22
+ let(:string) { "#{scheme}#{hosts}" }
23
+ let(:hosts) { 'test5.test.build.10gen.cc:8123' }
24
+
25
+ it 'raises an error' do
26
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
27
+ end
28
+ end
29
+
30
+ context 'when the host in URI does not have {hostname}, {domainname} and {tld}' do
31
+
32
+ let(:string) { "#{scheme}#{hosts}" }
33
+ let(:hosts) { '10gen.cc/' }
34
+
35
+ it 'raises an error' do
36
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
37
+ end
38
+ end
39
+
40
+ context 'string is not uri' do
41
+
42
+ let(:string) { 'tyler' }
43
+
44
+ it 'raises an error' do
45
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
46
+ end
47
+ end
48
+
49
+ context 'empty string' do
50
+
51
+ let(:string) { '' }
52
+
53
+ it 'raises an error' do
54
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
55
+ end
56
+ end
57
+
58
+ context 'mongodb+srv://' do
59
+
60
+ let(:string) { "#{scheme}" }
61
+
62
+ it 'raises an error' do
63
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
64
+ end
65
+ end
66
+
67
+ context 'mongodb+srv://localhost::27017/' do
68
+
69
+ let(:string) { "#{scheme}localhost::27017/" }
70
+
71
+ it 'raises an error' do
72
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
73
+ end
74
+ end
75
+
76
+ context 'mongodb+srv://::' do
77
+
78
+ let(:string) { "#{scheme}::" }
79
+
80
+ it 'raises an error' do
81
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
82
+ end
83
+ end
84
+
85
+ context 'mongodb+srv://localhost,localhost::' do
86
+
87
+ let(:string) { "#{scheme}localhost,localhost::" }
88
+
89
+ it 'raises an error' do
90
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
91
+ end
92
+ end
93
+
94
+ context 'mongodb+srv://localhost::27017,abc' do
95
+
96
+ let(:string) { "#{scheme}localhost::27017,abc" }
97
+
98
+ it 'raises an error' do
99
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
100
+ end
101
+ end
102
+
103
+ context 'mongodb+srv://localhost:-1' do
104
+
105
+ let(:string) { "#{scheme}localhost:-1" }
106
+
107
+ it 'raises an error' do
108
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
109
+ end
110
+ end
111
+
112
+ context 'mongodb+srv://localhost:0/' do
113
+
114
+ let(:string) { "#{scheme}localhost:0/" }
115
+
116
+ it 'raises an error' do
117
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
118
+ end
119
+ end
120
+
121
+ context 'mongodb+srv://localhost:65536' do
122
+
123
+ let(:string) { "#{scheme}localhost:65536" }
124
+
125
+ it 'raises an error' do
126
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
127
+ end
128
+ end
129
+
130
+ context 'mongodb+srv://localhost:foo' do
131
+
132
+ let(:string) { "#{scheme}localhost:foo" }
133
+
134
+ it 'raises an error' do
135
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
136
+ end
137
+ end
138
+
139
+ context 'mongodb+srv://mongodb://[::1]:-1' do
140
+
141
+ let(:string) { "#{scheme}mongodb://[::1]:-1" }
142
+
143
+ it 'raises an error' do
144
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
145
+ end
146
+ end
147
+
148
+ context 'mongodb+srv://[::1]:0/' do
149
+
150
+ let(:string) { "#{scheme}[::1]:0/" }
151
+
152
+ it 'raises an error' do
153
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
154
+ end
155
+ end
156
+
157
+ context 'mongodb+srv://[::1]:65536' do
158
+
159
+ let(:string) { "#{scheme}[::1]:65536" }
160
+
161
+ it 'raises an error' do
162
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
163
+ end
164
+ end
165
+
166
+ context 'mongodb+srv://[::1]:65536/' do
167
+
168
+ let(:string) { "#{scheme}[::1]:65536/" }
169
+
170
+ it 'raises an error' do
171
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
172
+ end
173
+ end
174
+
175
+ context 'mongodb+srv://[::1]:foo' do
176
+
177
+ let(:string) { "#{scheme}[::1]:foo" }
178
+
179
+ it 'raises an error' do
180
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
181
+ end
182
+ end
183
+
184
+ context 'mongodb+srv://example.com?w=1' do
185
+
186
+ let(:string) { "#{scheme}example.com?w=1" }
187
+
188
+ it 'raises an error' do
189
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
190
+ end
191
+ end
192
+
193
+ context 'mongodb+srv://example.com/?w' do
194
+
195
+ let(:string) { "#{scheme}example.com/?w" }
196
+
197
+ it 'raises an error' do
198
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
199
+ end
200
+ end
201
+ end
202
+
203
+ describe 'invalid query results' do
204
+
205
+ context 'when there are too many TXT records' do
206
+
207
+ let(:string) { "#{scheme}test6.test.build.10gen.cc/" }
208
+
209
+ it 'raises an error' do
210
+ expect { uri }.to raise_exception(Mongo::Error::InvalidTXTRecord)
211
+ end
212
+ end
213
+
214
+ context 'when the TXT has an invalid option' do
215
+
216
+ let(:string) { "#{scheme}test10.test.build.10gen.cc" }
217
+
218
+ it 'raises an error' do
219
+ expect { uri }.to raise_exception(Mongo::Error::InvalidTXTRecord)
220
+ end
221
+ end
222
+
223
+ context 'when the SRV records domain does not match hostname used for the query' do
224
+
225
+ let(:string) { "#{scheme}test12.test.build.10gen.cc" }
226
+
227
+ it 'raises an error' do
228
+ expect { uri }.to raise_exception(Mongo::Error::MismatchedDomain)
229
+ end
230
+ end
231
+
232
+ context 'when the query returns no SRV records' do
233
+
234
+ let(:string) { "#{scheme}test4.test.build.10gen.cc" }
235
+
236
+ it 'raises an error' do
237
+ expect { uri }.to raise_exception(Mongo::Error::NoSRVRecords)
238
+ end
239
+ end
240
+ end
241
+
242
+ describe '#servers' do
243
+ let(:string) { "#{scheme}#{servers}" }
244
+
245
+ context 'single server' do
246
+ let(:servers) { 'test5.test.build.10gen.cc' }
247
+
248
+ it 'returns an array with the parsed server' do
249
+ expect(uri.servers).to eq(['localhost.test.build.10gen.cc:27017'])
250
+ end
251
+ end
252
+ end
253
+
254
+ describe '#client_options' do
255
+
256
+ let(:db) { TEST_DB }
257
+ let(:servers) { 'test5.test.build.10gen.cc' }
258
+ let(:string) { "#{scheme}#{credentials}@#{servers}/#{db}" }
259
+ let(:user) { 'tyler' }
260
+ let(:password) { 's3kr4t' }
261
+ let(:credentials) { "#{user}:#{password}" }
262
+
263
+ let(:options) do
264
+ uri.client_options
265
+ end
266
+
267
+ it 'includes the database in the options' do
268
+ expect(options[:database]).to eq(TEST_DB)
269
+ end
270
+
271
+ it 'includes the user in the options' do
272
+ expect(options[:user]).to eq(user)
273
+ end
274
+
275
+ it 'includes the password in the options' do
276
+ expect(options[:password]).to eq(password)
277
+ end
278
+
279
+ it 'sets ssl to true' do
280
+ expect(options[:ssl]).to eq(true)
281
+ end
282
+ end
283
+
284
+ describe '#credentials' do
285
+ let(:servers) { 'test5.test.build.10gen.cc' }
286
+ let(:string) { "#{scheme}#{credentials}@#{servers}" }
287
+ let(:user) { 'tyler' }
288
+
289
+ context 'username provided' do
290
+ let(:credentials) { "#{user}:" }
291
+
292
+ it 'returns the username' do
293
+ expect(uri.credentials[:user]).to eq(user)
294
+ end
295
+ end
296
+
297
+ context 'username and password provided' do
298
+ let(:password) { 's3kr4t' }
299
+ let(:credentials) { "#{user}:#{password}" }
300
+
301
+ it 'returns the username' do
302
+ expect(uri.credentials[:user]).to eq(user)
303
+ end
304
+
305
+ it 'returns the password' do
306
+ expect(uri.credentials[:password]).to eq(password)
307
+ end
308
+ end
309
+ end
310
+
311
+ describe '#database' do
312
+ let(:servers) { 'test5.test.build.10gen.cc' }
313
+ let(:string) { "#{scheme}#{servers}/#{db}" }
314
+ let(:db) { 'auth-db' }
315
+
316
+ context 'database provided' do
317
+ it 'returns the database name' do
318
+ expect(uri.database).to eq(db)
319
+ end
320
+ end
321
+ end
322
+
323
+ describe '#uri_options' do
324
+ let(:servers) { 'test5.test.build.10gen.cc' }
325
+ let(:string) { "#{scheme}#{servers}/?#{options}" }
326
+
327
+ context 'when no options were provided' do
328
+ let(:string) { "#{scheme}#{servers}" }
329
+
330
+ it 'returns an empty hash' do
331
+ expect(uri.uri_options).to be_empty
332
+ end
333
+ end
334
+
335
+ context 'write concern options provided' do
336
+
337
+ context 'numerical w value' do
338
+ let(:options) { 'w=1' }
339
+ let(:concern) { Mongo::Options::Redacted.new(:w => 1)}
340
+
341
+ it 'sets the write concern options' do
342
+ expect(uri.uri_options[:write]).to eq(concern)
343
+ end
344
+
345
+ it 'sets the options on a client created with the uri' do
346
+ expect(Mongo::Client.new(string).options[:write]).to eq(concern)
347
+ end
348
+ end
349
+
350
+ context 'w=majority' do
351
+ let(:options) { 'w=majority' }
352
+ let(:concern) { Mongo::Options::Redacted.new(:w => :majority) }
353
+
354
+ it 'sets the write concern options' do
355
+ expect(uri.uri_options[:write]).to eq(concern)
356
+ end
357
+
358
+ it 'sets the options on a client created with the uri' do
359
+ expect(Mongo::Client.new(string).options[:write]).to eq(concern)
360
+ end
361
+ end
362
+
363
+ context 'journal' do
364
+ let(:options) { 'journal=true' }
365
+ let(:concern) { Mongo::Options::Redacted.new(:j => true) }
366
+
367
+ it 'sets the write concern options' do
368
+ expect(uri.uri_options[:write]).to eq(concern)
369
+ end
370
+
371
+ it 'sets the options on a client created with the uri' do
372
+ expect(Mongo::Client.new(string).options[:write]).to eq(concern)
373
+ end
374
+ end
375
+
376
+ context 'fsync' do
377
+ let(:options) { 'fsync=true' }
378
+ let(:concern) { Mongo::Options::Redacted.new(:fsync => true) }
379
+
380
+ it 'sets the write concern options' do
381
+ expect(uri.uri_options[:write]).to eq(concern)
382
+ end
383
+
384
+ it 'sets the options on a client created with the uri' do
385
+ expect(Mongo::Client.new(string).options[:write]).to eq(concern)
386
+ end
387
+ end
388
+
389
+ context 'wtimeoutMS' do
390
+ let(:timeout) { 1234 }
391
+ let(:options) { "w=2&wtimeoutMS=#{timeout}" }
392
+ let(:concern) { Mongo::Options::Redacted.new(:w => 2, :timeout => timeout) }
393
+
394
+ it 'sets the write concern options' do
395
+ expect(uri.uri_options[:write]).to eq(concern)
396
+ end
397
+
398
+ it 'sets the options on a client created with the uri' do
399
+ expect(Mongo::Client.new(string).options[:write]).to eq(concern)
400
+ end
401
+ end
402
+ end
403
+
404
+ context 'read preference option provided' do
405
+ let(:options) { "readPreference=#{mode}" }
406
+
407
+ context 'primary' do
408
+ let(:mode) { 'primary' }
409
+ let(:read) { Mongo::Options::Redacted.new(:mode => :primary) }
410
+
411
+ it 'sets the read preference' do
412
+ expect(uri.uri_options[:read]).to eq(read)
413
+ end
414
+
415
+ it 'sets the options on a client created with the uri' do
416
+ expect(Mongo::Client.new(string).options[:read]).to eq(read)
417
+ end
418
+ end
419
+
420
+ context 'primaryPreferred' do
421
+ let(:mode) { 'primaryPreferred' }
422
+ let(:read) { Mongo::Options::Redacted.new(:mode => :primary_preferred) }
423
+
424
+ it 'sets the read preference' do
425
+ expect(uri.uri_options[:read]).to eq(read)
426
+ end
427
+
428
+ it 'sets the options on a client created with the uri' do
429
+ expect(Mongo::Client.new(string).options[:read]).to eq(read)
430
+ end
431
+ end
432
+
433
+ context 'secondary' do
434
+ let(:mode) { 'secondary' }
435
+ let(:read) { Mongo::Options::Redacted.new(:mode => :secondary) }
436
+
437
+ it 'sets the read preference' do
438
+ expect(uri.uri_options[:read]).to eq(read)
439
+ end
440
+
441
+ it 'sets the options on a client created with the uri' do
442
+ expect(Mongo::Client.new(string).options[:read]).to eq(read)
443
+ end
444
+ end
445
+
446
+ context 'secondaryPreferred' do
447
+ let(:mode) { 'secondaryPreferred' }
448
+ let(:read) { Mongo::Options::Redacted.new(:mode => :secondary_preferred) }
449
+
450
+ it 'sets the read preference' do
451
+ expect(uri.uri_options[:read]).to eq(read)
452
+ end
453
+
454
+ it 'sets the options on a client created with the uri' do
455
+ expect(Mongo::Client.new(string).options[:read]).to eq(read)
456
+ end
457
+ end
458
+
459
+ context 'nearest' do
460
+ let(:mode) { 'nearest' }
461
+ let(:read) { Mongo::Options::Redacted.new(:mode => :nearest) }
462
+
463
+ it 'sets the read preference' do
464
+ expect(uri.uri_options[:read]).to eq(read)
465
+ end
466
+
467
+ it 'sets the options on a client created with the uri' do
468
+ expect(Mongo::Client.new(string).options[:read]).to eq(read)
469
+ end
470
+ end
471
+ end
472
+
473
+ context 'read preference tags provided' do
474
+
475
+ context 'single read preference tag set' do
476
+ let(:options) do
477
+ 'readPreferenceTags=dc:ny,rack:1'
478
+ end
479
+
480
+ let(:read) do
481
+ Mongo::Options::Redacted.new(:tag_sets => [{ 'dc' => 'ny', 'rack' => '1' }])
482
+ end
483
+
484
+ it 'sets the read preference tag set' do
485
+ expect(uri.uri_options[:read]).to eq(read)
486
+ end
487
+
488
+ it 'sets the options on a client created with the uri' do
489
+ expect(Mongo::Client.new(string).options[:read]).to eq(read)
490
+ end
491
+ end
492
+
493
+ context 'multiple read preference tag sets' do
494
+ let(:options) do
495
+ 'readPreferenceTags=dc:ny&readPreferenceTags=dc:bos'
496
+ end
497
+
498
+ let(:read) do
499
+ Mongo::Options::Redacted.new(:tag_sets => [{ 'dc' => 'ny' }, { 'dc' => 'bos' }])
500
+ end
501
+
502
+ it 'sets the read preference tag sets' do
503
+ expect(uri.uri_options[:read]).to eq(read)
504
+ end
505
+
506
+ it 'sets the options on a client created with the uri' do
507
+ expect(Mongo::Client.new(string).options[:read]).to eq(read)
508
+ end
509
+ end
510
+ end
511
+
512
+ context 'read preference max staleness option provided' do
513
+
514
+ let(:options) do
515
+ 'readPreference=Secondary&maxStalenessSeconds=120'
516
+ end
517
+
518
+ let(:read) do
519
+ Mongo::Options::Redacted.new(mode: :secondary, :max_staleness => 120)
520
+ end
521
+
522
+ it 'sets the read preference max staleness in seconds' do
523
+ expect(uri.uri_options[:read]).to eq(read)
524
+ end
525
+
526
+ it 'sets the options on a client created with the uri' do
527
+ expect(Mongo::Client.new(string).options[:read]).to eq(read)
528
+ end
529
+
530
+ context 'when the read preference and max staleness combination is invalid' do
531
+
532
+ context 'when max staleness is combined with read preference mode primary' do
533
+
534
+ let(:options) do
535
+ 'readPreference=primary&maxStalenessSeconds=120'
536
+ end
537
+
538
+ it 'raises an exception when read preference is accessed on the client' do
539
+ expect {
540
+ Mongo::Client.new(string).server_selector
541
+ }.to raise_exception(Mongo::Error::InvalidServerPreference)
542
+ end
543
+ end
544
+
545
+ context 'when the max staleness value is too small' do
546
+
547
+ let(:options) do
548
+ 'readPreference=secondary&maxStalenessSeconds=89'
549
+ end
550
+
551
+ it 'does not raise an exception until the read preference is used' do
552
+ expect(Mongo::Client.new(string).read_preference).to eq(BSON::Document.new(mode: :secondary, max_staleness: 89))
553
+ end
554
+ end
555
+ end
556
+ end
557
+
558
+ context 'replica set option provided' do
559
+ let(:rs_name) { TEST_SET }
560
+ let(:options) { "replicaSet=#{rs_name}" }
561
+
562
+ it 'sets the replica set option' do
563
+ expect(uri.uri_options[:replica_set]).to eq(rs_name)
564
+ end
565
+
566
+ it 'sets the options on a client created with the uri' do
567
+ expect(Mongo::Client.new(string).options[:replica_set]).to eq(rs_name)
568
+ end
569
+ end
570
+
571
+ context 'auth mechanism provided' do
572
+ let(:options) { "authMechanism=#{mechanism}" }
573
+
574
+ context 'plain' do
575
+ let(:mechanism) { 'PLAIN' }
576
+ let(:expected) { :plain }
577
+
578
+ it 'sets the auth mechanism to :plain' do
579
+ expect(uri.uri_options[:auth_mech]).to eq(expected)
580
+ end
581
+
582
+ it 'sets the options on a client created with the uri' do
583
+ expect(Mongo::Client.new(string).options[:auth_mech]).to eq(expected)
584
+ end
585
+
586
+ it 'is case-insensitive' do
587
+ expect(Mongo::Client.new(string.downcase).options[:auth_mech]).to eq(expected)
588
+ end
589
+ end
590
+
591
+ context 'mongodb-cr' do
592
+ let(:mechanism) { 'MONGODB-CR' }
593
+ let(:expected) { :mongodb_cr }
594
+
595
+ it 'sets the auth mechanism to :mongodb_cr' do
596
+ expect(uri.uri_options[:auth_mech]).to eq(expected)
597
+ end
598
+
599
+ it 'sets the options on a client created with the uri' do
600
+ expect(Mongo::Client.new(string).options[:auth_mech]).to eq(expected)
601
+ end
602
+
603
+ it 'is case-insensitive' do
604
+ expect(Mongo::Client.new(string.downcase).options[:auth_mech]).to eq(expected)
605
+ end
606
+ end
607
+
608
+ context 'gssapi' do
609
+ let(:mechanism) { 'GSSAPI' }
610
+ let(:expected) { :gssapi }
611
+
612
+ it 'sets the auth mechanism to :gssapi' do
613
+ expect(uri.uri_options[:auth_mech]).to eq(expected)
614
+ end
615
+
616
+ it 'sets the options on a client created with the uri' do
617
+ expect(Mongo::Client.new(string).options[:auth_mech]).to eq(expected)
618
+ end
619
+
620
+ it 'is case-insensitive' do
621
+ expect(Mongo::Client.new(string.downcase).options[:auth_mech]).to eq(expected)
622
+ end
623
+ end
624
+
625
+ context 'scram-sha-1' do
626
+ let(:mechanism) { 'SCRAM-SHA-1' }
627
+ let(:expected) { :scram }
628
+
629
+ it 'sets the auth mechanism to :scram' do
630
+ expect(uri.uri_options[:auth_mech]).to eq(expected)
631
+ end
632
+
633
+ it 'sets the options on a client created with the uri' do
634
+ expect(Mongo::Client.new(string).options[:auth_mech]).to eq(expected)
635
+ end
636
+
637
+ it 'is case-insensitive' do
638
+ expect(Mongo::Client.new(string.downcase).options[:auth_mech]).to eq(expected)
639
+ end
640
+ end
641
+
642
+ context 'mongodb-x509' do
643
+ let(:mechanism) { 'MONGODB-X509' }
644
+ let(:expected) { :mongodb_x509 }
645
+
646
+ it 'sets the auth mechanism to :mongodb_x509' do
647
+ expect(uri.uri_options[:auth_mech]).to eq(expected)
648
+ end
649
+
650
+ it 'sets the options on a client created with the uri' do
651
+ expect(Mongo::Client.new(string).options[:auth_mech]).to eq(expected)
652
+ end
653
+
654
+ it 'is case-insensitive' do
655
+ expect(Mongo::Client.new(string.downcase).options[:auth_mech]).to eq(expected)
656
+ end
657
+
658
+ context 'when a username is not provided' do
659
+
660
+ it 'recognizes the mechanism with no username' do
661
+ expect(Mongo::Client.new(string.downcase).options[:auth_mech]).to eq(expected)
662
+ expect(Mongo::Client.new(string.downcase).options[:user]).to be_nil
663
+ end
664
+ end
665
+ end
666
+ end
667
+
668
+ context 'auth source provided' do
669
+ let(:options) { "authSource=#{source}" }
670
+
671
+ context 'regular db' do
672
+ let(:source) { 'foo' }
673
+
674
+ it 'sets the auth source to the database' do
675
+ expect(uri.uri_options[:auth_source]).to eq(source)
676
+ end
677
+
678
+ it 'sets the options on a client created with the uri' do
679
+ expect(Mongo::Client.new(string).options[:auth_source]).to eq(source)
680
+ end
681
+ end
682
+
683
+ context '$external' do
684
+ let(:source) { '$external' }
685
+ let(:expected) { :external }
686
+
687
+ it 'sets the auth source to :external' do
688
+ expect(uri.uri_options[:auth_source]).to eq(expected)
689
+ end
690
+
691
+ it 'sets the options on a client created with the uri' do
692
+ expect(Mongo::Client.new(string).options[:auth_source]).to eq(expected)
693
+ end
694
+ end
695
+ end
696
+
697
+ context 'auth mechanism properties provided' do
698
+
699
+ context 'service_name' do
700
+ let(:options) do
701
+ "authMechanismProperties=SERVICE_NAME:#{service_name}"
702
+ end
703
+
704
+ let(:service_name) { 'foo' }
705
+ let(:expected) { Mongo::Options::Redacted.new({ service_name: service_name }) }
706
+
707
+ it 'sets the auth mechanism properties' do
708
+ expect(uri.uri_options[:auth_mech_properties]).to eq(expected)
709
+ end
710
+
711
+ it 'sets the options on a client created with the uri' do
712
+ expect(Mongo::Client.new(string).options[:auth_mech_properties]).to eq(expected)
713
+ end
714
+ end
715
+
716
+ context 'canonicalize_host_name' do
717
+ let(:options) do
718
+ "authMechanismProperties=CANONICALIZE_HOST_NAME:#{canonicalize_host_name}"
719
+ end
720
+ let(:canonicalize_host_name) { 'true' }
721
+ let(:expected) { Mongo::Options::Redacted.new({ canonicalize_host_name: true }) }
722
+
723
+ it 'sets the auth mechanism properties' do
724
+ expect(uri.uri_options[:auth_mech_properties]).to eq(expected)
725
+ end
726
+
727
+ it 'sets the options on a client created with the uri' do
728
+ expect(Mongo::Client.new(string).options[:auth_mech_properties]).to eq(expected)
729
+ end
730
+ end
731
+
732
+ context 'service_realm' do
733
+ let(:options) do
734
+ "authMechanismProperties=SERVICE_REALM:#{service_realm}"
735
+ end
736
+
737
+ let(:service_realm) { 'dumdum' }
738
+ let(:expected) { Mongo::Options::Redacted.new({ service_realm: service_realm }) }
739
+
740
+
741
+ it 'sets the auth mechanism properties' do
742
+ expect(uri.uri_options[:auth_mech_properties]).to eq(expected)
743
+ end
744
+
745
+ it 'sets the options on a client created with the uri' do
746
+ expect(Mongo::Client.new(string).options[:auth_mech_properties]).to eq(expected)
747
+ end
748
+ end
749
+
750
+ context 'multiple properties' do
751
+ let(:options) do
752
+ "authMechanismProperties=SERVICE_REALM:#{service_realm}," +
753
+ "CANONICALIZE_HOST_NAME:#{canonicalize_host_name}," +
754
+ "SERVICE_NAME:#{service_name}"
755
+ end
756
+
757
+ let(:service_name) { 'foo' }
758
+ let(:canonicalize_host_name) { 'true' }
759
+ let(:service_realm) { 'dumdum' }
760
+
761
+ let(:expected) do
762
+ Mongo::Options::Redacted.new({ service_name: service_name,
763
+ canonicalize_host_name: true,
764
+ service_realm: service_realm })
765
+ end
766
+
767
+ it 'sets the auth mechanism properties' do
768
+ expect(uri.uri_options[:auth_mech_properties]).to eq(expected)
769
+ end
770
+
771
+ it 'sets the options on a client created with the uri' do
772
+ expect(Mongo::Client.new(string).options[:auth_mech_properties]).to eq(expected)
773
+ end
774
+ end
775
+ end
776
+
777
+ context 'connectTimeoutMS' do
778
+ let(:options) { "connectTimeoutMS=4567" }
779
+
780
+ it 'sets the the connect timeout' do
781
+ expect(uri.uri_options[:connect_timeout]).to eq(4.567)
782
+ end
783
+ end
784
+
785
+ context 'socketTimeoutMS' do
786
+ let(:options) { "socketTimeoutMS=8910" }
787
+
788
+ it 'sets the socket timeout' do
789
+ expect(uri.uri_options[:socket_timeout]).to eq(8.910)
790
+ end
791
+ end
792
+
793
+ context 'when providing serverSelectionTimeoutMS' do
794
+
795
+ let(:options) { "serverSelectionTimeoutMS=3561" }
796
+
797
+ it 'sets the the connect timeout' do
798
+ expect(uri.uri_options[:server_selection_timeout]).to eq(3.561)
799
+ end
800
+ end
801
+
802
+ context 'when providing localThresholdMS' do
803
+
804
+ let(:options) { "localThresholdMS=3561" }
805
+
806
+ it 'sets the the connect timeout' do
807
+ expect(uri.uri_options[:local_threshold]).to eq(3.561)
808
+ end
809
+ end
810
+
811
+ context 'when providing maxPoolSize' do
812
+
813
+ let(:max_pool_size) { 10 }
814
+ let(:options) { "maxPoolSize=#{max_pool_size}" }
815
+
816
+ it 'sets the max pool size option' do
817
+ expect(uri.uri_options[:max_pool_size]).to eq(max_pool_size)
818
+ end
819
+ end
820
+
821
+ context 'when providing minPoolSize' do
822
+
823
+ let(:min_pool_size) { 5 }
824
+ let(:options) { "minPoolSize=#{min_pool_size}" }
825
+
826
+ it 'sets the min pool size option' do
827
+ expect(uri.uri_options[:min_pool_size]).to eq(min_pool_size)
828
+ end
829
+ end
830
+
831
+ context 'when providing waitQueueTimeoutMS' do
832
+
833
+ let(:wait_queue_timeout) { 500 }
834
+ let(:options) { "waitQueueTimeoutMS=#{wait_queue_timeout}" }
835
+
836
+ it 'sets the wait queue timeout option' do
837
+ expect(uri.uri_options[:wait_queue_timeout]).to eq(0.5)
838
+ end
839
+ end
840
+
841
+ context 'ssl' do
842
+ let(:options) { "ssl=#{ssl}" }
843
+
844
+ context 'true' do
845
+ let(:ssl) { true }
846
+
847
+ it 'sets the ssl option to true' do
848
+ expect(uri.uri_options[:ssl]).to be true
849
+ end
850
+ end
851
+
852
+ context 'false' do
853
+ let(:ssl) { false }
854
+
855
+ it 'sets the ssl option to false' do
856
+ expect(uri.uri_options[:ssl]).to be false
857
+ end
858
+ end
859
+ end
860
+
861
+ context 'grouped and non-grouped options provided' do
862
+ let(:options) { 'w=1&ssl=true' }
863
+
864
+ it 'do not overshadow top level options' do
865
+ expect(uri.uri_options).not_to be_empty
866
+ end
867
+ end
868
+
869
+ context 'when an invalid option is provided' do
870
+
871
+ let(:options) { 'invalidOption=10' }
872
+
873
+ let(:uri_options) do
874
+ uri.uri_options
875
+ end
876
+
877
+ it 'does not raise an exception' do
878
+ expect(uri_options).to be_empty
879
+ end
880
+
881
+ context 'when an invalid option is combined with valid options' do
882
+
883
+ let(:options) { 'invalidOption=10&waitQueueTimeoutMS=500&ssl=true' }
884
+
885
+ it 'does not raise an exception' do
886
+ expect(uri_options).not_to be_empty
887
+ end
888
+
889
+ it 'sets the valid options' do
890
+ expect(uri_options[:wait_queue_timeout]).to eq(0.5)
891
+ expect(uri_options[:ssl]).to be true
892
+ end
893
+ end
894
+ end
895
+
896
+ context 'when an app name option is provided' do
897
+ let(:options) { "appname=reports" }
898
+
899
+ it 'sets the app name on the client' do
900
+ expect(Mongo::Client.new(string).options[:app_name]).to eq(:reports)
901
+ end
902
+ end
903
+
904
+ context 'when a supported compressors option is provided' do
905
+ let(:options) { "compressors=zlib" }
906
+
907
+ it 'sets the compressors as an array on the client' do
908
+ expect(Mongo::Client.new(string).options[:compressors]).to eq(['zlib'])
909
+ end
910
+ end
911
+
912
+ context 'when a non-supported compressors option is provided' do
913
+ let(:options) { "compressors=snoopy" }
914
+
915
+ let(:client) do
916
+ Mongo::Client.new(string)
917
+ end
918
+
919
+ it 'sets no compressors on the client and warns' do
920
+ expect(Mongo::Logger.logger).to receive(:warn)
921
+ expect(client.options[:compressors]).to be_nil
922
+ end
923
+ end
924
+
925
+ context 'when a zlibCompressionLevel option is provided' do
926
+ let(:options) { "zlibCompressionLevel=6" }
927
+
928
+ it 'sets the zlib compression level on the client' do
929
+ expect(Mongo::Client.new(string).options[:zlib_compression_level]).to eq(6)
930
+ end
931
+ end
932
+ end
933
+ end