mongo 2.5.0.beta → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
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