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
@@ -1,6 +1,45 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Mongo::URI do
4
+
5
+ describe '.get' do
6
+
7
+ let(:uri) { described_class.get(string) }
8
+
9
+ context 'when the scheme is mongodb://' do
10
+
11
+ let(:string) do
12
+ 'mongodb://localhost:27017'
13
+ end
14
+
15
+ it 'returns a Mongo::URI object' do
16
+ expect(uri).to be_a(Mongo::URI)
17
+ end
18
+ end
19
+
20
+ context 'when the scheme is mongodb+srv://' do
21
+
22
+ let(:string) do
23
+ 'mongodb+srv://test5.test.build.10gen.cc'
24
+ end
25
+
26
+ it 'returns a Mongo::URI::SRVProtocol object' do
27
+ expect(uri).to be_a(Mongo::URI::SRVProtocol)
28
+ end
29
+ end
30
+
31
+ context 'when the scheme is invalid' do
32
+
33
+ let(:string) do
34
+ 'mongo://localhost:27017'
35
+ end
36
+
37
+ it 'raises an exception' do
38
+ expect { uri }.to raise_error(Mongo::Error::InvalidURI)
39
+ end
40
+ end
41
+ end
42
+
4
43
  let(:scheme) { 'mongodb://' }
5
44
  let(:uri) { described_class.new(string) }
6
45
 
@@ -263,7 +302,7 @@ describe Mongo::URI do
263
302
  let(:servers) { '%2Ftmp%2Fmongodb-27017.sock' }
264
303
 
265
304
  it 'returns an array with the parsed server' do
266
- expect(uri.servers).to eq([servers])
305
+ expect(uri.servers).to eq([URI.unescape(servers)])
267
306
  end
268
307
  end
269
308
 
@@ -301,11 +340,11 @@ describe Mongo::URI do
301
340
  expect(options[:database]).to eq(TEST_DB)
302
341
  end
303
342
 
304
- it 'includes the credentials in the options' do
343
+ it 'includes the user in the options' do
305
344
  expect(options[:user]).to eq(user)
306
345
  end
307
346
 
308
- it 'includes the options in the options' do
347
+ it 'includes the password in the options' do
309
348
  expect(options[:password]).to eq(password)
310
349
  end
311
350
  end
@@ -2,6 +2,17 @@ require 'spec_helper'
2
2
 
3
3
  describe Mongo::WriteConcern::Acknowledged do
4
4
 
5
+ describe '#acknowledged?' do
6
+
7
+ let(:concern) do
8
+ described_class.new(:w => :majority)
9
+ end
10
+
11
+ it 'returns true' do
12
+ expect(concern.acknowledged?).to be(true)
13
+ end
14
+ end
15
+
5
16
  describe '#get_last_error' do
6
17
 
7
18
  let(:get_last_error) do
@@ -12,4 +12,15 @@ describe Mongo::WriteConcern::Unacknowledged do
12
12
  expect(concern.get_last_error).to be_nil
13
13
  end
14
14
  end
15
+
16
+ describe '#acknowledged?' do
17
+
18
+ let(:concern) do
19
+ described_class.new(:w => 0)
20
+ end
21
+
22
+ it 'returns false' do
23
+ expect(concern.acknowledged?).to be(false)
24
+ end
25
+ end
15
26
  end
data/spec/spec_helper.rb CHANGED
@@ -7,8 +7,10 @@ SERVER_SELECTION_RTT_TESTS = Dir.glob("#{CURRENT_PATH}/support/server_selection/
7
7
  SERVER_SELECTION_TESTS = Dir.glob("#{CURRENT_PATH}/support/server_selection/selection/**/*.yml")
8
8
  MAX_STALENESS_TESTS = Dir.glob("#{CURRENT_PATH}/support/max_staleness/**/*.yml")
9
9
  CRUD_TESTS = Dir.glob("#{CURRENT_PATH}/support/crud_tests/**/*.yml")
10
+ RETRYABLE_WRITES_TESTS = Dir.glob("#{CURRENT_PATH}/support/retryable_writes_tests/**/*.yml")
10
11
  COMMAND_MONITORING_TESTS = Dir.glob("#{CURRENT_PATH}/support/command_monitoring/**/*.yml")
11
12
  CONNECTION_STRING_TESTS = Dir.glob("#{CURRENT_PATH}/support/connection_string_tests/*.yml")
13
+ DNS_SEEDLIST_DISCOVERY_TESTS = Dir.glob("#{CURRENT_PATH}/support/dns_seedlist_discovery_tests/*.yml")
12
14
  GRIDFS_TESTS = Dir.glob("#{CURRENT_PATH}/support/gridfs_tests/*.yml")
13
15
 
14
16
  if ENV['DRIVERS_TOOLS']
@@ -66,13 +68,6 @@ RSpec.configure do |config|
66
68
  # databases that will be used in the test suite.
67
69
  ADMIN_AUTHORIZED_TEST_CLIENT.database.users.create(TEST_USER)
68
70
  rescue Exception => e
69
- unless write_command_enabled?
70
- # If we are on versions less than 2.6, we need to create a user for
71
- # each database, since the users are not stored in the admin database
72
- # but in the system.users collection on the databases themselves. Also,
73
- # roles in versions lower than 2.6 can only be strings, not hashes.
74
- begin ADMIN_AUTHORIZED_TEST_CLIENT.database.users.create(TEST_READ_WRITE_USER); rescue; end
75
- end
76
71
  end
77
72
  end
78
73
  end
@@ -144,6 +139,15 @@ end
144
139
  alias :change_stream_enabled? :op_msg_enabled?
145
140
  alias :sessions_enabled? :op_msg_enabled?
146
141
 
142
+
143
+ # Whether sessions can be tested. Sessions are available on server versions 3.6
144
+ # and higher and when connected to a replica set or sharded cluster.
145
+ #
146
+ # @since 2.5.0
147
+ def test_sessions?
148
+ sessions_enabled? && (replica_set? || sharded?)
149
+ end
150
+
147
151
  # Whether change streams can be tested. Change streams are available on server versions 3.6
148
152
  # and higher and when connected to a replica set.
149
153
  #
@@ -180,15 +184,6 @@ def find_command_enabled?
180
184
  $find_command_enabled ||= $mongo_client.cluster.servers.first.features.find_command_enabled?
181
185
  end
182
186
 
183
- # For instances where behaviour is different on different versions, we need to
184
- # determine in the specs if we are 2.6 or higher.
185
- #
186
- # @since 2.0.0
187
- def write_command_enabled?
188
- $mongo_client ||= initialize_scanned_client!
189
- $write_command_enabled ||= $mongo_client.cluster.servers.first.features.write_command_enabled?
190
- end
191
-
192
187
  # For instances where behaviour is different on different versions, we need to
193
188
  # determine in the specs if we are 2.7 or higher.
194
189
  #
@@ -229,15 +224,6 @@ end
229
224
 
230
225
  alias :scram_sha_1_enabled? :list_command_enabled?
231
226
 
232
- # Depending on whether write commands are enabled, there are different documents that
233
- # are guaranteed to cause a delete failure.
234
- #
235
- # @since 2.0.0
236
- def failing_delete_doc
237
- write_command_enabled? ? { q: { '$set' => { a: 1 } }, limit: 0 } :
238
- { que: { field: 'test' } }
239
- end
240
-
241
227
  # Try running a command on the admin database to see if the mongod was started with auth.
242
228
  #
243
229
  # @since 2.2.0
@@ -86,7 +86,8 @@ BASE_OPTIONS = {
86
86
  heartbeat_frequency: 20,
87
87
  max_read_retries: 5,
88
88
  wait_queue_timeout: 2,
89
- connect_timeout: 3
89
+ connect_timeout: 3,
90
+ max_idle_time: 5
90
91
  }
91
92
 
92
93
  # Options for test suite clients.
@@ -156,12 +156,16 @@ module Mongo
156
156
  end
157
157
 
158
158
  def uri
159
- @uri ||= Mongo::URI.new(@spec['uri'])
159
+ @uri ||= Mongo::URI.get(@spec['uri'])
160
160
  end
161
161
 
162
162
  def auth
163
163
  @auth ||= Auth.new(@spec['auth']) if @spec['auth']
164
164
  end
165
+
166
+ def raise_error?
167
+ @spec['error']
168
+ end
165
169
  end
166
170
 
167
171
  class Host
@@ -218,9 +222,9 @@ module Mongo
218
222
  end
219
223
 
220
224
  def match?(opts)
221
- @options.keys.all? do |k|
222
- opts[MAPPINGS[k]] == @options[k] ||
223
- Mongo::URI::AUTH_MECH_MAP[@options[k]] == opts[MAPPINGS[k]]
225
+ @options.all? do |k, v|
226
+ opts[MAPPINGS[k.downcase]] == v ||
227
+ opts[MAPPINGS[k.downcase]] == Mongo::URI::AUTH_MECH_MAP[v]
224
228
  end
225
229
  end
226
230
  end
data/spec/support/crud.rb CHANGED
@@ -103,29 +103,13 @@ module Mongo
103
103
  private
104
104
 
105
105
  def upper_bound_satisfied?(client)
106
- if @max_server_version
107
- if @max_server_version < '2.6'
108
- !client.cluster.next_primary.features.write_command_enabled?
109
- end
110
- else
111
- true
112
- end
106
+ return true unless @max_server_version
107
+ client.database.command(buildInfo: 1).first['version'] <= @max_server_version
113
108
  end
114
109
 
115
110
  def lower_bound_satisfied?(client)
116
- if @min_server_version
117
- if @min_server_version >= '3.6'
118
- client.cluster.next_primary.features.array_filters_enabled?
119
- elsif @min_server_version >= '3.4'
120
- client.cluster.next_primary.features.collation_enabled?
121
- elsif @min_server_version >= '2.6'
122
- client.cluster.next_primary.features.write_command_enabled?
123
- else
124
- true
125
- end
126
- else
127
- true
128
- end
111
+ return true unless @min_server_version
112
+ @min_server_version <= client.database.command(buildInfo: 1).first['version']
129
113
  end
130
114
  end
131
115
 
@@ -141,6 +125,8 @@ module Mongo
141
125
  # @since 2.0.0
142
126
  attr_reader :description
143
127
 
128
+ FAIL_POINT_BASE_COMMAND = { configureFailPoint: "onPrimaryTransactionalWrite" }
129
+
144
130
  # Instantiate the new CRUDTest.
145
131
  #
146
132
  # @example Create the test.
@@ -153,6 +139,7 @@ module Mongo
153
139
  # @since 2.0.0
154
140
  def initialize(data, test)
155
141
  @data = data
142
+ @fail_point_command = FAIL_POINT_BASE_COMMAND.merge(test['failPoint']) if test['failPoint']
156
143
  @description = test['description']
157
144
  @operation = Operation.get(test['operation'])
158
145
  @outcome = test['outcome']
@@ -170,11 +157,27 @@ module Mongo
170
157
  #
171
158
  # @since 2.0.0
172
159
  def run(collection)
173
- @collection = collection
174
- @collection.insert_many(@data)
175
160
  @operation.execute(collection)
176
161
  end
177
162
 
163
+ def setup_test(collection)
164
+ clear_fail_point(collection)
165
+ @collection = collection
166
+ collection.delete_many
167
+ collection.insert_many(@data)
168
+ set_up_fail_point(collection)
169
+ end
170
+
171
+ def set_up_fail_point(collection)
172
+ collection.client.use(:admin).command(@fail_point_command) if @fail_point_command
173
+ end
174
+
175
+ def clear_fail_point(collection)
176
+ if @fail_point_command
177
+ collection.client.use(:admin).command(FAIL_POINT_BASE_COMMAND.merge(mode: "off"))
178
+ end
179
+ end
180
+
178
181
  # The expected result of running the test.
179
182
  #
180
183
  # @example Get the expected result of running the test.
@@ -241,6 +244,10 @@ module Mongo
241
244
  @outcome['collection']['data'] if @outcome['collection']
242
245
  end
243
246
 
247
+ def error?
248
+ !!@outcome['error']
249
+ end
250
+
244
251
  private
245
252
 
246
253
  def compare_result(expected, actual)
@@ -248,8 +255,9 @@ module Mongo
248
255
  when nil
249
256
  actual.nil?
250
257
  when Hash
251
- actual.all? do |k, v|
252
- expected[k] == v || handle_upserted_id(k, expected[k], v)
258
+ results = actual.instance_variable_get(:@results)
259
+ (results || actual).all? do |k, v|
260
+ expected[k] == v || handle_upserted_id(k, expected[k], v) || handle_inserted_ids(k, expected[k], v)
253
261
  end
254
262
  when Integer
255
263
  expected == actual
@@ -265,6 +273,12 @@ module Mongo
265
273
  end
266
274
  end
267
275
 
276
+ def handle_inserted_ids(field, expected, actual)
277
+ if field == 'insertedIds'
278
+ expected.values == actual
279
+ end
280
+ end
281
+
268
282
  def actual_collection_data
269
283
  if @outcome['collection']
270
284
  collection_name = @outcome['collection']['name'] || @collection.name
@@ -99,7 +99,15 @@ module Mongo
99
99
  private
100
100
 
101
101
  def bulk_write(collection)
102
- collection.bulk_write(requests, options)
102
+ result = collection.bulk_write(requests, options)
103
+ return_doc = {}
104
+ return_doc['deletedCount'] = result.deleted_count if result.deleted_count
105
+ return_doc['insertedIds'] = result.inserted_ids if result.inserted_ids
106
+ return_doc['upsertedId'] = result.upserted_id if upsert
107
+ return_doc['upsertedCount'] = result.upserted_count if result.upserted_count
108
+ return_doc['matchedCount'] = result.matched_count if result.matched_count
109
+ return_doc['modifiedCount'] = result.modified_count if result.modified_count
110
+ return_doc
103
111
  end
104
112
 
105
113
  def delete_many(collection)
@@ -211,17 +219,36 @@ module Mongo
211
219
  { insert_one: request['insertOne']['document'] }
212
220
  when 'updateOne' then
213
221
  update = request['updateOne']
214
- { update_one: { filter: update['filter'], update: update['update'] }}
222
+ { update_one: { filter: update['filter'], update: update['update'] } }
223
+ when 'name' then
224
+ bulk_request(request)
215
225
  end
216
226
  end
217
227
  end
218
228
 
229
+ def bulk_request(request)
230
+ op_name = OPERATIONS[request['name']]
231
+ op = { op_name => {} }
232
+ op[op_name].merge!(filter: request['arguments']['filter']) if request['arguments']['filter']
233
+ op[op_name].merge!(update: request['arguments']['update']) if request['arguments']['update']
234
+ op[op_name].merge!(upsert: request['arguments']['upsert']) if request['arguments']['upsert']
235
+ op[op_name].merge!(replacement: request['arguments']['replacement']) if request['arguments']['replacement']
236
+ op[op_name].merge!(array_filters: request['arguments']['arrayFilters']) if request['arguments']['arrayFilters']
237
+ op[op_name] = request['arguments']['document'] if request['arguments']['document']
238
+ op
239
+ end
240
+
219
241
  def upsert
220
242
  arguments['upsert']
221
243
  end
222
244
 
223
245
  def return_document
224
- :after if arguments['returnDocument']
246
+ case arguments['returnDocument']
247
+ when 'Before'
248
+ :before
249
+ when 'After'
250
+ :after
251
+ end
225
252
  end
226
253
 
227
254
  def update
@@ -26,3 +26,24 @@ tests:
26
26
  data:
27
27
  - {_id: 2, x: 22}
28
28
  - {_id: 3, x: 33}
29
+ -
30
+ description: "Aggregate with $out and batch size of 0"
31
+ operation:
32
+ name: aggregate
33
+ arguments:
34
+ pipeline:
35
+ - $sort: {x: 1}
36
+ - $match:
37
+ _id: {$gt: 1}
38
+ - $out: "other_test_collection"
39
+ batchSize: 0
40
+
41
+ outcome:
42
+ result:
43
+ - {_id: 2, x: 22}
44
+ - {_id: 3, x: 33}
45
+ collection:
46
+ name: "other_test_collection"
47
+ data:
48
+ - {_id: 2, x: 22}
49
+ - {_id: 3, x: 33}
@@ -0,0 +1,44 @@
1
+ data:
2
+ - {_id: 1, y: [{b: 3}, {b: 1}]}
3
+ - {_id: 2, y: [{b: 0}, {b: 1}]}
4
+
5
+ minServerVersion: '3.5.6'
6
+
7
+ tests:
8
+ -
9
+ description: "BulkWrite with arrayFilters"
10
+ operation:
11
+ name: "bulkWrite"
12
+ arguments:
13
+ requests:
14
+ -
15
+ # UpdateOne when one document matches arrayFilters
16
+ name: "updateOne"
17
+ arguments:
18
+ filter: {}
19
+ update:
20
+ $set: {"y.$[i].b": 2}
21
+ arrayFilters:
22
+ - {i.b: 3}
23
+ -
24
+ # UpdateMany when multiple documents match arrayFilters
25
+ name: "updateMany"
26
+ arguments:
27
+ filter: {}
28
+ update:
29
+ $set: {"y.$[i].b": 2}
30
+ arrayFilters:
31
+ - {i.b: 1}
32
+ options: { ordered: true }
33
+ outcome:
34
+ result:
35
+ deletedCount: 0
36
+ insertedIds: {}
37
+ matchedCount: 3
38
+ modifiedCount: 3
39
+ upsertedCount: 0
40
+ upsertedIds: {}
41
+ collection:
42
+ data:
43
+ - {_id: 1, y: [{b: 2}, {b: 2}]}
44
+ - {_id: 2, y: [{b: 0}, {b: 2}]}