mongo 2.9.2 → 2.10.0.rc0

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 (227) 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.rb +1 -0
  5. data/lib/mongo/auth/user/view.rb +4 -4
  6. data/lib/mongo/bulk_write.rb +14 -8
  7. data/lib/mongo/bulk_write/result.rb +1 -1
  8. data/lib/mongo/bulk_write/result_combiner.rb +2 -2
  9. data/lib/mongo/bulk_write/transformable.rb +17 -9
  10. data/lib/mongo/client.rb +107 -16
  11. data/lib/mongo/cluster.rb +47 -25
  12. data/lib/mongo/cluster/topology/replica_set_no_primary.rb +1 -1
  13. data/lib/mongo/cluster_time.rb +139 -0
  14. data/lib/mongo/collection.rb +84 -25
  15. data/lib/mongo/collection/view.rb +7 -3
  16. data/lib/mongo/collection/view/aggregation.rb +4 -4
  17. data/lib/mongo/collection/view/builder/aggregation.rb +31 -6
  18. data/lib/mongo/collection/view/builder/find_command.rb +4 -1
  19. data/lib/mongo/collection/view/builder/map_reduce.rb +4 -1
  20. data/lib/mongo/collection/view/change_stream.rb +54 -66
  21. data/lib/mongo/collection/view/iterable.rb +2 -2
  22. data/lib/mongo/collection/view/map_reduce.rb +6 -4
  23. data/lib/mongo/collection/view/readable.rb +36 -16
  24. data/lib/mongo/collection/view/writable.rb +68 -22
  25. data/lib/mongo/cursor.rb +87 -20
  26. data/lib/mongo/database.rb +47 -43
  27. data/lib/mongo/database/view.rb +54 -11
  28. data/lib/mongo/error.rb +13 -4
  29. data/lib/mongo/error/invalid_write_concern.rb +2 -2
  30. data/lib/mongo/error/operation_failure.rb +65 -11
  31. data/lib/mongo/error/parser.rb +41 -8
  32. data/lib/mongo/grid/fs_bucket.rb +26 -6
  33. data/lib/mongo/grid/stream/read.rb +9 -2
  34. data/lib/mongo/grid/stream/write.rb +21 -5
  35. data/lib/mongo/index/view.rb +3 -3
  36. data/lib/mongo/lint.rb +10 -3
  37. data/lib/mongo/operation.rb +2 -0
  38. data/lib/mongo/operation/aggregate/result.rb +19 -6
  39. data/lib/mongo/operation/collections_info.rb +1 -1
  40. data/lib/mongo/operation/get_more/result.rb +9 -0
  41. data/lib/mongo/operation/list_collections/command.rb +1 -3
  42. data/lib/mongo/operation/list_collections/op_msg.rb +1 -2
  43. data/lib/mongo/operation/parallel_scan/command.rb +4 -1
  44. data/lib/mongo/operation/parallel_scan/op_msg.rb +4 -1
  45. data/lib/mongo/operation/result.rb +27 -4
  46. data/lib/mongo/operation/shared/executable.rb +19 -5
  47. data/lib/mongo/operation/shared/executable_no_validate.rb +1 -2
  48. data/lib/mongo/operation/shared/executable_transaction_label.rb +0 -9
  49. data/lib/mongo/operation/shared/polymorphic_result.rb +9 -1
  50. data/lib/mongo/operation/shared/result/aggregatable.rb +2 -2
  51. data/lib/mongo/operation/shared/sessions_supported.rb +42 -32
  52. data/lib/mongo/operation/shared/specifiable.rb +40 -0
  53. data/lib/mongo/operation/shared/unpinnable.rb +39 -0
  54. data/lib/mongo/operation/shared/write.rb +1 -1
  55. data/lib/mongo/protocol/update.rb +6 -2
  56. data/lib/mongo/retryable.rb +79 -39
  57. data/lib/mongo/server/connection.rb +10 -3
  58. data/lib/mongo/server/description.rb +25 -1
  59. data/lib/mongo/server/monitor/connection.rb +1 -1
  60. data/lib/mongo/server_selector.rb +10 -0
  61. data/lib/mongo/server_selector/selectable.rb +172 -32
  62. data/lib/mongo/session.rb +654 -581
  63. data/lib/mongo/session/session_pool.rb +1 -1
  64. data/lib/mongo/socket.rb +7 -28
  65. data/lib/mongo/socket/ssl.rb +26 -1
  66. data/lib/mongo/socket/tcp.rb +3 -0
  67. data/lib/mongo/socket/unix.rb +3 -0
  68. data/lib/mongo/uri.rb +112 -265
  69. data/lib/mongo/uri/srv_protocol.rb +4 -1
  70. data/lib/mongo/version.rb +1 -1
  71. data/lib/mongo/write_concern.rb +10 -29
  72. data/lib/mongo/write_concern/acknowledged.rb +12 -0
  73. data/lib/mongo/write_concern/base.rb +17 -13
  74. data/lib/mongo/write_concern/unacknowledged.rb +12 -0
  75. data/spec/atlas/atlas_connectivity_spec.rb +7 -37
  76. data/spec/atlas/operations_spec.rb +25 -0
  77. data/spec/integration/change_stream_examples_spec.rb +45 -31
  78. data/spec/integration/change_stream_spec.rb +305 -5
  79. data/spec/integration/client_spec.rb +44 -0
  80. data/spec/integration/command_monitoring_spec.rb +1 -0
  81. data/spec/integration/command_spec.rb +7 -1
  82. data/spec/integration/mmapv1_spec.rb +28 -0
  83. data/spec/integration/mongos_pinning_spec.rb +34 -0
  84. data/spec/integration/operation_failure_code_spec.rb +2 -2
  85. data/spec/integration/{read_concern.rb → read_concern_spec.rb} +7 -1
  86. data/spec/integration/read_preference_spec.rb +485 -0
  87. data/spec/integration/retryable_writes_spec.rb +8 -19
  88. data/spec/integration/sdam_error_handling_spec.rb +1 -1
  89. data/spec/integration/sdam_events_spec.rb +2 -2
  90. data/spec/integration/server_description_spec.rb +14 -17
  91. data/spec/integration/server_selector_spec.rb +7 -3
  92. data/spec/integration/server_spec.rb +48 -0
  93. data/spec/integration/ssl_uri_options_spec.rb +1 -1
  94. data/spec/integration/step_down_spec.rb +10 -4
  95. data/spec/integration/transactions_examples_spec.rb +11 -10
  96. data/spec/lite_spec_helper.rb +19 -16
  97. data/spec/mongo/auth/scram/negotiation_spec.rb +11 -8
  98. data/spec/mongo/bulk_write/ordered_combiner_spec.rb +6 -6
  99. data/spec/mongo/bulk_write/unordered_combiner_spec.rb +4 -4
  100. data/spec/mongo/bulk_write_spec.rb +12 -2
  101. data/spec/mongo/client_construction_spec.rb +160 -8
  102. data/spec/mongo/client_spec.rb +5 -4
  103. data/spec/mongo/cluster_spec.rb +6 -6
  104. data/spec/mongo/cluster_time_spec.rb +148 -0
  105. data/spec/mongo/collection/view/aggregation_spec.rb +34 -15
  106. data/spec/mongo/collection/view/change_stream_spec.rb +62 -3
  107. data/spec/mongo/collection/view/map_reduce_spec.rb +7 -5
  108. data/spec/mongo/collection/view/readable_spec.rb +4 -4
  109. data/spec/mongo/collection_spec.rb +331 -14
  110. data/spec/mongo/cursor_spec.rb +117 -5
  111. data/spec/mongo/database_spec.rb +240 -8
  112. data/spec/mongo/error/operation_failure_spec.rb +47 -1
  113. data/spec/mongo/error/parser_spec.rb +160 -23
  114. data/spec/mongo/operation/insert/bulk_spec.rb +2 -1
  115. data/spec/mongo/operation/result_spec.rb +27 -0
  116. data/spec/mongo/operation/update/bulk_spec.rb +1 -0
  117. data/spec/mongo/retryable_spec.rb +2 -0
  118. data/spec/mongo/server/app_metadata_spec.rb +2 -2
  119. data/spec/mongo/server/connection_spec.rb +13 -17
  120. data/spec/mongo/server/monitor/connection_spec.rb +13 -10
  121. data/spec/mongo/server_selector_spec.rb +34 -2
  122. data/spec/mongo/session/session_pool_spec.rb +14 -3
  123. data/spec/mongo/session_spec.rb +3 -3
  124. data/spec/mongo/session_transaction_spec.rb +4 -3
  125. data/spec/mongo/socket/ssl_spec.rb +19 -5
  126. data/spec/mongo/socket_spec.rb +1 -62
  127. data/spec/mongo/uri/srv_protocol_spec.rb +14 -20
  128. data/spec/mongo/uri_option_parsing_spec.rb +94 -8
  129. data/spec/mongo/uri_spec.rb +23 -10
  130. data/spec/mongo/write_concern_spec.rb +56 -3
  131. data/spec/spec_tests/change_streams_spec.rb +2 -1
  132. data/spec/spec_tests/cmap_spec.rb +1 -1
  133. data/spec/spec_tests/crud_spec.rb +12 -2
  134. data/spec/spec_tests/data/change_streams/change-streams-errors.yml +24 -1
  135. data/spec/spec_tests/data/change_streams/change-streams.yml +172 -3
  136. data/spec/spec_tests/data/command_monitoring/bulkWrite.yml +1 -1
  137. data/spec/spec_tests/data/command_monitoring/updateMany.yml +0 -2
  138. data/spec/spec_tests/data/command_monitoring/updateOne.yml +0 -5
  139. data/spec/spec_tests/data/crud/read/aggregate-out.yml +0 -6
  140. data/spec/spec_tests/data/crud/read/count-empty.yml +29 -0
  141. data/spec/spec_tests/data/crud/write/bulkWrite-arrayFilters.yml +1 -0
  142. data/spec/spec_tests/data/crud/write/bulkWrite-collation.yml +101 -0
  143. data/spec/spec_tests/data/crud/write/bulkWrite.yml +401 -0
  144. data/spec/spec_tests/data/crud/write/insertMany.yml +58 -2
  145. data/spec/spec_tests/data/crud/write/updateMany-arrayFilters.yml +3 -0
  146. data/spec/spec_tests/data/crud/write/updateOne-arrayFilters.yml +6 -1
  147. data/spec/spec_tests/data/crud_v2/aggregate-merge.yml +103 -0
  148. data/spec/spec_tests/data/crud_v2/aggregate-out-readConcern.yml +110 -0
  149. data/spec/spec_tests/data/crud_v2/bulkWrite-arrayFilters.yml +81 -0
  150. data/spec/spec_tests/data/crud_v2/db-aggregate.yml +38 -0
  151. data/spec/spec_tests/data/crud_v2/updateWithPipelines.yml +92 -0
  152. data/spec/spec_tests/data/retryable_writes/insertOne-serverErrors.yml +2 -2
  153. data/spec/spec_tests/data/transactions/abort.yml +3 -0
  154. data/spec/spec_tests/data/transactions/bulk.yml +3 -8
  155. data/spec/spec_tests/data/transactions/causal-consistency.yml +3 -8
  156. data/spec/spec_tests/data/transactions/commit.yml +3 -1
  157. data/spec/spec_tests/data/transactions/count.yml +3 -0
  158. data/spec/spec_tests/data/transactions/delete.yml +3 -0
  159. data/spec/spec_tests/data/transactions/error-labels.yml +4 -1
  160. data/spec/spec_tests/data/transactions/errors-client.yml +56 -0
  161. data/spec/spec_tests/data/transactions/errors.yml +3 -0
  162. data/spec/spec_tests/data/transactions/findOneAndDelete.yml +3 -0
  163. data/spec/spec_tests/data/transactions/findOneAndReplace.yml +3 -0
  164. data/spec/spec_tests/data/transactions/findOneAndUpdate.yml +3 -0
  165. data/spec/spec_tests/data/transactions/insert.yml +3 -0
  166. data/spec/spec_tests/data/transactions/isolation.yml +3 -0
  167. data/spec/spec_tests/data/transactions/mongos-pin-auto.yml +1671 -0
  168. data/spec/spec_tests/data/transactions/mongos-recovery-token.yml +347 -0
  169. data/spec/spec_tests/data/transactions/pin-mongos.yml +557 -0
  170. data/spec/spec_tests/data/transactions/read-concern.yml +3 -0
  171. data/spec/spec_tests/data/transactions/read-pref.yml +3 -0
  172. data/spec/spec_tests/data/transactions/reads.yml +3 -0
  173. data/spec/spec_tests/data/transactions/retryable-abort.yml +5 -2
  174. data/spec/spec_tests/data/transactions/retryable-commit.yml +4 -1
  175. data/spec/spec_tests/data/transactions/retryable-writes.yml +3 -0
  176. data/spec/spec_tests/data/transactions/run-command.yml +3 -0
  177. data/spec/spec_tests/data/transactions/transaction-options.yml +6 -0
  178. data/spec/spec_tests/data/transactions/update.yml +3 -8
  179. data/spec/spec_tests/data/transactions/write-concern.yml +348 -38
  180. data/spec/spec_tests/data/transactions_api/callback-aborts.yml +6 -0
  181. data/spec/spec_tests/data/transactions_api/callback-commits.yml +5 -0
  182. data/spec/spec_tests/data/transactions_api/callback-retry.yml +7 -2
  183. data/spec/spec_tests/data/transactions_api/commit-retry.yml +70 -15
  184. data/spec/spec_tests/data/transactions_api/commit-transienttransactionerror-4.2.yml +3 -0
  185. data/spec/spec_tests/data/transactions_api/commit-transienttransactionerror.yml +3 -0
  186. data/spec/spec_tests/data/transactions_api/commit-writeconcernerror.yml +59 -109
  187. data/spec/spec_tests/data/transactions_api/commit.yml +5 -0
  188. data/spec/spec_tests/data/transactions_api/transaction-options.yml +10 -0
  189. data/spec/spec_tests/retryable_reads_spec.rb +5 -2
  190. data/spec/spec_tests/retryable_writes_spec.rb +5 -2
  191. data/spec/spec_tests/sdam_monitoring_spec.rb +3 -3
  192. data/spec/spec_tests/sdam_spec.rb +2 -2
  193. data/spec/spec_tests/transactions_api_spec.rb +1 -67
  194. data/spec/spec_tests/transactions_spec.rb +2 -66
  195. data/spec/support/authorization.rb +4 -0
  196. data/spec/support/change_streams.rb +30 -10
  197. data/spec/support/change_streams/operation.rb +27 -0
  198. data/spec/support/client_registry.rb +44 -25
  199. data/spec/support/cluster_config.rb +25 -14
  200. data/spec/support/cluster_tools.rb +32 -10
  201. data/spec/support/command_monitoring.rb +1 -1
  202. data/spec/support/common_shortcuts.rb +30 -0
  203. data/spec/support/connection_string.rb +8 -3
  204. data/spec/support/constraints.rb +34 -0
  205. data/spec/support/crud.rb +31 -16
  206. data/spec/support/crud/context.rb +23 -0
  207. data/spec/support/crud/operation.rb +311 -14
  208. data/spec/support/crud/spec.rb +2 -1
  209. data/spec/support/crud/test.rb +24 -27
  210. data/spec/support/crud/test_base.rb +22 -0
  211. data/spec/support/crud/verifier.rb +15 -1
  212. data/spec/support/event_subscriber.rb +12 -0
  213. data/spec/support/sdam_formatter_integration.rb +12 -6
  214. data/spec/support/shared/server_selector.rb +10 -0
  215. data/spec/support/shared/session.rb +13 -12
  216. data/spec/support/spec_config.rb +32 -22
  217. data/spec/support/spec_setup.rb +2 -2
  218. data/spec/support/transactions.rb +87 -0
  219. data/spec/support/transactions/context.rb +33 -0
  220. data/spec/support/transactions/operation.rb +99 -349
  221. data/spec/support/transactions/spec.rb +1 -3
  222. data/spec/support/transactions/test.rb +110 -49
  223. data/spec/support/utils.rb +74 -1
  224. metadata +52 -10
  225. metadata.gz.sig +0 -0
  226. data/spec/support/crud/read.rb +0 -265
  227. data/spec/support/crud/write.rb +0 -284
@@ -16,6 +16,7 @@ module Mongo
16
16
 
17
17
  # Since Ruby driver binds a client to a database, change the
18
18
  # database name in the spec to the one we are using
19
+ contents.sub!(/"crud-tests"/, '"ruby-driver"')
19
20
  contents.sub!(/"retryable-reads-tests"/, '"ruby-driver"')
20
21
  contents.sub!(/"transaction-tests"/, '"ruby-driver"')
21
22
  contents.sub!(/"withTransaction-tests"/, '"ruby-driver"')
@@ -60,7 +61,7 @@ module Mongo
60
61
  # Get a list of Test instances, one for each test definition.
61
62
  def tests
62
63
  @tests.map do |test|
63
- Mongo::CRUD::CRUDTest.new(@data, test)
64
+ Mongo::CRUD::CRUDTest.new(self, @data, test)
64
65
  end
65
66
  end
66
67
  end
@@ -4,7 +4,7 @@ module Mongo
4
4
  # Represents a single CRUD test.
5
5
  #
6
6
  # @since 2.0.0
7
- class CRUDTest
7
+ class CRUDTest < CRUDTestBase
8
8
 
9
9
  # The test description.
10
10
  #
@@ -25,12 +25,14 @@ module Mongo
25
25
  # collection_name as configured in the YAML file. Alternatively data
26
26
  # can be a map of collection names to arrays of hashes.
27
27
  #
28
+ # @param [ Crud::Spec ] crud_spec The top level YAML specification object.
28
29
  # @param [ Hash | Array<Hash> ] data The documents the collection
29
30
  # must have before the test runs.
30
31
  # @param [ Hash ] test The test specification.
31
32
  #
32
33
  # @since 2.0.0
33
- def initialize(data, test)
34
+ def initialize(crud_spec, data, test)
35
+ @spec = crud_spec
34
36
  @data = data
35
37
  if test['failPoint']
36
38
  @fail_point_command = FAIL_POINT_BASE_COMMAND.merge(test['failPoint'])
@@ -39,10 +41,13 @@ module Mongo
39
41
  @client_options = Utils.convert_client_options(test['clientOptions'] || {})
40
42
  if test['operations']
41
43
  @operations = test['operations'].map do |op_spec|
42
- Operation.get(op_spec)
44
+ Operation.new(self, op_spec)
43
45
  end
44
46
  else
45
- @operations = [Operation.get(test['operation'], test['outcome'])]
47
+ @operations = [Operation.new(self, test['operation'], test['outcome'])]
48
+ end
49
+ if test['outcome']
50
+ @outcome = Mongo::CRUD::Outcome.new(test['outcome'])
46
51
  end
47
52
  @expectations = test['expectations']
48
53
  end
@@ -59,6 +64,8 @@ module Mongo
59
64
  # The expected command monitoring events
60
65
  attr_reader :expectations
61
66
 
67
+ attr_reader :outcome
68
+
62
69
  # Run the test.
63
70
  #
64
71
  # The specified number of operations are executed, so that the
@@ -71,22 +78,11 @@ module Mongo
71
78
  # @return [ Result, Array<Hash> ] The result(s) of running the test.
72
79
  #
73
80
  # @since 2.0.0
74
- def run(spec, client, num_ops)
81
+ def run(client, num_ops)
75
82
  result = nil
76
83
  1.upto(num_ops) do |i|
77
84
  operation = @operations[i-1]
78
- target = case operation.object
79
- when 'collection'
80
- client[spec.collection_name]
81
- when 'database'
82
- client.database
83
- when 'client'
84
- client
85
- when 'gridfsbucket'
86
- client.database.fs
87
- else
88
- raise "Unknown target #{operation.object}"
89
- end
85
+ target = resolve_target(client, operation)
90
86
  result = operation.execute(target)
91
87
  end
92
88
  result
@@ -98,8 +94,10 @@ module Mongo
98
94
 
99
95
  def setup_test(spec, client)
100
96
  clear_fail_point(client)
101
- if @data.is_a?(Array)
102
- collection = client[spec.collection_name]
97
+ if @data.nil?
98
+ # nothing to do
99
+ elsif @data.is_a?(Array)
100
+ collection = client[spec.collection_name, write_concern: {w: :majority}]
103
101
  collection.delete_many
104
102
  collection.insert_many(@data)
105
103
  elsif @data.is_a?(Hash)
@@ -113,10 +111,10 @@ module Mongo
113
111
  else
114
112
  raise "Unknown type of data: #{@data}"
115
113
  end
116
- set_up_fail_point(client)
114
+ setup_fail_point(client)
117
115
  end
118
116
 
119
- def set_up_fail_point(client)
117
+ def setup_fail_point(client)
120
118
  if @fail_point_command
121
119
  client.use(:admin).command(@fail_point_command)
122
120
  end
@@ -128,13 +126,12 @@ module Mongo
128
126
  end
129
127
  end
130
128
 
131
- private
132
-
133
- def actual_collection_data
134
- if expected_outcome.collection_data?
135
- collection_name = expected_outcome.collection_name || @collection.name
136
- @collection.database[collection_name].find.to_a
129
+ def actual_collection_contents(client)
130
+ unless @spec.collection_name
131
+ raise ArgumentError, 'Spec does not specify a global collection'
137
132
  end
133
+
134
+ client[@spec.collection_name, read_concern: {level: :majority}].find.to_a
138
135
  end
139
136
  end
140
137
  end
@@ -0,0 +1,22 @@
1
+ module Mongo
2
+ module CRUD
3
+
4
+ class CRUDTestBase
5
+
6
+ def resolve_target(client, operation)
7
+ case operation.object
8
+ when 'collection'
9
+ client[@spec.collection_name].with(operation.collection_options)
10
+ when 'database'
11
+ client.database
12
+ when 'client'
13
+ client
14
+ when 'gridfsbucket'
15
+ client.database.fs
16
+ else
17
+ raise "Unknown target #{operation.object}"
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -67,7 +67,13 @@ module Mongo
67
67
  end
68
68
 
69
69
  def verify_command_started_event_count(expected_events, actual_events)
70
- expect(actual_events.length).to eq(expected_events.length)
70
+ if actual_events.length != expected_events.length
71
+ raise RSpec::Expectations::ExpectationNotMetError.new, <<-EOT
72
+ Expected #{expected_events.length} events, got #{actual_events.length} events.
73
+ Expected events: #{expected_events.pretty_inspect}
74
+ Actual events: #{actual_events.pretty_inspect}
75
+ EOT
76
+ end
71
77
  end
72
78
 
73
79
  def verify_command_started_event(expected_events, actual_events, i)
@@ -117,6 +123,14 @@ module Mongo
117
123
  when nil
118
124
  expect(actual).to be nil
119
125
  when Hash
126
+ if actual.is_a?(Hash) && actual['error'] &&
127
+ !expected.keys.any? { |key| key.start_with?('error') }
128
+ then
129
+ raise RSpec::Expectations::ExpectationNotMetError.new,
130
+ "Expected operation not to fail but it failed: #{actual.inspect}"
131
+ end
132
+ expect(actual).to be_a(Hash)
133
+
120
134
  expected.each do |k, v|
121
135
  case k
122
136
  when 'errorContains'
@@ -44,6 +44,18 @@ class EventSubscriber
44
44
  end
45
45
  end
46
46
 
47
+ # Locates command stated events for the specified command name,
48
+ # asserts that there is exactly one such event, and returns it.
49
+ def single_command_started_event(command_name)
50
+ events = started_events.select do |event|
51
+ event.command[command_name]
52
+ end
53
+ if events.length != 1
54
+ raise "Expected a single #{command_name} event but we have #{events.length}"
55
+ end
56
+ events.first
57
+ end
58
+
47
59
  # Cache the failed event.
48
60
  #
49
61
  # @param [ Event ] event The event.
@@ -1,3 +1,5 @@
1
+ $sdam_formatter_lock = Mutex.new
2
+
1
3
  module SdamFormatterIntegration
2
4
  def log_entries
3
5
  @log_entries ||= []
@@ -10,16 +12,20 @@ module SdamFormatterIntegration
10
12
  module_function :clear_log_entries
11
13
 
12
14
  def assign_log_entries(example_id)
13
- @log_entries_by_example_id ||= {}
14
- @log_entries_by_example_id[example_id] ||= []
15
- @log_entries_by_example_id[example_id] += log_entries
16
- clear_log_entries
15
+ $sdam_formatter_lock.synchronize do
16
+ @log_entries_by_example_id ||= {}
17
+ @log_entries_by_example_id[example_id] ||= []
18
+ @log_entries_by_example_id[example_id] += log_entries
19
+ clear_log_entries
20
+ end
17
21
  end
18
22
  module_function :assign_log_entries
19
23
 
20
24
  def example_log_entries(example_id)
21
- @log_entries_by_example_id ||= {}
22
- @log_entries_by_example_id[example_id]
25
+ $sdam_formatter_lock.synchronize do
26
+ @log_entries_by_example_id ||= {}
27
+ @log_entries_by_example_id[example_id]
28
+ end
23
29
  end
24
30
  module_function :example_log_entries
25
31
 
@@ -10,6 +10,16 @@ shared_context 'server selector' do
10
10
  end
11
11
  let(:primary) { make_server(:primary) }
12
12
  let(:secondary) { make_server(:secondary) }
13
+ let(:mongos) do
14
+ make_server(:mongos).tap do |server|
15
+ expect(server.mongos?).to be true
16
+ end
17
+ end
18
+ let(:unknown) do
19
+ make_server(:unknown).tap do |server|
20
+ expect(server.unknown?).to be true
21
+ end
22
+ end
13
23
  let(:options) { { :mode => name, :tag_sets => tag_sets, max_staleness: max_staleness } }
14
24
  let(:selector) { described_class.new(options) }
15
25
  let(:monitoring) do
@@ -141,15 +141,14 @@ shared_examples 'an explicit session with an unacknowledged write' do
141
141
  end
142
142
 
143
143
  context 'when sessions are not supported' do
144
- min_server_fcv '3.6'
144
+ max_server_version '3.4'
145
145
 
146
146
  let(:session) do
147
- double('session').tap do |s|
148
- allow(s).to receive(:validate!)
149
- end
147
+ nil
150
148
  end
151
149
 
152
150
  it 'does not add a session id to the operation' do
151
+ expect(Mongo::Session).not_to receive(:new)
153
152
  operation
154
153
  expect(EventSubscriber.started_events.collect(&:command).collect { |cmd| cmd['lsid'] }.compact).to be_empty
155
154
  end
@@ -172,7 +171,7 @@ shared_examples 'an implicit session with an unacknowledged write' do
172
171
  end
173
172
 
174
173
  context 'when sessions are not supported' do
175
- min_server_fcv '3.6'
174
+ max_server_version '3.4'
176
175
 
177
176
  it 'does not add a session id to the operation' do
178
177
  operation
@@ -604,6 +603,8 @@ shared_examples 'an operation supporting causally consistent reads' do
604
603
  end
605
604
  end
606
605
 
606
+ # Since background operatons can advance cluster time, exact cluster time
607
+ # comparisons sometimes fail. Work around this by retrying the tests.
607
608
  shared_examples 'an operation updating cluster time' do
608
609
 
609
610
  let(:cluster) do
@@ -619,7 +620,7 @@ shared_examples 'an operation updating cluster time' do
619
620
  end
620
621
 
621
622
  shared_examples_for 'does not update the cluster time of the cluster' do
622
- it 'does not update the cluster time of the cluster' do
623
+ it 'does not update the cluster time of the cluster', retry: 3 do
623
624
  bct = before_cluster_time
624
625
  reply_cluster_time
625
626
  expect(client.cluster.cluster_time).to eq(before_cluster_time)
@@ -639,12 +640,12 @@ shared_examples 'an operation updating cluster time' do
639
640
  EventSubscriber.succeeded_events[-1].reply['$clusterTime']
640
641
  end
641
642
 
642
- it 'updates the cluster time of the cluster' do
643
+ it 'updates the cluster time of the cluster', retry: 3 do
643
644
  rct = reply_cluster_time
644
645
  expect(cluster.cluster_time).to eq(rct)
645
646
  end
646
647
 
647
- it 'updates the cluster time of the session' do
648
+ it 'updates the cluster time of the session', retry: 3 do
648
649
  rct = reply_cluster_time
649
650
  expect(session.cluster_time).to eq(rct)
650
651
  end
@@ -664,7 +665,7 @@ shared_examples 'an operation updating cluster time' do
664
665
 
665
666
  it_behaves_like 'does not update the cluster time of the cluster'
666
667
 
667
- it 'does not update the cluster time of the session' do
668
+ it 'does not update the cluster time of the session', retry: 3 do
668
669
  reply_cluster_time
669
670
  expect(session.cluster_time).to be_nil
670
671
  end
@@ -718,7 +719,7 @@ shared_examples 'an operation updating cluster time' do
718
719
  new_cluster_time.merge(Mongo::Cluster::CLUSTER_TIME => new_timestamp)
719
720
  end
720
721
 
721
- it 'includes the advanced cluster time in the second command' do
722
+ it 'includes the advanced cluster time in the second command', retry: 3 do
722
723
  expect(second_command_cluster_time).to eq(advanced_cluster_time)
723
724
  end
724
725
  end
@@ -734,7 +735,7 @@ shared_examples 'an operation updating cluster time' do
734
735
  new_cluster_time.merge(Mongo::Cluster::CLUSTER_TIME => new_timestamp)
735
736
  end
736
737
 
737
- it 'does not advance the cluster time' do
738
+ it 'does not advance the cluster time', retry: 3 do
738
739
  expect(second_command_cluster_time).to eq(reply_cluster_time)
739
740
  end
740
741
  end
@@ -747,7 +748,7 @@ shared_examples 'an operation updating cluster time' do
747
748
  EventSubscriber.started_events[-1].command['$clusterTime']
748
749
  end
749
750
 
750
- it 'includes the received cluster time in the second command' do
751
+ it 'includes the received cluster time in the second command', retry: 3 do
751
752
  reply_cluster_time
752
753
  expect(second_command_cluster_time).to eq(reply_cluster_time)
753
754
  end
@@ -3,6 +3,8 @@ require 'singleton'
3
3
  class SpecConfig
4
4
  include Singleton
5
5
 
6
+ # NB: constructor should not do I/O as SpecConfig may be used by tests
7
+ # only loading the lite spec helper. Do I/O eagerly in accessor methods.
6
8
  def initialize
7
9
  @uri_options = {}
8
10
  if ENV['MONGODB_URI']
@@ -12,11 +14,7 @@ class SpecConfig
12
14
  @addresses = @mongodb_uri.servers
13
15
  @connect_options = { connect: :replica_set, replica_set: @uri_options[:replica_set] }
14
16
  elsif @uri_options[:connect] == :sharded || ENV['TOPOLOGY'] == 'sharded_cluster'
15
- # See SERVER-16836 for why we can only use one host:port
16
- if @mongodb_uri.servers.length > 1
17
- warn "Using only the first mongos (#{@mongodb_uri.servers.first})"
18
- end
19
- @addresses = [ @mongodb_uri.servers.first ]
17
+ @addresses = @mongodb_uri.servers
20
18
  @connect_options = { connect: :sharded }
21
19
  elsif @uri_options[:connect] == :direct
22
20
  @addresses = @mongodb_uri.servers
@@ -45,40 +43,50 @@ class SpecConfig
45
43
  @uri_tls_options[k] = v
46
44
  end
47
45
  end
46
+ end
48
47
 
49
- if @addresses.nil?
50
- # Discover deployment topology
48
+ attr_reader :uri_options, :connect_options
49
+
50
+ def addresses
51
+ @addresses ||= begin
51
52
  if @mongodb_uri
52
- # TLS options need to be merged for evergreen due to
53
- # https://github.com/10gen/mongo-orchestration/issues/268
54
- client = Mongo::Client.new(@mongodb_uri.servers, Mongo::Options::Redacted.new(
55
- server_selection_timeout: 5,
56
- ).merge(@mongodb_uri.uri_options).merge(ssl_options))
57
- @addresses = @mongodb_uri.servers
53
+ @mongodb_uri.servers
58
54
  else
59
- client = Mongo::Client.new(['localhost:27017'], server_selection_timeout: 5)
55
+ client = Mongo::Client.new(['localhost:27017'], server_selection_timeout: 5.02)
56
+ client.cluster.next_primary
60
57
  @addresses = client.cluster.servers_list.map do |server|
61
58
  server.address.to_s
62
59
  end
60
+ client.close(true)
63
61
  end
64
- client.cluster.next_primary
65
- case client.cluster.topology.class.name
62
+ end
63
+ end
64
+
65
+ def connect_options
66
+ @connect_options ||= begin
67
+ # Discover deployment topology.
68
+ # TLS options need to be merged for evergreen due to
69
+ # https://github.com/10gen/mongo-orchestration/issues/268
70
+ client = Mongo::Client.new(addresses, Mongo::Options::Redacted.new(
71
+ server_selection_timeout: 5,
72
+ ).merge(ssl_options))
73
+ options = case client.cluster.topology.class.name
66
74
  when /Replica/
67
- @connect_options = { connect: :replica_set, replica_set: client.cluster.topology.replica_set_name }
75
+ { connect: :replica_set, replica_set: client.cluster.topology.replica_set_name }
68
76
  when /Sharded/
69
- @connect_options = { connect: :sharded }
77
+ { connect: :sharded }
70
78
  when /Single/
71
- @connect_options = { connect: :direct }
79
+ { connect: :direct }
72
80
  when /Unknown/
73
81
  raise "Could not detect topology because the test client failed to connect to MongoDB deployment"
74
82
  else
75
83
  raise "Weird topology #{client.cluster.topology}"
76
84
  end
85
+ client.close(true)
86
+ options
77
87
  end
78
88
  end
79
89
 
80
- attr_reader :uri_options, :addresses, :connect_options
81
-
82
90
  # Environment
83
91
 
84
92
  def ci?
@@ -325,16 +333,18 @@ EOT
325
333
 
326
334
  # Base test options.
327
335
  def base_test_options
336
+ uri_options = @uri_options || {}
328
337
  {
329
338
  max_pool_size: 1,
330
339
  heartbeat_frequency: 20,
340
+ max_read_retries: 5,
331
341
  # The test suite seems to perform a number of operations
332
342
  # requiring server selection. Hence a timeout of 1 here,
333
343
  # together with e.g. a misconfigured replica set,
334
344
  # means the test suite hangs for about 4 seconds before
335
345
  # failing.
336
346
  # Server selection timeout of 1 is insufficient for evergreen.
337
- server_selection_timeout: ssl? ? 4.01 : 2.01,
347
+ server_selection_timeout: uri_options[:server_selection_timeout] || (ssl? ? 4.01 : 2.01),
338
348
  wait_queue_timeout: 2,
339
349
  connect_timeout: 3,
340
350
  max_idle_time: 5