mongo 2.16.0 → 2.17.1

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 (119) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +1 -1
  4. data/lib/mongo/auth/aws/request.rb +0 -1
  5. data/lib/mongo/client.rb +4 -0
  6. data/lib/mongo/cluster/reapers/cursor_reaper.rb +26 -14
  7. data/lib/mongo/collection/view/aggregation.rb +62 -17
  8. data/lib/mongo/collection/view/builder/aggregation.rb +11 -13
  9. data/lib/mongo/collection/view/builder/map_reduce.rb +8 -5
  10. data/lib/mongo/collection/view/change_stream.rb +7 -3
  11. data/lib/mongo/collection/view/iterable.rb +2 -3
  12. data/lib/mongo/collection/view/map_reduce.rb +16 -1
  13. data/lib/mongo/collection/view/readable.rb +24 -1
  14. data/lib/mongo/collection/view/writable.rb +23 -0
  15. data/lib/mongo/collection.rb +21 -1
  16. data/lib/mongo/cursor/kill_spec.rb +19 -2
  17. data/lib/mongo/cursor.rb +5 -5
  18. data/lib/mongo/database/view.rb +4 -2
  19. data/lib/mongo/database.rb +6 -6
  20. data/lib/mongo/error/snapshot_session_invalid_server_version.rb +31 -0
  21. data/lib/mongo/error/snapshot_session_transaction_prohibited.rb +30 -0
  22. data/lib/mongo/error.rb +2 -0
  23. data/lib/mongo/operation/delete/op_msg.rb +2 -1
  24. data/lib/mongo/operation/find/builder/command.rb +1 -0
  25. data/lib/mongo/operation/result.rb +6 -0
  26. data/lib/mongo/operation/shared/executable.rb +4 -0
  27. data/lib/mongo/operation/shared/sessions_supported.rb +18 -2
  28. data/lib/mongo/operation/update/op_msg.rb +2 -1
  29. data/lib/mongo/server/description/features.rb +3 -1
  30. data/lib/mongo/server/push_monitor.rb +4 -1
  31. data/lib/mongo/server_selector/base.rb +26 -4
  32. data/lib/mongo/session.rb +19 -0
  33. data/lib/mongo/socket/ocsp_cache.rb +2 -3
  34. data/lib/mongo/socket.rb +1 -5
  35. data/lib/mongo/utils.rb +0 -6
  36. data/lib/mongo/version.rb +1 -1
  37. data/mongo.gemspec +1 -1
  38. data/spec/integration/read_preference_spec.rb +16 -12
  39. data/spec/lite_spec_helper.rb +7 -0
  40. data/spec/mongo/cluster/cursor_reaper_spec.rb +22 -15
  41. data/spec/mongo/collection/view/aggregation_spec.rb +71 -95
  42. data/spec/mongo/collection/view/change_stream_spec.rb +1 -1
  43. data/spec/mongo/collection/view/map_reduce_spec.rb +30 -1
  44. data/spec/mongo/cursor_spec.rb +3 -2
  45. data/spec/mongo/operation/read_preference_op_msg_spec.rb +24 -1
  46. data/spec/mongo/server/monitor/connection_spec.rb +22 -0
  47. data/spec/mongo/server/push_monitor_spec.rb +101 -0
  48. data/spec/mongo/server_selector_spec.rb +136 -15
  49. data/spec/mongo/socket/ssl_spec.rb +26 -58
  50. data/spec/mongo/utils_spec.rb +0 -14
  51. data/spec/runners/auth.rb +1 -1
  52. data/spec/runners/change_streams/spec.rb +1 -1
  53. data/spec/runners/cmap.rb +1 -1
  54. data/spec/runners/command_monitoring.rb +1 -1
  55. data/spec/runners/connection_string.rb +1 -1
  56. data/spec/runners/crud/spec.rb +1 -3
  57. data/spec/runners/crud/verifier.rb +1 -2
  58. data/spec/runners/gridfs.rb +1 -1
  59. data/spec/runners/read_write_concern_document.rb +1 -1
  60. data/spec/runners/sdam.rb +1 -1
  61. data/spec/runners/server_selection.rb +1 -1
  62. data/spec/runners/server_selection_rtt.rb +1 -1
  63. data/spec/runners/unified/assertions.rb +3 -1
  64. data/spec/runners/unified/crud_operations.rb +77 -23
  65. data/spec/runners/unified/ddl_operations.rb +29 -1
  66. data/spec/runners/unified/entity_map.rb +3 -3
  67. data/spec/runners/unified/support_operations.rb +6 -1
  68. data/spec/runners/unified/test.rb +15 -3
  69. data/spec/runners/unified/test_group.rb +1 -1
  70. data/spec/spec_tests/data/crud_unified/aggregate-let.yml +138 -0
  71. data/spec/spec_tests/data/crud_unified/aggregate-write-readPreference.yml +155 -0
  72. data/spec/spec_tests/data/crud_unified/db-aggregate-write-readPreference.yml +151 -0
  73. data/spec/spec_tests/data/crud_unified/deleteMany-let.yml +91 -0
  74. data/spec/spec_tests/data/crud_unified/deleteOne-let.yml +89 -0
  75. data/spec/spec_tests/data/crud_unified/find-let.yml +71 -0
  76. data/spec/spec_tests/data/crud_unified/findOneAndDelete-let.yml +88 -0
  77. data/spec/spec_tests/data/crud_unified/findOneAndReplace-let.yml +94 -0
  78. data/spec/spec_tests/data/crud_unified/findOneAndUpdate-let.yml +96 -0
  79. data/spec/spec_tests/data/crud_unified/updateMany-let.yml +103 -0
  80. data/spec/spec_tests/data/crud_unified/updateOne-let.yml +98 -0
  81. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/DefaultNoMaxStaleness.yml +2 -2
  82. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/LastUpdateTime.yml +3 -3
  83. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Nearest.yml +3 -3
  84. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Nearest2.yml +3 -3
  85. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred.yml +2 -2
  86. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred_tags.yml +2 -2
  87. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Secondary.yml +4 -4
  88. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred.yml +2 -2
  89. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred_tags.yml +4 -4
  90. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/ZeroMaxStaleness.yml +2 -2
  91. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/DefaultNoMaxStaleness.yml +2 -2
  92. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LastUpdateTime.yml +3 -3
  93. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LongHeartbeat.yml +2 -2
  94. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LongHeartbeat2.yml +2 -2
  95. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/MaxStalenessTooSmall.yml +2 -2
  96. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/MaxStalenessWithModePrimary.yml +2 -2
  97. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest.yml +3 -3
  98. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest2.yml +3 -3
  99. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest_tags.yml +2 -2
  100. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/PrimaryPreferred.yml +2 -2
  101. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred.yml +2 -2
  102. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags.yml +5 -5
  103. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags2.yml +3 -3
  104. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Secondary_tags.yml +5 -5
  105. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Secondary_tags2.yml +3 -3
  106. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/ZeroMaxStaleness.yml +2 -2
  107. data/spec/spec_tests/data/max_staleness/Sharded/SmallMaxStaleness.yml +2 -2
  108. data/spec/spec_tests/data/max_staleness/Single/SmallMaxStaleness.yml +1 -1
  109. data/spec/spec_tests/data/max_staleness/Unknown/SmallMaxStaleness.yml +1 -1
  110. data/spec/spec_tests/data/sessions_unified/snapshot-sessions-not-supported-client-error.yml +69 -0
  111. data/spec/spec_tests/data/sessions_unified/snapshot-sessions-not-supported-server-error.yml +102 -0
  112. data/spec/spec_tests/data/sessions_unified/snapshot-sessions-unsupported-ops.yml +258 -0
  113. data/spec/spec_tests/data/sessions_unified/snapshot-sessions.yml +482 -0
  114. data/spec/spec_tests/seed_list_discovery_spec.rb +1 -1
  115. data/spec/spec_tests/sessions_unified_spec.rb +13 -0
  116. data/spec/support/utils.rb +31 -0
  117. data.tar.gz.sig +0 -0
  118. metadata +1127 -1090
  119. metadata.gz.sig +1 -2
@@ -306,67 +306,40 @@ describe Mongo::Socket::SSL, retry: 3 do
306
306
  end
307
307
  end
308
308
 
309
- context 'when ruby version is < 2.4.1' do
310
- ruby_version_lt '2.4.1'
311
-
312
- context 'when a key is passed, but it is not of the right type' do
313
-
314
- let(:ssl_options) do
315
- key = "This is a string not a key"
316
- {
317
- :ssl => true,
318
- :ssl_key_object => key,
319
- :ssl_cert => SpecConfig.instance.client_cert_path,
320
- :ssl_verify => false
321
- }
322
- end
323
-
324
- it 'raises a TypeError' do
325
- expect do
326
- socket
327
- end.to raise_exception(TypeError)
328
- end
329
- end
330
- end
331
-
332
309
  # Note that as of MRI 2.4, Creating a socket with the wrong key type raises
333
310
  # a NoMethodError because #private? is attempted to be called on the key.
334
311
  # In jruby 9.2 a TypeError is raised.
335
312
  # In jruby 9.1 a OpenSSL::PKey::PKeyError is raised.
336
- context 'when ruby version is >= 2.4.1' do
337
- ruby_version_gte '2.4.1'
313
+ context 'when a key is passed, but it is not of the right type' do
338
314
 
339
- context 'when a key is passed, but it is not of the right type' do
315
+ let(:ssl_options) do
316
+ key = "This is a string not a key"
317
+ {
318
+ :ssl => true,
319
+ :ssl_key_object => key,
320
+ :ssl_cert => SpecConfig.instance.client_cert_path,
321
+ :ssl_verify => false
322
+ }
323
+ end
340
324
 
341
- let(:ssl_options) do
342
- key = "This is a string not a key"
343
- {
344
- :ssl => true,
345
- :ssl_key_object => key,
346
- :ssl_cert => SpecConfig.instance.client_cert_path,
347
- :ssl_verify => false
348
- }
349
- end
350
-
351
- let(:expected_exception) do
352
- if SpecConfig.instance.jruby?
353
- if RUBY_VERSION >= '2.5.0'
354
- # jruby 9.2
355
- TypeError
356
- else
357
- # jruby 9.1
358
- OpenSSL::OpenSSLError
359
- end
325
+ let(:expected_exception) do
326
+ if SpecConfig.instance.jruby?
327
+ if RUBY_VERSION >= '2.5.0'
328
+ # jruby 9.2
329
+ TypeError
360
330
  else
361
- NoMethodError
331
+ # jruby 9.1
332
+ OpenSSL::OpenSSLError
362
333
  end
334
+ else
335
+ NoMethodError
363
336
  end
337
+ end
364
338
 
365
- it 'raises a NoMethodError' do
366
- expect do
367
- socket
368
- end.to raise_exception(expected_exception)
369
- end
339
+ it 'raises a NoMethodError' do
340
+ expect do
341
+ socket
342
+ end.to raise_exception(expected_exception)
370
343
  end
371
344
  end
372
345
 
@@ -403,13 +376,8 @@ describe Mongo::Socket::SSL, retry: 3 do
403
376
  context 'when a bad key is provided' do
404
377
 
405
378
  let(:expected_exception) do
406
- if RUBY_VERSION >= '2.4.0'
407
- # OpenSSL::PKey::PKeyError: Could not parse PKey: no start line
408
- [OpenSSL::OpenSSLError, /Could not parse PKey/]
409
- else
410
- # ArgumentError: Could not parse PKey: no start line
411
- [ArgumentError, /Could not parse PKey/]
412
- end
379
+ # OpenSSL::PKey::PKeyError: Could not parse PKey: no start line
380
+ [OpenSSL::OpenSSLError, /Could not parse PKey/]
413
381
  end
414
382
 
415
383
  let(:ssl_options) do
@@ -39,18 +39,4 @@ describe Mongo::Utils do
39
39
  }
40
40
  end
41
41
  end
42
-
43
- describe '#slice_hash' do
44
- it do
45
- hash = {'key1' => 1, :key2 => 's', :key3 => true}
46
- expect(
47
- described_class.slice_hash(hash, 'key1', :key3)
48
- ).to eq(
49
- {
50
- 'key1' => 1,
51
- :key3 => true
52
- }
53
- )
54
- end
55
- end
56
42
  end
data/spec/runners/auth.rb CHANGED
@@ -48,7 +48,7 @@ module Mongo
48
48
  attr_reader :tests
49
49
 
50
50
  def initialize(test_path)
51
- @spec = YAML.load(File.read(test_path))
51
+ @spec = ::Utils.load_spec_yaml_file(test_path)
52
52
  @description = File.basename(test_path)
53
53
  end
54
54
 
@@ -32,7 +32,7 @@ module Mongo
32
32
  #
33
33
  # @since 2.6.0
34
34
  def initialize(test_path)
35
- @spec = YAML.load(File.read(test_path))
35
+ @spec = ::Utils.load_spec_yaml_file(test_path)
36
36
  @description = File.basename(test_path)
37
37
  @spec_tests = @spec['tests']
38
38
  @collection_name = @spec['collection_name']
data/spec/runners/cmap.rb CHANGED
@@ -40,7 +40,7 @@ module Mongo
40
40
  #
41
41
  # @param [ String ] test_path The path to the file.
42
42
  def initialize(test_path)
43
- @test = YAML.load(File.read(test_path))
43
+ @test = ::Utils.load_spec_yaml_file(test_path)
44
44
 
45
45
  @description = @test['description']
46
46
  @pool_options = ::Utils.snakeize_hash(process_options(@test['poolOptions']))
@@ -204,7 +204,7 @@ module Mongo
204
204
  #
205
205
  # @since 2.1.0
206
206
  def initialize(test_path)
207
- @spec = YAML.load(File.read(test_path))
207
+ @spec = ::Utils.load_spec_yaml_file(test_path)
208
208
  @data = @spec['data']
209
209
  @tests = @spec['tests']
210
210
  end
@@ -100,7 +100,7 @@ module Mongo
100
100
  #
101
101
  # @since 2.0.0
102
102
  def initialize(test_path)
103
- @spec = YAML.load(File.read(test_path))
103
+ @spec = ::Utils.load_spec_yaml_file(test_path)
104
104
  @description = File.basename(test_path)
105
105
  end
106
106
 
@@ -12,9 +12,7 @@ module Mongo
12
12
  #
13
13
  # @since 2.0.0
14
14
  def initialize(test_path)
15
- contents = File.read(test_path)
16
-
17
- @spec = YAML.load(contents)
15
+ @spec = ::Utils.load_spec_yaml_file(test_path)
18
16
  @description = File.basename(test_path)
19
17
  @data = BSON::ExtJSON.parse_obj(@spec['data'])
20
18
  @tests = @spec['tests']
@@ -110,8 +110,7 @@ EOT
110
110
  expected_command = expected_event.delete('command')
111
111
  actual_command = actual_event.delete('command')
112
112
 
113
- # Hash#compact is ruby 2.4+
114
- expected_presence = expected_command.select { |k, v| !v.nil? }
113
+ expected_presence = expected_command.compact
115
114
  expected_absence = expected_command.select { |k, v| v.nil? }
116
115
 
117
116
  expected_presence.each do |k, v|
@@ -100,7 +100,7 @@ module Mongo
100
100
  #
101
101
  # @since 2.1.0
102
102
  def initialize(test_path)
103
- @spec = YAML.load(File.read(test_path))
103
+ @spec = ::Utils.load_spec_yaml_file(test_path)
104
104
  @description = File.basename(test_path)
105
105
  @data = @spec['data']
106
106
  end
@@ -13,7 +13,7 @@ module ReadWriteConcernDocument
13
13
  #
14
14
  # @since 2.0.0
15
15
  def initialize(test_path)
16
- @spec = YAML.load(File.read(test_path))
16
+ @spec = ::Utils.load_spec_yaml_file(test_path)
17
17
  @description = File.basename(test_path)
18
18
  end
19
19
 
data/spec/runners/sdam.rb CHANGED
@@ -77,7 +77,7 @@ module Mongo
77
77
  #
78
78
  # @since 2.0.0
79
79
  def initialize(test_path)
80
- @test = YAML.load(File.read(test_path))
80
+ @test = ::Utils.load_spec_yaml_file(test_path)
81
81
  @description = @test['description']
82
82
  @uri_string = @test['uri']
83
83
  @uri = URI.new(uri_string)
@@ -64,7 +64,7 @@ module Mongo
64
64
  #
65
65
  # @since 2.0.0
66
66
  def initialize(test_path)
67
- @test = YAML.load(File.read(test_path))
67
+ @test = ::Utils.load_spec_yaml_file(test_path)
68
68
  @description = "#{@test['topology_description']['type']}: #{File.basename(test_path)}"
69
69
  @heartbeat_frequency = @test['heartbeatFrequencyMS'] / 1000 if @test['heartbeatFrequencyMS']
70
70
  @read_preference = @test['read_preference']
@@ -28,7 +28,7 @@ module Mongo
28
28
  #
29
29
  # @since 2.0.0
30
30
  def initialize(test_path)
31
- @test = YAML.load(File.read(test_path))
31
+ @test = ::Utils.load_spec_yaml_file(test_path)
32
32
  @description = "#{File.basename(test_path)}: avg_rtt_ms: #{@test['avg_rtt_ms']}, new_rtt_ms: #{@test['new_rtt_ms']}," +
33
33
  " new_avg_rtt: #{@test['new_avg_rtt']}"
34
34
  @average_rtt = @test['avg_rtt_ms'] == 'NULL' ? nil : @test['avg_rtt_ms'].to_f / 1000
@@ -62,7 +62,7 @@ module Unified
62
62
  def assert_outcome
63
63
  return unless outcome
64
64
 
65
- client = ClientRegistry.instance.global_client('authorized')
65
+ client = ClientRegistry.instance.global_client('root_authorized')
66
66
  outcome.each do |spec|
67
67
  spec = UsingHash[spec]
68
68
  collection = client.use(spec.use!('databaseName'))[spec.use!('collectionName')]
@@ -217,6 +217,8 @@ module Unified
217
217
  BSON::ObjectId === object
218
218
  when 'date'
219
219
  Time === object
220
+ when 'double'
221
+ Float === object
220
222
  else
221
223
  raise NotImplementedError, "Unhandled type #{type}"
222
224
  end
@@ -8,7 +8,9 @@ module Unified
8
8
  def find(op)
9
9
  collection = entities.get(:collection, op.use!('object'))
10
10
  use_arguments(op) do |args|
11
- opts = {}
11
+ opts = {
12
+ let: args.use('let'),
13
+ }
12
14
  if session = args.use('session')
13
15
  opts[:session] = entities.get(:session, session)
14
16
  end
@@ -29,7 +31,11 @@ module Unified
29
31
  def count_documents(op)
30
32
  collection = entities.get(:collection, op.use!('object'))
31
33
  use_arguments(op) do |args|
32
- collection.find(args.use!('filter')).count_documents
34
+ opts = {}
35
+ if session = args.use('session')
36
+ opts[:session] = entities.get(:session, session)
37
+ end
38
+ collection.find(args.use!('filter')).count_documents(**opts)
33
39
  end
34
40
  end
35
41
 
@@ -47,7 +53,11 @@ module Unified
47
53
  def distinct(op)
48
54
  collection = entities.get(:collection, op.use!('object'))
49
55
  use_arguments(op) do |args|
50
- req = collection.find(args.use!('filter')).distinct(args.use!('fieldName'))
56
+ opts = {}
57
+ if session = args.use('session')
58
+ opts[:session] = entities.get(:session, session)
59
+ end
60
+ req = collection.find(args.use!('filter'), **opts).distinct(args.use!('fieldName'), **opts)
51
61
  result = req.to_a
52
62
  end
53
63
  end
@@ -57,10 +67,15 @@ module Unified
57
67
  use_arguments(op) do |args|
58
68
  filter = args.use!('filter')
59
69
  update = args.use!('update')
60
- opts = {}
70
+ opts = {
71
+ let: args.use('let'),
72
+ }
61
73
  if return_document = args.use('returnDocument')
62
74
  opts[:return_document] = return_document.downcase.to_sym
63
75
  end
76
+ if session = args.use('session')
77
+ opts[:session] = entities.get(:session, session)
78
+ end
64
79
  collection.find_one_and_update(filter, update, **opts)
65
80
  end
66
81
  end
@@ -70,7 +85,13 @@ module Unified
70
85
  use_arguments(op) do |args|
71
86
  filter = args.use!('filter')
72
87
  update = args.use!('replacement')
73
- collection.find_one_and_replace(filter, update)
88
+ opts = {
89
+ let: args.use('let'),
90
+ }
91
+ if session = args.use('session')
92
+ opts[:session] = entities.get(:session, session)
93
+ end
94
+ collection.find_one_and_replace(filter, update, **opts)
74
95
  end
75
96
  end
76
97
 
@@ -78,7 +99,13 @@ module Unified
78
99
  collection = entities.get(:collection, op.use!('object'))
79
100
  use_arguments(op) do |args|
80
101
  filter = args.use!('filter')
81
- collection.find_one_and_delete(filter)
102
+ opts = {
103
+ let: args.use('let'),
104
+ }
105
+ if session = args.use('session')
106
+ opts[:session] = entities.get(:session, session)
107
+ end
108
+ collection.find_one_and_delete(filter, **opts)
82
109
  end
83
110
  end
84
111
 
@@ -96,25 +123,37 @@ module Unified
96
123
  def insert_many(op)
97
124
  collection = entities.get(:collection, op.use!('object'))
98
125
  use_arguments(op) do |args|
99
- options = {}
126
+ opts = {}
100
127
  unless (ordered = args.use('ordered')).nil?
101
- options[:ordered] = ordered
128
+ opts[:ordered] = ordered
129
+ end
130
+ if session = args.use('session')
131
+ opts[:session] = entities.get(:session, session)
102
132
  end
103
- collection.insert_many(args.use!('documents'), **options)
133
+ collection.insert_many(args.use!('documents'), **opts)
104
134
  end
105
135
  end
106
136
 
107
137
  def update_one(op)
108
138
  collection = entities.get(:collection, op.use!('object'))
109
139
  use_arguments(op) do |args|
110
- collection.update_one(args.use!('filter'), args.use!('update'))
140
+ opts = {
141
+ let: args.use('let'),
142
+ }
143
+ if session = args.use('session')
144
+ opts[:session] = entities.get(:session, session)
145
+ end
146
+ collection.update_one(args.use!('filter'), args.use!('update'), **opts)
111
147
  end
112
148
  end
113
149
 
114
150
  def update_many(op)
115
151
  collection = entities.get(:collection, op.use!('object'))
116
152
  use_arguments(op) do |args|
117
- collection.update_many(args.use!('filter'), args.use!('update'))
153
+ opts = {
154
+ let: args.use('let'),
155
+ }
156
+ collection.update_many(args.use!('filter'), args.use!('update'), **opts)
118
157
  end
119
158
  end
120
159
 
@@ -132,14 +171,23 @@ module Unified
132
171
  def delete_one(op)
133
172
  collection = entities.get(:collection, op.use!('object'))
134
173
  use_arguments(op) do |args|
135
- collection.delete_one(args.use!('filter'))
174
+ opts = {
175
+ let: args.use('let'),
176
+ }
177
+ if session = args.use('session')
178
+ opts[:session] = entities.get(:session, session)
179
+ end
180
+ collection.delete_one(args.use!('filter'), **opts)
136
181
  end
137
182
  end
138
183
 
139
184
  def delete_many(op)
140
185
  collection = entities.get(:collection, op.use!('object'))
141
186
  use_arguments(op) do |args|
142
- collection.delete_many(args.use!('filter'))
187
+ opts = {
188
+ let: args.use('let'),
189
+ }
190
+ collection.delete_many(args.use!('filter'), **opts)
143
191
  end
144
192
  end
145
193
 
@@ -157,6 +205,22 @@ module Unified
157
205
  end
158
206
  end
159
207
 
208
+ def aggregate(op)
209
+ obj = entities.get_any(op.use!('object'))
210
+ args = op.use!('arguments')
211
+ pipeline = args.use!('pipeline')
212
+ opts = {
213
+ let: args.use('let'),
214
+ }
215
+ if session = args.use('session')
216
+ opts[:session] = entities.get(:session, session)
217
+ end
218
+ unless args.empty?
219
+ raise NotImplementedError, "Unhandled spec keys: #{args} in #{test_spec}"
220
+ end
221
+ obj.aggregate(pipeline, **opts).to_a
222
+ end
223
+
160
224
  private
161
225
 
162
226
  def convert_bulk_write_spec(spec)
@@ -192,15 +256,5 @@ module Unified
192
256
  end
193
257
  {Utils.underscore(op) =>out}
194
258
  end
195
-
196
- def aggregate(op)
197
- obj = entities.get_any(op.use!('object'))
198
- args = op.use!('arguments')
199
- pipeline = args.use!('pipeline')
200
- unless args.empty?
201
- raise NotImplementedError, "Unhandled spec keys: #{test_spec}"
202
- end
203
- obj.aggregate(pipeline).to_a
204
- end
205
259
  end
206
260
  end
@@ -7,7 +7,13 @@ module Unified
7
7
 
8
8
  def list_databases(op)
9
9
  client = entities.get(:client, op.use!('object'))
10
- client.list_databases
10
+ use_arguments(op) do |args|
11
+ opts = {}
12
+ if session = args.use('session')
13
+ opts[:session] = entities.get(:session, session)
14
+ end
15
+ client.list_databases({}, false, **opts)
16
+ end
11
17
  end
12
18
 
13
19
  def create_collection(op)
@@ -28,6 +34,17 @@ module Unified
28
34
  end
29
35
  end
30
36
 
37
+ def list_collections(op)
38
+ database = entities.get(:database, op.use!('object'))
39
+ use_arguments(op) do |args|
40
+ opts = {}
41
+ if session = args.use('session')
42
+ opts[:session] = entities.get(:session, session)
43
+ end
44
+ database.list_collections(**opts)
45
+ end
46
+ end
47
+
31
48
  def drop_collection(op)
32
49
  database = entities.get(:database, op.use!('object'))
33
50
  use_arguments(op) do |args|
@@ -58,6 +75,17 @@ module Unified
58
75
  assert_collection_exists(op, false)
59
76
  end
60
77
 
78
+ def list_indexes(op)
79
+ collection = entities.get(:collection, op.use!('object'))
80
+ use_arguments(op) do |args|
81
+ opts = {}
82
+ if session = args.use('session')
83
+ opts[:session] = entities.get(:session, session)
84
+ end
85
+ collection.indexes(**opts).to_a
86
+ end
87
+ end
88
+
61
89
  def create_index(op)
62
90
  collection = entities.get(:collection, op.use!('object'))
63
91
  use_arguments(op) do |args|
@@ -3,6 +3,8 @@
3
3
 
4
4
  module Unified
5
5
  class EntityMap
6
+ extend Forwardable
7
+
6
8
  def initialize
7
9
  @map = {}
8
10
  end
@@ -35,8 +37,6 @@ module Unified
35
37
  raise Error::EntityMissing, "There is no #{id} known"
36
38
  end
37
39
 
38
- def [](type)
39
- @map[type]
40
- end
40
+ def_delegators :@map, :[], :fetch
41
41
  end
42
42
  end
@@ -13,7 +13,12 @@ module Unified
13
13
 
14
14
  cmd = args.use!('command')
15
15
 
16
- database.command(cmd)
16
+ opts = {}
17
+ if session = args.use('session')
18
+ opts[:session] = entities.get(:session, session)
19
+ end
20
+
21
+ database.command(cmd, **opts)
17
22
  end
18
23
  end
19
24
 
@@ -160,13 +160,24 @@ module Unified
160
160
  end
161
161
  when 'database'
162
162
  client = entities.get(:client, spec.use!('client'))
163
- client.use(spec.use!('databaseName')).database
163
+ opts = Utils.snakeize_hash(spec.use('databaseOptions') || {})
164
+ .merge(database: spec.use!('databaseName'))
165
+ if opts.key?(:read_preference)
166
+ opts[:read] = opts.delete(:read_preference)
167
+ if opts[:read].key?(:max_staleness_seconds)
168
+ opts[:read][:max_staleness] = opts[:read].delete(:max_staleness_seconds)
169
+ end
170
+ end
171
+ client.with(opts).database
164
172
  when 'collection'
165
173
  database = entities.get(:database, spec.use!('database'))
166
174
  # TODO verify
167
175
  opts = Utils.snakeize_hash(spec.use('collectionOptions') || {})
168
176
  if opts.key?(:read_preference)
169
177
  opts[:read] = opts.delete(:read_preference)
178
+ if opts[:read].key?(:max_staleness_seconds)
179
+ opts[:read][:max_staleness] = opts[:read].delete(:max_staleness_seconds)
180
+ end
170
181
  end
171
182
  database[spec.use!('collectionName'), opts]
172
183
  when 'bucket'
@@ -195,7 +206,8 @@ module Unified
195
206
  def set_initial_data
196
207
  @spec['initialData']&.each do |entity_spec|
197
208
  spec = UsingHash[entity_spec]
198
- collection = root_authorized_client.use(spec.use!('databaseName'))[spec.use!('collectionName')]
209
+ collection = root_authorized_client.with(write_concern: {w: :majority}).
210
+ use(spec.use!('databaseName'))[spec.use!('collectionName')]
199
211
  collection.drop
200
212
  docs = spec.use!('documents')
201
213
  if docs.any?
@@ -268,7 +280,7 @@ module Unified
268
280
  end
269
281
  if expected_error = op.use('expectError')
270
282
  begin
271
- send(method_name, op)
283
+ public_send(method_name, op)
272
284
  rescue Mongo::Error, BSON::String::IllegalKey => e
273
285
  if expected_error.use('isClientError')
274
286
  # isClientError doesn't actually mean a client error.
@@ -6,7 +6,7 @@ module Unified
6
6
  class TestGroup
7
7
  def initialize(path, **opts)
8
8
  if String === path
9
- data = YAML.load(File.read(path))
9
+ data = ::Utils.load_spec_yaml_file(path)
10
10
  else
11
11
  data = path
12
12
  end