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
@@ -29,12 +29,12 @@ class SpecSetup
29
29
  raise
30
30
  end
31
31
  end
32
- admin_unauthorized_client.close
32
+ admin_unauthorized_client.close(true)
33
33
 
34
34
  # Adds the test user to the test database with permissions on all
35
35
  # databases that will be used in the test suite.
36
36
  create_user(admin_authorized_test_client, SpecConfig.instance.test_user)
37
- admin_authorized_test_client.close
37
+ admin_authorized_test_client.close(true)
38
38
  end
39
39
 
40
40
  def create_user(client, user)
@@ -12,6 +12,93 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ require 'support/transactions/context'
15
16
  require 'support/transactions/operation'
16
17
  require 'support/transactions/spec'
17
18
  require 'support/transactions/test'
19
+
20
+ def define_transactions_spec_tests(test_paths)
21
+
22
+ test_paths.each do |file|
23
+
24
+ spec = Mongo::Transactions::Spec.new(file)
25
+
26
+ context(spec.description) do
27
+ require_wired_tiger
28
+
29
+ define_spec_tests_with_requirements(spec) do |req|
30
+ spec.tests.each do |test|
31
+
32
+ before do
33
+ if test.multiple_mongoses?
34
+ unless SpecConfig.instance.addresses.length > 1
35
+ skip "Test requires multiple mongoses"
36
+ end
37
+ else
38
+ # Many transaction spec tests that do not specifically deal with
39
+ # sharded transactions fail when run against a multi-mongos cluster
40
+ if SpecConfig.instance.addresses.length > 1
41
+ skip "Test does not specify multiple mongoses"
42
+ end
43
+ end
44
+ end
45
+
46
+ context(test.description) do
47
+
48
+ if test.skip_reason
49
+ before(:all) do
50
+ skip test.skip_reason
51
+ end
52
+ end
53
+
54
+ before(:all) do
55
+ if req.satisfied?
56
+ test.setup_test
57
+ end
58
+ end
59
+
60
+ after(:all) do
61
+ if req.satisfied?
62
+ test.teardown_test
63
+ end
64
+ end
65
+
66
+ let(:results) do
67
+ $tx_spec_results_cache ||= {}
68
+ $tx_spec_results_cache[test.object_id] ||= test.run
69
+ end
70
+
71
+ let(:verifier) { Mongo::CRUD::Verifier.new(test) }
72
+
73
+ it 'returns the correct results' do
74
+ verifier.verify_operation_result(test.expected_results, results[:results])
75
+ end
76
+
77
+ if test.outcome && test.outcome.collection_data?
78
+ it 'has the correct data in the collection' do
79
+ results
80
+ verifier.verify_collection_data(
81
+ test.outcome.collection_data,
82
+ results[:contents])
83
+ end
84
+ end
85
+
86
+ if test.expectations
87
+ it 'has the correct number of command_started events' do
88
+ verifier.verify_command_started_event_count(
89
+ test.expectations, results[:events])
90
+ end
91
+
92
+ test.expectations.each_with_index do |expectation, i|
93
+ it "has the correct command_started event #{i}" do
94
+ verifier.verify_command_started_event(
95
+ test.expectations, results[:events], i)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,33 @@
1
+ # Copyright (C) 2019 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+ module Transactions
17
+ Context = Struct.new(
18
+ :session0,
19
+ :session1,
20
+ :session,
21
+ ) do
22
+ def transform_arguments(arguments)
23
+ arguments.dup.tap do |out|
24
+ [:session].each do |key|
25
+ if out[key]
26
+ out[key] = send(key)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -14,126 +14,42 @@
14
14
 
15
15
  module Mongo
16
16
  module Transactions
17
- class Operation
18
-
19
- # Map of operation names to method names.
20
- #
21
- # @since 2.6.0
22
- OPERATIONS = {
23
- 'startTransaction' => :start_transaction,
24
- 'abortTransaction' => :abort_transaction,
25
- 'commitTransaction' => :commit_transaction,
26
- 'withTransaction' => :with_transaction,
27
- 'aggregate' => :aggregate,
28
- 'deleteMany' => :delete_many,
29
- 'deleteOne' => :delete_one,
30
- 'insertMany' => :insert_many,
31
- 'insertOne' => :insert_one,
32
- 'replaceOne' => :replace_one,
33
- 'updateMany' => :update_many,
34
- 'updateOne' => :update_one,
35
- 'findOneAndDelete' => :find_one_and_delete,
36
- 'findOneAndReplace' => :find_one_and_replace,
37
- 'findOneAndUpdate' => :find_one_and_update,
38
- 'bulkWrite' => :bulk_write,
39
- 'count' => :count,
40
- 'countDocuments' => :count_documents,
41
- 'distinct' => :distinct,
42
- 'find' => :find,
43
- 'runCommand' => :run_command,
44
- }.freeze
45
-
46
- # Map of operation options to method names.
47
- #
48
- # @since 2.6.0
49
- ARGUMENT_MAP = {
50
- array_filters: 'arrayFilters',
51
- batch_size: 'batchSize',
52
- collation: 'collation',
53
- read_preference: 'readPreference',
54
- document: 'document',
55
- field_name: 'fieldName',
56
- filter: 'filter',
57
- ordered: 'ordered',
58
- pipeline: 'pipeline',
59
- projection: 'projection',
60
- replacement: 'replacement',
61
- return_document: 'returnDocument',
62
- session: 'session',
63
- sort: 'sort',
64
- update: 'update',
65
- upsert: 'upsert'
66
- }.freeze
67
-
68
- # The operation name.
69
- #
70
- # @return [ String ] name The operation name.
71
- #
72
- # @since 2.6.0
73
- attr_reader :name
74
-
75
- # Instantiate the operation.
76
- #
77
- # @return [ Hash ] spec The operation spec.
78
- #
79
- # @since 2.6.0
80
- def initialize(spec, session0, session1, transaction_session=nil)
81
- @spec = spec
82
- @name = spec['name']
83
- @session0 = session0
84
- @session1 = session1
85
- @arguments = case spec['arguments'] && spec['arguments']['session']
86
- when 'session0'
87
- spec['arguments'].merge('session' => @session0)
88
- when 'session1'
89
- spec['arguments'].merge('session' => @session1)
90
- else
91
- args = spec['arguments'] || {}
92
- if transaction_session
93
- args = args.merge('session' => transaction_session)
94
- end
95
- args
96
- end
97
- end
98
-
99
- attr_reader :arguments
17
+ class Operation < Mongo::CRUD::Operation
18
+ include RSpec::Matchers
19
+
20
+ def execute(target, session0, session1, active_session=nil)
21
+ session = case arguments && arguments['session']
22
+ when 'session0'
23
+ session0
24
+ when 'session1'
25
+ session1
26
+ else
27
+ # active session could be nil
28
+ active_session
29
+ end
100
30
 
101
- # Execute the operation.
102
- #
103
- # @example Execute the operation.
104
- # operation.execute
105
- #
106
- # @param [ Collection ] collection The collection to execute
107
- # the operation on.
108
- #
109
- # @return [ Result ] The result of executing the operation.
110
- #
111
- # @since 2.6.0
112
- def execute(collection)
113
- # Determine which object the operation method should be called on.
114
- obj = case object
115
- when 'session0'
116
- @session0
117
- when 'session1'
118
- @session1
119
- when 'database'
120
- collection.database
121
- else
122
- collection = collection.with(read: read_preference) if collection_read_preference
123
- collection = collection.with(read_concern: read_concern) if read_concern
124
- collection = collection.with(write: write_concern) if write_concern
125
- collection
126
- end
31
+ context = Context.new(
32
+ session0,
33
+ session1,
34
+ session)
127
35
 
128
- if (op_name = OPERATIONS[name]) == :with_transaction
129
- args = [collection]
36
+ op_name = Utils.underscore(name).to_sym
37
+ if op_name == :with_transaction
38
+ args = [target]
130
39
  else
131
40
  args = []
132
41
  end
133
42
  if op_name.nil?
134
43
  raise "Unknown operation #{name}"
135
44
  end
136
- send(op_name, obj, *args)
45
+ result = send(op_name, target, context, *args)
46
+ if result
47
+ if result.is_a?(Hash)
48
+ result = result.dup
49
+ result['error'] = false
50
+ end
51
+ end
52
+ result
137
53
  rescue Mongo::Error::OperationFailure => e
138
54
  err_doc = e.instance_variable_get(:@result).send(:first_document)
139
55
  error_code_name = err_doc['codeName'] || err_doc['writeConcernError'] && err_doc['writeConcernError']['codeName']
@@ -142,55 +58,81 @@ module Mongo
142
58
  # but does return the error code (or we can parse the error code
143
59
  # out of the message).
144
60
  # https://jira.mongodb.org/browse/SERVER-39706
145
- if e.code == 11000
146
- error_code_name = 'DuplicateKey'
147
- else
148
- warn "Error without error code name: #{e.code}"
149
- end
61
+ warn "Error without error code name: #{e.code}"
150
62
  end
151
63
 
152
64
  {
153
- 'errorCodeName' => error_code_name,
65
+ 'errorCode' => e.code,
66
+ 'errorCodeName' => e.code_name,
154
67
  'errorContains' => e.message,
155
68
  'errorLabels' => e.labels,
156
69
  'exception' => e,
70
+ 'error' => true,
157
71
  }
158
72
  rescue Mongo::Error => e
159
73
  {
160
74
  'errorContains' => e.message,
161
75
  'errorLabels' => e.labels,
162
76
  'exception' => e,
77
+ 'error' => true,
78
+ }
79
+ # We do not have a base class for client side BSON-related errors.
80
+ # See https://jira.mongodb.org/browse/RUBY-1806.
81
+ # Rescue this particular exception for the time being.
82
+ rescue BSON::String::IllegalKey => e
83
+ {
84
+ 'exception' => e,
85
+ 'clientError' => true,
86
+ 'error' => true,
163
87
  }
164
88
  end
165
89
 
166
90
  private
167
91
 
168
- def start_transaction(session)
169
- session.start_transaction(Utils.snakeize_hash(arguments['options'])) ; nil
92
+ # operations
93
+
94
+ def run_command(database, context)
95
+ # Convert the first key (i.e. the command name) to a symbol.
96
+ cmd = arguments['command'].dup
97
+ command_name = cmd.first.first
98
+ command_value = cmd.delete(command_name)
99
+ cmd = { command_name.to_sym => command_value }.merge(cmd)
100
+
101
+ opts = Utils.snakeize_hash(context.transform_arguments(options)).dup
102
+ opts[:read] = opts.delete(:read_preference)
103
+ database.command(cmd, opts).documents.first
104
+ end
105
+
106
+ def start_transaction(session, context)
107
+ session.start_transaction(Utils.convert_operation_options(arguments['options']))
108
+ nil
170
109
  end
171
110
 
172
- def commit_transaction(session)
173
- session.commit_transaction ; nil
111
+ def commit_transaction(session, context)
112
+ session.commit_transaction
113
+ nil
174
114
  end
175
115
 
176
- def abort_transaction(session)
177
- session.abort_transaction ; nil
116
+ def abort_transaction(session, context)
117
+ session.abort_transaction
118
+ nil
178
119
  end
179
120
 
180
- def with_transaction(session, collection)
181
- unless callback = @spec['arguments']['callback']
121
+ def with_transaction(session, context, collection)
122
+ unless callback = arguments['callback']
182
123
  raise ArgumentError, 'with_transaction requires a callback to be present'
183
124
  end
184
125
 
185
- if @spec['arguments']['options']
186
- options = Utils.snakeize_hash(@spec['arguments']['options'])
126
+ if arguments['options']
127
+ options = Utils.snakeize_hash(arguments['options'])
187
128
  else
188
129
  options = nil
189
130
  end
190
131
  session.with_transaction(options) do
191
132
  callback['operations'].each do |op_spec|
192
- op = Operation.new(op_spec, @session0, @session1, session)
193
- rv = op.execute(collection)
133
+ op = Operation.new(@crud_test, op_spec)
134
+ target = @crud_test.resolve_target(@crud_test.test_client, op)
135
+ rv = op.execute(target, context.session0, context.session1, session)
194
136
  if rv && rv['exception']
195
137
  raise rv['exception']
196
138
  end
@@ -198,237 +140,45 @@ module Mongo
198
140
  end
199
141
  end
200
142
 
201
- def run_command(database)
202
- # Convert the first key (i.e. the command name) to a symbol.
203
- cmd = command.dup
204
- command_name = cmd.first.first
205
- command_value = cmd.delete(command_name)
206
- cmd = { command_name.to_sym => command_value }.merge(cmd)
207
-
208
- opts = Utils.snakeize_hash(options)
209
- opts[:read] = opts.delete(:read_preference)
210
- database.command(cmd, opts).documents.first
211
- end
212
-
213
- def aggregate(collection)
214
- collection.aggregate(pipeline, options).to_a
215
- end
216
-
217
- def bulk_write(collection)
218
- result = collection.bulk_write(requests, options)
219
- return_doc = {}
220
- return_doc['deletedCount'] = result.deleted_count || 0
221
- return_doc['insertedIds'] = result.inserted_ids if result.inserted_ids
222
- return_doc['upsertedId'] = result.upserted_id if upsert
223
- return_doc['upsertedCount'] = result.upserted_count || 0
224
- return_doc['matchedCount'] = result.matched_count || 0
225
- return_doc['modifiedCount'] = result.modified_count || 0
226
- return_doc['upsertedIds'] = result.upserted_ids if result.upserted_ids
227
- return_doc
228
- end
229
-
230
- def count(collection)
231
- collection.count(filter, options).to_s
232
- end
233
-
234
- def count_documents(collection)
235
- collection.count_documents(filter, options)
236
- end
237
-
238
- def delete_many(collection)
239
- result = collection.delete_many(filter, options)
240
- { 'deletedCount' => result.deleted_count }
241
- end
242
-
243
- def delete_one(collection)
244
- result = collection.delete_one(filter, options)
245
- { 'deletedCount' => result.deleted_count }
246
- end
247
-
248
- def distinct(collection)
249
- collection.distinct(field_name, filter, options)
250
- end
251
-
252
- def find(collection)
253
- opts = modifiers ? options.merge(modifiers: BSON::Document.new(modifiers)) : options
254
- collection.find(filter, opts).to_a
255
- end
256
-
257
- def insert_many(collection)
258
- result = collection.insert_many(documents, options)
259
- { 'insertedIds' => result.inserted_ids }
143
+ def assert_session_transaction_state(collection, context)
144
+ session = context.send(arguments['session'])
145
+ actual_state = session.instance_variable_get('@state').to_s.sub(/^transaction_|_transaction$/, '').sub(/^no$/, 'none')
146
+ expect(actual_state).to eq(arguments['state'])
260
147
  end
261
148
 
262
- def insert_one(collection)
263
- result = collection.insert_one(document, options)
264
- { 'insertedId' => result.inserted_id }
265
- end
266
-
267
- def update_return_doc(result)
268
- return_doc = {}
269
- return_doc['upsertedId'] = result.upserted_id if upsert
270
- return_doc['upsertedCount'] = result.upserted_count
271
- return_doc['matchedCount'] = result.matched_count
272
- return_doc['modifiedCount'] = result.modified_count if result.modified_count
273
- return_doc
274
- end
275
-
276
- def replace_one(collection)
277
- result = collection.replace_one(filter, replacement, options)
278
- update_return_doc(result)
279
- end
280
-
281
- def update_many(collection)
282
- result = collection.update_many(filter, update, options)
283
- update_return_doc(result)
284
- end
285
-
286
- def update_one(collection)
287
- result = collection.update_one(filter, update, options)
288
- update_return_doc(result)
289
- end
290
-
291
- def find_one_and_delete(collection)
292
- collection.find_one_and_delete(filter, options)
293
- end
294
-
295
- def find_one_and_replace(collection)
296
- collection.find_one_and_replace(filter, replacement, options)
297
- end
298
-
299
- def find_one_and_update(collection)
300
- collection.find_one_and_update(filter, update, options)
301
- end
302
-
303
- def object
304
- @spec['object']
305
- end
306
-
307
- def options
308
- ARGUMENT_MAP.reduce({}) do |opts, (key, value)|
309
- arguments.key?(value) ? opts.merge!(key => send(key)) : opts
149
+ def targeted_fail_point(collection, context)
150
+ args = context.transform_arguments(options)
151
+ session = args[:session]
152
+ unless session.pinned_server
153
+ raise ArgumentError, 'Targeted fail point requires session to be pinned to a server'
310
154
  end
311
- end
312
-
313
- def collation
314
- arguments['collation']
315
- end
316
155
 
317
- def command
318
- arguments['command']
319
- end
320
-
321
- def replacement
322
- arguments['replacement']
323
- end
324
-
325
- def sort
326
- arguments['sort']
327
- end
328
-
329
- def projection
330
- arguments['projection']
331
- end
156
+ client = ClusterTools.instance.direct_client(session.pinned_server.address,
157
+ database: 'admin')
158
+ client.command(arguments['failPoint'])
332
159
 
333
- def documents
334
- arguments['documents']
160
+ $disable_fail_points ||= []
161
+ $disable_fail_points << [
162
+ arguments['failPoint'],
163
+ session.pinned_server.address,
164
+ ]
335
165
  end
336
166
 
337
- def document
338
- arguments['document']
339
- end
340
-
341
- def ordered
342
- arguments['ordered']
343
- end
344
-
345
- def field_name
346
- arguments['fieldName']
347
- end
348
-
349
- def filter
350
- arguments['filter']
351
- end
352
-
353
- def pipeline
354
- arguments['pipeline']
355
- end
356
-
357
- def array_filters
358
- arguments['arrayFilters']
359
- end
360
-
361
- def batch_size
362
- arguments['batchSize']
363
- end
364
-
365
- def session
366
- arguments['session']
367
- end
368
-
369
- def requests
370
- arguments['requests'].map do |request|
371
- case request.keys.first
372
- when 'insertOne' then
373
- { insert_one: request['insertOne']['document'] }
374
- when 'updateOne' then
375
- update = request['updateOne']
376
- { update_one: { filter: update['filter'], update: update['update'] } }
377
- when 'name' then
378
- bulk_request(request)
379
- end
167
+ def assert_session_pinned(collection, context)
168
+ args = context.transform_arguments(options)
169
+ session = args[:session]
170
+ unless session.pinned_server
171
+ raise ArgumentError, 'Expected session to be pinned'
380
172
  end
381
173
  end
382
174
 
383
- def bulk_request(request)
384
- op_name = OPERATIONS[request['name']]
385
- op = { op_name => {} }
386
-
387
- op[op_name][:filter] = request['arguments']['filter'] if request['arguments']['filter']
388
- op[op_name][:update] = request['arguments']['update'] if request['arguments']['update']
389
- op[op_name][:upsert] = request['arguments']['upsert'] if request['arguments']['upsert']
390
- op[op_name][:replacement] = request['arguments']['replacement'] if request['arguments']['replacement']
391
- op[op_name][:array_filters] = request['arguments']['arrayFilters'] if request['arguments']['arrayFilters']
392
- op[op_name] = request['arguments']['document'] if request['arguments']['document']
393
- op
394
- end
395
-
396
- def upsert
397
- arguments['upsert']
398
- end
399
-
400
- def return_document
401
- case arguments['returnDocument']
402
- when 'Before'
403
- :before
404
- when 'After'
405
- :after
175
+ def assert_session_unpinned(collection, context)
176
+ args = context.transform_arguments(options)
177
+ session = args[:session]
178
+ if session.pinned_server
179
+ raise ArgumentError, 'Expected session to not be pinned'
406
180
  end
407
181
  end
408
-
409
- def update
410
- arguments['update']
411
- end
412
-
413
- def modifiers
414
- arguments['modifiers']
415
- end
416
-
417
- def read_concern
418
- Utils.snakeize_hash(@spec['collectionOptions'] && @spec['collectionOptions']['readConcern'])
419
- end
420
-
421
- def write_concern
422
- Utils.snakeize_hash(@spec['collectionOptions'] && @spec['collectionOptions']['writeConcern'])
423
- end
424
-
425
- def read_preference
426
- Utils.snakeize_hash(arguments['readPreference'])
427
- end
428
-
429
- def collection_read_preference
430
- Utils.snakeize_hash(@spec['collectionOptions'] && @spec['collectionOptions']['readPreference'])
431
- end
432
182
  end
433
183
  end
434
184
  end