mongo 2.13.3 → 2.14.0.rc1

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 (197) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/mongo/address/ipv4.rb +1 -1
  4. data/lib/mongo/address/ipv6.rb +1 -1
  5. data/lib/mongo/address.rb +1 -1
  6. data/lib/mongo/bulk_write.rb +17 -0
  7. data/lib/mongo/caching_cursor.rb +74 -0
  8. data/lib/mongo/client.rb +47 -8
  9. data/lib/mongo/cluster/topology/single.rb +1 -1
  10. data/lib/mongo/cluster.rb +3 -3
  11. data/lib/mongo/collection/view/aggregation.rb +25 -4
  12. data/lib/mongo/collection/view/builder/find_command.rb +38 -18
  13. data/lib/mongo/collection/view/explainable.rb +27 -8
  14. data/lib/mongo/collection/view/iterable.rb +72 -12
  15. data/lib/mongo/collection/view/readable.rb +12 -2
  16. data/lib/mongo/collection/view/writable.rb +15 -1
  17. data/lib/mongo/collection/view.rb +24 -20
  18. data/lib/mongo/collection.rb +26 -2
  19. data/lib/mongo/crypt/encryption_io.rb +6 -6
  20. data/lib/mongo/cursor.rb +1 -0
  21. data/lib/mongo/database/view.rb +1 -1
  22. data/lib/mongo/database.rb +8 -14
  23. data/lib/mongo/error/invalid_read_concern.rb +28 -0
  24. data/lib/mongo/error/server_certificate_revoked.rb +22 -0
  25. data/lib/mongo/error/unsupported_option.rb +14 -12
  26. data/lib/mongo/error.rb +2 -0
  27. data/lib/mongo/grid/fs_bucket.rb +37 -37
  28. data/lib/mongo/lint.rb +2 -1
  29. data/lib/mongo/logger.rb +3 -3
  30. data/lib/mongo/operation/aggregate/result.rb +9 -8
  31. data/lib/mongo/operation/collections_info/command.rb +0 -5
  32. data/lib/mongo/operation/collections_info/result.rb +3 -16
  33. data/lib/mongo/operation/delete/bulk_result.rb +2 -0
  34. data/lib/mongo/operation/delete/result.rb +3 -0
  35. data/lib/mongo/operation/explain/command.rb +4 -0
  36. data/lib/mongo/operation/explain/legacy.rb +4 -0
  37. data/lib/mongo/operation/explain/op_msg.rb +6 -0
  38. data/lib/mongo/operation/explain/result.rb +3 -0
  39. data/lib/mongo/operation/find/legacy/result.rb +2 -0
  40. data/lib/mongo/operation/find/result.rb +3 -0
  41. data/lib/mongo/operation/get_more/result.rb +3 -0
  42. data/lib/mongo/operation/indexes/result.rb +5 -0
  43. data/lib/mongo/operation/insert/bulk_result.rb +5 -0
  44. data/lib/mongo/operation/insert/result.rb +5 -0
  45. data/lib/mongo/operation/list_collections/result.rb +5 -0
  46. data/lib/mongo/operation/map_reduce/result.rb +10 -0
  47. data/lib/mongo/operation/parallel_scan/command.rb +2 -1
  48. data/lib/mongo/operation/parallel_scan/result.rb +4 -0
  49. data/lib/mongo/operation/result.rb +35 -6
  50. data/lib/mongo/operation/shared/bypass_document_validation.rb +1 -0
  51. data/lib/mongo/operation/shared/causal_consistency_supported.rb +1 -0
  52. data/lib/mongo/operation/shared/collections_info_or_list_collections.rb +2 -0
  53. data/lib/mongo/operation/shared/executable.rb +1 -0
  54. data/lib/mongo/operation/shared/idable.rb +2 -1
  55. data/lib/mongo/operation/shared/limited.rb +1 -0
  56. data/lib/mongo/operation/shared/object_id_generator.rb +1 -0
  57. data/lib/mongo/operation/shared/read_preference_supported.rb +36 -38
  58. data/lib/mongo/operation/shared/result/aggregatable.rb +1 -0
  59. data/lib/mongo/operation/shared/sessions_supported.rb +3 -3
  60. data/lib/mongo/operation/shared/specifiable.rb +1 -0
  61. data/lib/mongo/operation/shared/write.rb +1 -0
  62. data/lib/mongo/operation/shared/write_concern_supported.rb +1 -0
  63. data/lib/mongo/operation/update/legacy/result.rb +7 -0
  64. data/lib/mongo/operation/update/result.rb +8 -0
  65. data/lib/mongo/operation/users_info/result.rb +3 -0
  66. data/lib/mongo/operation.rb +2 -0
  67. data/lib/mongo/protocol/msg.rb +2 -2
  68. data/lib/mongo/protocol/query.rb +11 -11
  69. data/lib/mongo/query_cache.rb +242 -0
  70. data/lib/mongo/retryable.rb +8 -1
  71. data/lib/mongo/server/connection_common.rb +2 -2
  72. data/lib/mongo/server/connection_pool.rb +3 -0
  73. data/lib/mongo/server/monitor/connection.rb +3 -3
  74. data/lib/mongo/server/monitor.rb +1 -1
  75. data/lib/mongo/server/pending_connection.rb +2 -2
  76. data/lib/mongo/server/push_monitor.rb +1 -1
  77. data/lib/mongo/server.rb +5 -1
  78. data/lib/mongo/server_selector/base.rb +5 -1
  79. data/lib/mongo/server_selector/secondary_preferred.rb +7 -2
  80. data/lib/mongo/session.rb +3 -0
  81. data/lib/mongo/socket/ocsp_cache.rb +97 -0
  82. data/lib/mongo/socket/ocsp_verifier.rb +368 -0
  83. data/lib/mongo/socket/ssl.rb +45 -24
  84. data/lib/mongo/socket.rb +6 -4
  85. data/lib/mongo/srv/monitor.rb +7 -13
  86. data/lib/mongo/srv/resolver.rb +14 -10
  87. data/lib/mongo/timeout.rb +2 -0
  88. data/lib/mongo/uri/options_mapper.rb +582 -0
  89. data/lib/mongo/uri/srv_protocol.rb +3 -2
  90. data/lib/mongo/uri.rb +21 -390
  91. data/lib/mongo/utils.rb +12 -1
  92. data/lib/mongo/version.rb +1 -1
  93. data/lib/mongo.rb +9 -0
  94. data/spec/NOTES.aws-auth.md +12 -7
  95. data/spec/README.md +56 -1
  96. data/spec/integration/bson_symbol_spec.rb +2 -4
  97. data/spec/integration/bulk_write_spec.rb +48 -0
  98. data/spec/integration/client_authentication_options_spec.rb +55 -28
  99. data/spec/integration/connection_pool_populator_spec.rb +3 -1
  100. data/spec/integration/cursor_reaping_spec.rb +53 -17
  101. data/spec/integration/ocsp_connectivity_spec.rb +26 -0
  102. data/spec/integration/ocsp_verifier_cache_spec.rb +188 -0
  103. data/spec/integration/ocsp_verifier_spec.rb +334 -0
  104. data/spec/integration/query_cache_spec.rb +1045 -0
  105. data/spec/integration/query_cache_transactions_spec.rb +179 -0
  106. data/spec/integration/retryable_writes/retryable_writes_40_and_newer_spec.rb +1 -0
  107. data/spec/integration/retryable_writes/shared/performs_legacy_retries.rb +2 -0
  108. data/spec/integration/sdam_error_handling_spec.rb +69 -18
  109. data/spec/integration/sdam_events_spec.rb +7 -8
  110. data/spec/integration/server_selection_spec.rb +36 -0
  111. data/spec/integration/srv_monitoring_spec.rb +38 -3
  112. data/spec/integration/srv_spec.rb +56 -0
  113. data/spec/lite_spec_helper.rb +4 -2
  114. data/spec/mongo/address_spec.rb +1 -1
  115. data/spec/mongo/caching_cursor_spec.rb +70 -0
  116. data/spec/mongo/client_construction_spec.rb +54 -1
  117. data/spec/mongo/client_encryption_spec.rb +10 -16
  118. data/spec/mongo/client_spec.rb +40 -0
  119. data/spec/mongo/cluster/topology/single_spec.rb +14 -5
  120. data/spec/mongo/cluster_spec.rb +3 -0
  121. data/spec/mongo/collection/view/explainable_spec.rb +87 -4
  122. data/spec/mongo/collection/view/map_reduce_spec.rb +2 -0
  123. data/spec/mongo/collection_spec.rb +60 -0
  124. data/spec/mongo/crypt/auto_decryption_context_spec.rb +1 -1
  125. data/spec/mongo/crypt/auto_encryption_context_spec.rb +1 -1
  126. data/spec/mongo/crypt/data_key_context_spec.rb +1 -1
  127. data/spec/mongo/crypt/explicit_decryption_context_spec.rb +1 -1
  128. data/spec/mongo/crypt/explicit_encryption_context_spec.rb +1 -1
  129. data/spec/mongo/database_spec.rb +44 -64
  130. data/spec/mongo/error/no_server_available_spec.rb +1 -1
  131. data/spec/mongo/index/view_spec.rb +2 -4
  132. data/spec/mongo/logger_spec.rb +13 -11
  133. data/spec/mongo/operation/read_preference_legacy_spec.rb +19 -9
  134. data/spec/mongo/operation/read_preference_op_msg_spec.rb +3 -3
  135. data/spec/mongo/query_cache_spec.rb +279 -0
  136. data/spec/mongo/server/app_metadata_shared.rb +7 -33
  137. data/spec/mongo/server/connection_pool_spec.rb +7 -3
  138. data/spec/mongo/server/connection_spec.rb +14 -7
  139. data/spec/mongo/server_selector/secondary_preferred_spec.rb +6 -6
  140. data/spec/mongo/socket/ssl_spec.rb +1 -1
  141. data/spec/mongo/socket_spec.rb +1 -1
  142. data/spec/mongo/uri/srv_protocol_spec.rb +64 -33
  143. data/spec/mongo/uri_option_parsing_spec.rb +11 -11
  144. data/spec/mongo/uri_spec.rb +68 -41
  145. data/spec/mongo/utils_spec.rb +39 -0
  146. data/spec/runners/auth.rb +3 -0
  147. data/spec/runners/connection_string.rb +35 -124
  148. data/spec/runners/transactions/operation.rb +2 -13
  149. data/spec/spec_tests/cmap_spec.rb +7 -3
  150. data/spec/spec_tests/data/change_streams/change-streams-errors.yml +0 -1
  151. data/spec/spec_tests/data/change_streams/change-streams.yml +0 -1
  152. data/spec/spec_tests/data/cmap/pool-checkout-connection.yml +6 -2
  153. data/spec/spec_tests/data/cmap/pool-create-min-size.yml +3 -0
  154. data/spec/spec_tests/data/connection_string/valid-warnings.yml +24 -0
  155. data/spec/spec_tests/data/sdam_monitoring/discovered_standalone.yml +1 -3
  156. data/spec/spec_tests/data/sdam_monitoring/standalone.yml +2 -2
  157. data/spec/spec_tests/data/sdam_monitoring/standalone_repeated.yml +2 -2
  158. data/spec/spec_tests/data/sdam_monitoring/standalone_suppress_equal_description_changes.yml +2 -2
  159. data/spec/spec_tests/data/sdam_monitoring/standalone_to_rs_with_me_mismatch.yml +2 -2
  160. data/spec/spec_tests/data/uri_options/auth-options.yml +25 -0
  161. data/spec/spec_tests/data/uri_options/compression-options.yml +6 -3
  162. data/spec/spec_tests/data/uri_options/read-preference-options.yml +24 -0
  163. data/spec/spec_tests/data/uri_options/ruby-connection-options.yml +1 -0
  164. data/spec/spec_tests/data/uri_options/tls-options.yml +160 -4
  165. data/spec/spec_tests/dns_seedlist_discovery_spec.rb +9 -1
  166. data/spec/spec_tests/uri_options_spec.rb +31 -33
  167. data/spec/support/certificates/atlas-ocsp-ca.crt +28 -0
  168. data/spec/support/certificates/atlas-ocsp.crt +41 -0
  169. data/spec/support/client_registry.rb +4 -8
  170. data/spec/support/client_registry_macros.rb +4 -4
  171. data/spec/support/common_shortcuts.rb +45 -0
  172. data/spec/support/constraints.rb +23 -0
  173. data/spec/support/lite_constraints.rb +24 -0
  174. data/spec/support/matchers.rb +16 -0
  175. data/spec/support/ocsp +1 -0
  176. data/spec/support/session_registry.rb +52 -0
  177. data/spec/support/spec_config.rb +22 -12
  178. data/spec/support/spec_setup.rb +38 -48
  179. data/spec/support/utils.rb +19 -1
  180. data.tar.gz.sig +1 -3
  181. metadata +938 -933
  182. metadata.gz.sig +0 -0
  183. data/spec/integration/secondary_reads_spec.rb +0 -102
  184. data/spec/shared/LICENSE +0 -20
  185. data/spec/shared/bin/get-mongodb-download-url +0 -17
  186. data/spec/shared/lib/mrss/child_process_helper.rb +0 -80
  187. data/spec/shared/lib/mrss/cluster_config.rb +0 -221
  188. data/spec/shared/lib/mrss/constraints.rb +0 -346
  189. data/spec/shared/lib/mrss/docker_runner.rb +0 -265
  190. data/spec/shared/lib/mrss/lite_constraints.rb +0 -191
  191. data/spec/shared/lib/mrss/server_version_registry.rb +0 -115
  192. data/spec/shared/lib/mrss/spec_organizer.rb +0 -152
  193. data/spec/shared/lib/mrss/utils.rb +0 -15
  194. data/spec/shared/share/Dockerfile.erb +0 -231
  195. data/spec/shared/shlib/distro.sh +0 -73
  196. data/spec/shared/shlib/server.sh +0 -290
  197. data/spec/shared/shlib/set_env.sh +0 -128
@@ -0,0 +1,179 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'QueryCache with transactions' do
4
+ around do |spec|
5
+ Mongo::QueryCache.clear
6
+ Mongo::QueryCache.cache { spec.run }
7
+ end
8
+
9
+ before do
10
+ authorized_collection.delete_many
11
+ subscriber.clear_events!
12
+ end
13
+
14
+ # These tests do not currently use the session registry because transactions
15
+ # leak sessions independently of the query cache. This will be resolved by
16
+ # RUBY-2391.
17
+
18
+ let(:subscriber) { EventSubscriber.new }
19
+
20
+ let(:client) do
21
+ authorized_client.tap do |client|
22
+ client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
23
+ end
24
+ end
25
+
26
+ let(:authorized_collection) { client['collection_spec'] }
27
+
28
+ describe 'in transactions' do
29
+ require_transaction_support
30
+ require_wired_tiger
31
+
32
+ let(:collection) { authorized_client['test'] }
33
+
34
+ let(:events) do
35
+ subscriber.command_started_events('find')
36
+ end
37
+
38
+ before do
39
+ Utils.create_collection(authorized_client, 'test')
40
+ end
41
+
42
+ context 'with convenient API' do
43
+ context 'when same query is performed inside and outside of transaction' do
44
+ it 'performs one query' do
45
+ collection.find.to_a
46
+
47
+ session = authorized_client.start_session
48
+ session.with_transaction do
49
+ collection.find({}, session: session).to_a
50
+ end
51
+
52
+ expect(subscriber.command_started_events('find').length).to eq(1)
53
+ end
54
+ end
55
+
56
+ context 'when transaction has a different read concern' do
57
+ it 'performs two queries' do
58
+ collection.find.to_a
59
+
60
+ session = authorized_client.start_session
61
+ session.with_transaction(
62
+ read_concern: { level: :snapshot }
63
+ ) do
64
+ collection.find({}, session: session).to_a
65
+ end
66
+
67
+ expect(subscriber.command_started_events('find').length).to eq(2)
68
+ end
69
+ end
70
+
71
+ context 'when transaction has a different read preference' do
72
+ it 'performs two queries' do
73
+ collection.find.to_a
74
+
75
+ session = authorized_client.start_session
76
+ session.with_transaction(
77
+ read: { mode: :primary }
78
+ ) do
79
+ collection.find({}, session: session).to_a
80
+ end
81
+
82
+ expect(subscriber.command_started_events('find').length).to eq(2)
83
+ end
84
+ end
85
+
86
+ context 'when transaction is committed' do
87
+ it 'clears the cache' do
88
+ session = authorized_client.start_session
89
+ session.with_transaction do
90
+ collection.insert_one({ test: 1 }, session: session)
91
+ collection.insert_one({ test: 2 }, session: session)
92
+
93
+ expect(collection.find({}, session: session).to_a.length).to eq(2)
94
+ expect(collection.find({}, session: session).to_a.length).to eq(2)
95
+
96
+ # The driver caches the queries within the transaction
97
+ expect(subscriber.command_started_events('find').length).to eq(1)
98
+ session.commit_transaction
99
+ end
100
+
101
+ expect(collection.find.to_a.length).to eq(2)
102
+
103
+ # The driver clears the cache and runs the query again
104
+ expect(subscriber.command_started_events('find').length).to eq(2)
105
+ end
106
+ end
107
+
108
+ context 'when transaction is aborted' do
109
+ it 'clears the cache' do
110
+ session = authorized_client.start_session
111
+ session.with_transaction do
112
+ collection.insert_one({ test: 1 }, session: session)
113
+ collection.insert_one({ test: 2 }, session: session)
114
+
115
+ expect(collection.find({}, session: session).to_a.length).to eq(2)
116
+ expect(collection.find({}, session: session).to_a.length).to eq(2)
117
+
118
+ # The driver caches the queries within the transaction
119
+ expect(subscriber.command_started_events('find').length).to eq(1)
120
+ session.abort_transaction
121
+ end
122
+
123
+ expect(collection.find.to_a.length).to eq(0)
124
+
125
+ # The driver clears the cache and runs the query again
126
+ expect(subscriber.command_started_events('find').length).to eq(2)
127
+ end
128
+ end
129
+ end
130
+
131
+ context 'with low-level API' do
132
+ context 'when transaction is committed' do
133
+ it 'clears the cache' do
134
+ session = authorized_client.start_session
135
+ session.start_transaction
136
+
137
+ collection.insert_one({ test: 1 }, session: session)
138
+ collection.insert_one({ test: 2 }, session: session)
139
+
140
+ expect(collection.find({}, session: session).to_a.length).to eq(2)
141
+ expect(collection.find({}, session: session).to_a.length).to eq(2)
142
+
143
+ # The driver caches the queries within the transaction
144
+ expect(subscriber.command_started_events('find').length).to eq(1)
145
+
146
+ session.commit_transaction
147
+
148
+ expect(collection.find.to_a.length).to eq(2)
149
+
150
+ # The driver clears the cache and runs the query again
151
+ expect(subscriber.command_started_events('find').length).to eq(2)
152
+ end
153
+ end
154
+
155
+ context 'when transaction is aborted' do
156
+ it 'clears the cache' do
157
+ session = authorized_client.start_session
158
+ session.start_transaction
159
+
160
+ collection.insert_one({ test: 1 }, session: session)
161
+ collection.insert_one({ test: 2 }, session: session)
162
+
163
+ expect(collection.find({}, session: session).to_a.length).to eq(2)
164
+ expect(collection.find({}, session: session).to_a.length).to eq(2)
165
+
166
+ # The driver caches the queries within the transaction
167
+ expect(subscriber.command_started_events('find').length).to eq(1)
168
+
169
+ session.abort_transaction
170
+
171
+ expect(collection.find.to_a.length).to eq(0)
172
+
173
+ # The driver clears the cache and runs the query again
174
+ expect(subscriber.command_started_events('find').length).to eq(2)
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
@@ -8,6 +8,7 @@ describe 'Retryable Writes' do
8
8
  require_fail_command
9
9
  require_wired_tiger
10
10
  require_no_multi_shard
11
+ require_warning_clean
11
12
 
12
13
  let(:client) do
13
14
  authorized_client.with(
@@ -2,6 +2,8 @@ require_relative './adds_diagnostics'
2
2
 
3
3
  module PerformsLegacyRetries
4
4
  shared_examples 'it performs legacy retries' do
5
+ require_warning_clean
6
+
5
7
  context 'for connection error' do
6
8
  before do
7
9
  client.use('admin').command(
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'SDAM error handling' do
4
- clean_slate
4
+ clean_slate_for_all
5
5
 
6
6
  after do
7
7
  # Close all clients after every test to avoid leaking expectations into
@@ -19,7 +19,6 @@ describe 'SDAM error handling' do
19
19
  new_local_client(SpecConfig.instance.addresses,
20
20
  SpecConfig.instance.all_test_options.merge(
21
21
  socket_timeout: 3, connect_timeout: 3,
22
- heartbeat_frequency: 100,
23
22
  # Uncomment to print all events to stdout:
24
23
  #sdam_proc: Utils.subscribe_all_sdam_proc(diagnostic_subscriber),
25
24
  **Utils.disable_retries_client_options)
@@ -29,14 +28,6 @@ describe 'SDAM error handling' do
29
28
  let(:server) { client.cluster.next_primary }
30
29
 
31
30
  shared_examples_for 'marks server unknown' do
32
- before do
33
- server.monitor.stop!
34
- end
35
-
36
- after do
37
- client.close
38
- end
39
-
40
31
  it 'marks server unknown' do
41
32
  expect(server).not_to be_unknown
42
33
  RSpec::Mocks.with_temporary_scope do
@@ -47,14 +38,6 @@ describe 'SDAM error handling' do
47
38
  end
48
39
 
49
40
  shared_examples_for 'does not mark server unknown' do
50
- before do
51
- server.monitor.stop!
52
- end
53
-
54
- after do
55
- client.close
56
- end
57
-
58
41
  it 'does not mark server unknown' do
59
42
  expect(server).not_to be_unknown
60
43
  RSpec::Mocks.with_temporary_scope do
@@ -214,6 +197,74 @@ describe 'SDAM error handling' do
214
197
  end
215
198
  end
216
199
 
200
+ describe 'when there is an error during connection establishment' do
201
+ require_topology :single
202
+
203
+ # The push monitor creates sockets unpredictably and interferes with this
204
+ # test.
205
+ max_server_version '4.2'
206
+
207
+ # When TLS is used there are two socket classes and we can't simply
208
+ # mock the base Socket class.
209
+ require_no_tls
210
+
211
+ {
212
+ SystemCallError => Mongo::Error::SocketError,
213
+ Errno::ETIMEDOUT => Mongo::Error::SocketTimeoutError,
214
+ }.each do |raw_error_cls, mapped_error_cls|
215
+ context raw_error_cls.name do
216
+ let(:socket) do
217
+ double('mock socket').tap do |socket|
218
+ allow(socket).to receive(:set_encoding)
219
+ allow(socket).to receive(:setsockopt)
220
+ allow(socket).to receive(:getsockopt)
221
+ allow(socket).to receive(:connect)
222
+ allow(socket).to receive(:close)
223
+ socket.should receive(:write).and_raise(raw_error_cls, 'mocked failure')
224
+ end
225
+ end
226
+
227
+ it 'marks server unknown' do
228
+ server = client.cluster.next_primary
229
+ client.cluster.servers.map(&:disconnect!)
230
+
231
+ RSpec::Mocks.with_temporary_scope do
232
+
233
+ Socket.should receive(:new).with(any_args).ordered.once.and_return(socket)
234
+
235
+ lambda do
236
+ client.command(ping: 1)
237
+ end.should raise_error(mapped_error_cls, /mocked failure/)
238
+
239
+ server.should be_unknown
240
+ end
241
+ end
242
+
243
+ it 'recovers' do
244
+ server = client.cluster.next_primary
245
+ # If we do not kill the monitor, the client will recover automatically.
246
+
247
+ RSpec::Mocks.with_temporary_scope do
248
+
249
+ Socket.should receive(:new).with(any_args).ordered.once.and_return(socket)
250
+ Socket.should receive(:new).with(any_args).ordered.once.and_call_original
251
+
252
+ lambda do
253
+ client.command(ping: 1)
254
+ end.should raise_error(mapped_error_cls, /mocked failure/)
255
+
256
+ client.command(ping: 1)
257
+ end
258
+ end
259
+ end
260
+ end
261
+
262
+ after do
263
+ # Since we stopped monitoring on the client, close it.
264
+ ClientRegistry.instance.close_all_clients
265
+ end
266
+ end
267
+
217
268
  describe 'when there is an error on monitoring connection' do
218
269
  clean_slate_for_all
219
270
 
@@ -67,8 +67,9 @@ describe 'SDAM events' do
67
67
  started_events.length.should <= 10
68
68
 
69
69
  succeeded_events = subscriber.select_succeeded_events(Mongo::Monitoring::Event::ServerHeartbeatSucceeded)
70
- started_events.length.should > 1
71
- (succeeded_events.length..succeeded_events.length+1).should include(started_events.length)
70
+ # Since we gracefully close the client, we expect each heartbeat
71
+ # to complete.
72
+ started_events.length.should == succeeded_events.length
72
73
  end
73
74
  end
74
75
 
@@ -104,12 +105,10 @@ describe 'SDAM events' do
104
105
  (succeeded_awaited = events.select(&:awaited?)).should_not be_empty
105
106
  (succeeded_regular = events.reject(&:awaited?)).should_not be_empty
106
107
 
107
- # There may be in-flight ismasters that don't complete, both
108
- # regular and awaited.
109
- started_awaited.length.should > 1
110
- (succeeded_awaited.length..succeeded_awaited.length+1).should include(started_awaited.length)
111
- started_regular.length.should > 1
112
- (succeeded_regular.length..succeeded_regular.length+1).should include(started_regular.length)
108
+ # Since we gracefully close the client, we expect each heartbeat
109
+ # to complete.
110
+ started_awaited.length.should == succeeded_awaited.length
111
+ started_regular.length.should == succeeded_regular.length
113
112
  end
114
113
  end
115
114
  end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Server selection' do
4
+ context 'replica set' do
5
+ require_topology :replica_set
6
+ # 2.6 server does not provide replSetGetConfig and hence we cannot add
7
+ # the tags to the members.
8
+ min_server_version '3.0'
9
+
10
+ context 'when mixed case tag names are used' do
11
+ # For simplicity this test assumes our Evergreen configuration:
12
+ # nodes are started from port 27017 onwards and there are more than
13
+ # one of them.
14
+
15
+ let(:desired_index) do
16
+ if authorized_client.cluster.next_primary.address.port == 27017
17
+ 1
18
+ else
19
+ 0
20
+ end
21
+ end
22
+
23
+ let(:client) do
24
+ new_local_client(SpecConfig.instance.addresses,
25
+ SpecConfig.instance.authorized_test_options.merge(
26
+ server_selection_timeout: 4,
27
+ read: {mode: :secondary, tag_sets: [nodeIndex: desired_index.to_s]},
28
+ ))
29
+ end
30
+
31
+ it 'selects the server' do
32
+ client['nonexistent'].count.should == 0
33
+ end
34
+ end
35
+ end
36
+ end
@@ -76,6 +76,37 @@ describe 'SRV Monitoring' do
76
76
  require 'support/dns'
77
77
  end
78
78
 
79
+ around do |example|
80
+ # Speed up the tests by listening on the fake ports we are using.
81
+ done = false
82
+
83
+ servers = []
84
+ threads = [27998, 27999].map do |port|
85
+ Thread.new do
86
+ server = TCPServer.open(port)
87
+ servers << server
88
+ begin
89
+ loop do
90
+ break if done
91
+ server.accept.close rescue nil
92
+ end
93
+ ensure
94
+ server.close
95
+ end
96
+ end
97
+ end
98
+
99
+ begin
100
+ example.run
101
+ ensure
102
+ done = true
103
+ servers.map(&:close)
104
+
105
+ threads.map(&:kill)
106
+ threads.map(&:join)
107
+ end
108
+ end
109
+
79
110
  let(:uri) do
80
111
  "mongodb+srv://test-fake.test.build.10gen.cc/?tls=#{SpecConfig.instance.ssl?}&tlsInsecure=true"
81
112
  end
@@ -88,11 +119,15 @@ describe 'SRV Monitoring' do
88
119
  new_local_client(uri,
89
120
  SpecConfig.instance.ssl_options.merge(
90
121
  server_selection_timeout: 3.16,
91
- timeout: 8.11,
122
+ socket_timeout: 8.11,
92
123
  connect_timeout: 8.12,
93
124
  resolv_options: {
94
- nameserver: 'localhost',
95
- nameserver_port: [['localhost', 5300], ['127.0.0.1', 5300]],
125
+ # Using localhost instead of 127.0.0.1 here causes Ruby's resolv
126
+ # client to drop responses.
127
+ nameserver: '127.0.0.1',
128
+ # TODO figure out why the address & port here need to be given
129
+ # twice - if given once, DNS resolution fails.
130
+ nameserver_port: [['127.0.0.1', 5300], ['127.0.0.1', 5300]],
96
131
  },
97
132
  logger: logger,
98
133
  ),
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'SRV lookup' do
4
+ context 'end to end' do
5
+
6
+ # JRuby apparently does not implement non-blocking UDP I/O which is used
7
+ # by RubyDNS:
8
+ # NotImplementedError: recvmsg_nonblock is not implemented
9
+ fails_on_jruby
10
+
11
+ before(:all) do
12
+ require 'support/dns'
13
+ end
14
+
15
+ let(:uri) do
16
+ "mongodb+srv://test-fake.test.build.10gen.cc/?tls=#{SpecConfig.instance.ssl?}&tlsInsecure=true"
17
+ end
18
+
19
+ let(:client) do
20
+ new_local_client(uri,
21
+ SpecConfig.instance.ssl_options.merge(
22
+ server_selection_timeout: 3.16,
23
+ timeout: 4.11,
24
+ connect_timeout: 4.12,
25
+ resolv_options: {
26
+ nameserver: 'localhost',
27
+ nameserver_port: [['localhost', 5300], ['127.0.0.1', 5300]],
28
+ },
29
+ ),
30
+ )
31
+ end
32
+
33
+ context 'DNS resolver not responding' do
34
+ it 'fails to create client' do
35
+ lambda do
36
+ client
37
+ end.should raise_error(Mongo::Error::NoSRVRecords, /The DNS query returned no SRV records for 'test-fake.test.build.10gen.cc'/)
38
+ end
39
+
40
+ it 'times out in connect_timeout' do
41
+ start_time = Time.now
42
+
43
+ lambda do
44
+ client
45
+ end.should raise_error(Mongo::Error::NoSRVRecords)
46
+
47
+ elapsed_time = Time.now - start_time
48
+ elapsed_time.should > 4
49
+ # The number of queries performed depends on local DNS search suffixes,
50
+ # therefore we cannot reliably assert how long it would take for this
51
+ # resolution to time out.
52
+ #elapsed_time.should < 8
53
+ end
54
+ end
55
+ end
56
+ end
@@ -49,6 +49,7 @@ end
49
49
  autoload :Benchmark, 'benchmark'
50
50
  autoload :IceNine, 'ice_nine'
51
51
  autoload :Timecop, 'timecop'
52
+ autoload :ChildProcess, 'childprocess'
52
53
 
53
54
  if BSON::Environment.jruby?
54
55
  require 'concurrent-ruby'
@@ -60,7 +61,7 @@ end
60
61
  require 'support/utils'
61
62
  require 'support/spec_config'
62
63
 
63
- Mongo::Logger.logger = Logger.new($stdout)
64
+ Mongo::Logger.logger = Logger.new(STDOUT)
64
65
  unless SpecConfig.instance.client_debug?
65
66
  Mongo::Logger.logger.level = Logger::INFO
66
67
  end
@@ -76,6 +77,7 @@ require 'support/crypt'
76
77
  require 'support/json_ext_formatter'
77
78
  require 'support/sdam_formatter_integration'
78
79
  require 'support/background_thread_registry'
80
+ require 'support/session_registry'
79
81
 
80
82
  if SpecConfig.instance.mri?
81
83
  require 'timeout_interrupt'
@@ -104,7 +106,7 @@ RSpec.configure do |config|
104
106
  end
105
107
  end
106
108
 
107
- if SpecConfig.instance.ci? && !%w(1 true yes).include?(ENV['INTERACTIVE']&.downcase)
109
+ if SpecConfig.instance.ci?
108
110
  # Allow a max of 30 seconds per test.
109
111
  # Tests should take under 10 seconds ideally but it seems
110
112
  # we have some that run for more than 10 seconds in CI.
@@ -234,7 +234,7 @@ describe Mongo::Address do
234
234
  end
235
235
 
236
236
  let(:address) do
237
- Mongo::Address.new(custom_hostname)
237
+ Mongo::Address.new("#{custom_hostname}:#{SpecConfig.instance.any_port}")
238
238
  end
239
239
 
240
240
  before do
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::CachingCursor do
4
+
5
+ around do |spec|
6
+ Mongo::QueryCache.clear
7
+ Mongo::QueryCache.cache { spec.run }
8
+ end
9
+
10
+ let(:authorized_collection) do
11
+ authorized_client['caching_cursor']
12
+ end
13
+
14
+ before do
15
+ authorized_collection.drop
16
+ end
17
+
18
+ let(:server) do
19
+ view.send(:server_selector).select_server(authorized_client.cluster)
20
+ end
21
+
22
+ let(:reply) do
23
+ view.send(:send_initial_query, server)
24
+ end
25
+
26
+ let(:cursor) do
27
+ described_class.new(view, reply, server)
28
+ end
29
+
30
+ let(:view) do
31
+ Mongo::Collection::View.new(authorized_collection)
32
+ end
33
+
34
+ before do
35
+ authorized_collection.delete_many
36
+ 3.times { |i| authorized_collection.insert_one(_id: i) }
37
+ end
38
+
39
+ describe '#cached_docs' do
40
+ context 'when no query has been performed' do
41
+ it 'returns nil' do
42
+ expect(cursor.cached_docs).to be_nil
43
+ end
44
+ end
45
+
46
+ context 'when a query has been performed' do
47
+ it 'returns the number of documents' do
48
+ cursor.to_a
49
+ expect(cursor.cached_docs.length).to eq(3)
50
+ expect(cursor.cached_docs).to eq([{ '_id' => 0 }, { '_id' => 1 }, { '_id' => 2 }])
51
+ end
52
+ end
53
+ end
54
+
55
+ describe '#try_next' do
56
+ it 'fetches the next document' do
57
+ expect(cursor.try_next).to eq('_id' => 0)
58
+ expect(cursor.try_next).to eq('_id' => 1)
59
+ expect(cursor.try_next).to eq('_id' => 2)
60
+ end
61
+ end
62
+
63
+ describe '#each' do
64
+ it 'iterates the cursor' do
65
+ result = cursor.each.to_a
66
+ expect(result.length).to eq(3)
67
+ expect(result).to eq([{ '_id' => 0 }, { '_id' => 1 }, { '_id' => 2 }])
68
+ end
69
+ end
70
+ end
@@ -496,6 +496,7 @@ describe Mongo::Client do
496
496
  end
497
497
 
498
498
  context 'when the compressor is not supported by the driver' do
499
+ require_warning_clean
499
500
 
500
501
  let(:options) do
501
502
  { compressors: ['snoopy'] }
@@ -674,7 +675,7 @@ describe Mongo::Client do
674
675
  context 'when providing a custom logger' do
675
676
 
676
677
  let(:logger) do
677
- Logger.new($stdout).tap do |l|
678
+ Logger.new(STDOUT).tap do |l|
678
679
  l.level = Logger::FATAL
679
680
  end
680
681
  end
@@ -1343,6 +1344,46 @@ describe Mongo::Client do
1343
1344
  end
1344
1345
  end
1345
1346
 
1347
+ context 'when setting read concern options' do
1348
+ min_server_fcv '3.2'
1349
+
1350
+ context 'when read concern is valid' do
1351
+ let(:options) do
1352
+ { read_concern: { level: :local } }
1353
+ end
1354
+
1355
+ it 'does not warn' do
1356
+ expect(Mongo::Logger.logger).to_not receive(:warn)
1357
+ new_local_client_nmio(SpecConfig.instance.addresses, options)
1358
+ end
1359
+ end
1360
+
1361
+ context 'when read concern has an invalid key' do
1362
+ skip_if_linting
1363
+
1364
+ let(:options) do
1365
+ { read_concern: { hello: :local } }
1366
+ end
1367
+
1368
+ it 'logs a warning' do
1369
+ expect(Mongo::Logger.logger).to receive(:warn).with(/Read concern has invalid keys: hello/)
1370
+ new_local_client_nmio(SpecConfig.instance.addresses, options)
1371
+ end
1372
+ end
1373
+
1374
+ context 'when read concern has a non-user-settable key' do
1375
+ let(:options) do
1376
+ { read_concern: { after_cluster_time: 100 } }
1377
+ end
1378
+
1379
+ it 'raises an exception' do
1380
+ expect do
1381
+ new_local_client_nmio(SpecConfig.instance.addresses, options)
1382
+ end.to raise_error(Mongo::Error::InvalidReadConcern, 'The after_cluster_time read_concern option cannot be specified by the user')
1383
+ end
1384
+ end
1385
+ end
1386
+
1346
1387
  context 'when an invalid option is provided' do
1347
1388
 
1348
1389
  let(:options) do
@@ -1494,6 +1535,18 @@ describe Mongo::Client do
1494
1535
  end
1495
1536
  end
1496
1537
  end
1538
+
1539
+ context ':auth_mech_properties option' do
1540
+ context 'is nil' do
1541
+ let(:options) do
1542
+ {auth_mech_properties: nil}
1543
+ end
1544
+
1545
+ it 'creates the client without the option' do
1546
+ client.options.should_not have_key(:auth_mech_properties)
1547
+ end
1548
+ end
1549
+ end
1497
1550
  end
1498
1551
 
1499
1552
  context 'when making a block client' do