mongo 2.9.2 → 2.10.0.rc0

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