mongo 2.8.0 → 2.9.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 (276) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +12 -0
  5. data/lib/mongo.rb +15 -1
  6. data/lib/mongo/address/ipv6.rb +0 -2
  7. data/lib/mongo/auth/scram/conversation.rb +0 -3
  8. data/lib/mongo/bulk_write/result_combiner.rb +12 -2
  9. data/lib/mongo/client.rb +59 -6
  10. data/lib/mongo/cluster.rb +19 -8
  11. data/lib/mongo/cluster/reapers/cursor_reaper.rb +0 -2
  12. data/lib/mongo/cluster/reapers/socket_reaper.rb +12 -9
  13. data/lib/mongo/collection.rb +1 -1
  14. data/lib/mongo/collection/view/aggregation.rb +5 -1
  15. data/lib/mongo/collection/view/builder/map_reduce.rb +1 -1
  16. data/lib/mongo/collection/view/change_stream.rb +30 -10
  17. data/lib/mongo/collection/view/iterable.rb +13 -6
  18. data/lib/mongo/collection/view/map_reduce.rb +12 -10
  19. data/lib/mongo/collection/view/readable.rb +19 -14
  20. data/lib/mongo/cursor.rb +12 -8
  21. data/lib/mongo/database.rb +10 -7
  22. data/lib/mongo/database/view.rb +18 -11
  23. data/lib/mongo/error.rb +2 -2
  24. data/lib/mongo/error/connection_check_out_timeout.rb +49 -0
  25. data/lib/mongo/error/operation_failure.rb +9 -9
  26. data/lib/mongo/error/parser.rb +25 -3
  27. data/lib/mongo/error/pool_closed_error.rb +43 -0
  28. data/lib/mongo/error/sdam_error_detection.rb +18 -0
  29. data/lib/mongo/grid/file/chunk.rb +0 -2
  30. data/lib/mongo/grid/fs_bucket.rb +26 -12
  31. data/lib/mongo/grid/stream/read.rb +36 -21
  32. data/lib/mongo/index/view.rb +11 -7
  33. data/lib/mongo/logger.rb +0 -2
  34. data/lib/mongo/monitoring.rb +31 -0
  35. data/lib/mongo/monitoring/cmap_log_subscriber.rb +53 -0
  36. data/lib/mongo/monitoring/event.rb +1 -0
  37. data/lib/mongo/monitoring/event/cmap.rb +25 -0
  38. data/lib/mongo/monitoring/event/cmap/base.rb +28 -0
  39. data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +78 -0
  40. data/lib/mongo/monitoring/event/cmap/connection_check_out_started.rb +56 -0
  41. data/lib/mongo/monitoring/event/cmap/connection_checked_in.rb +63 -0
  42. data/lib/mongo/monitoring/event/cmap/connection_checked_out.rb +64 -0
  43. data/lib/mongo/monitoring/event/cmap/connection_closed.rb +103 -0
  44. data/lib/mongo/monitoring/event/cmap/connection_created.rb +64 -0
  45. data/lib/mongo/monitoring/event/cmap/connection_ready.rb +64 -0
  46. data/lib/mongo/monitoring/event/cmap/pool_cleared.rb +57 -0
  47. data/lib/mongo/monitoring/event/cmap/pool_closed.rb +57 -0
  48. data/lib/mongo/monitoring/event/cmap/pool_created.rb +63 -0
  49. data/lib/mongo/monitoring/event/command_started.rb +12 -3
  50. data/lib/mongo/monitoring/publishable.rb +10 -2
  51. data/lib/mongo/operation.rb +0 -1
  52. data/lib/mongo/operation/find/legacy/result.rb +1 -0
  53. data/lib/mongo/operation/list_collections/result.rb +7 -1
  54. data/lib/mongo/operation/result.rb +10 -1
  55. data/lib/mongo/operation/shared/executable.rb +15 -0
  56. data/lib/mongo/operation/shared/result/use_legacy_error_parser.rb +29 -0
  57. data/lib/mongo/operation/shared/specifiable.rb +0 -16
  58. data/lib/mongo/operation/update/legacy/result.rb +1 -0
  59. data/lib/mongo/protocol/compressed.rb +0 -2
  60. data/lib/mongo/protocol/msg.rb +25 -2
  61. data/lib/mongo/retryable.rb +171 -33
  62. data/lib/mongo/server.rb +26 -7
  63. data/lib/mongo/server/app_metadata.rb +0 -2
  64. data/lib/mongo/server/connectable.rb +8 -2
  65. data/lib/mongo/server/connection.rb +83 -13
  66. data/lib/mongo/server/connection_base.rb +1 -1
  67. data/lib/mongo/server/connection_pool.rb +439 -43
  68. data/lib/mongo/server/monitor/connection.rb +4 -1
  69. data/lib/mongo/session.rb +37 -5
  70. data/lib/mongo/session/session_pool.rb +2 -2
  71. data/lib/mongo/socket.rb +0 -2
  72. data/lib/mongo/socket/ssl.rb +0 -2
  73. data/lib/mongo/uri.rb +127 -66
  74. data/lib/mongo/uri/srv_protocol.rb +35 -13
  75. data/lib/mongo/version.rb +1 -1
  76. data/spec/README.md +190 -63
  77. data/spec/integration/change_stream_spec.rb +64 -0
  78. data/spec/integration/command_spec.rb +0 -7
  79. data/spec/integration/error_detection_spec.rb +39 -0
  80. data/spec/integration/read_concern.rb +83 -0
  81. data/spec/integration/retryable_writes_spec.rb +6 -50
  82. data/spec/integration/sdam_error_handling_spec.rb +60 -7
  83. data/spec/integration/ssl_uri_options_spec.rb +24 -0
  84. data/spec/integration/step_down_spec.rb +197 -0
  85. data/spec/lite_spec_helper.rb +4 -0
  86. data/spec/mongo/client_construction_spec.rb +42 -17
  87. data/spec/mongo/client_spec.rb +32 -1
  88. data/spec/mongo/cluster/socket_reaper_spec.rb +2 -2
  89. data/spec/mongo/cluster_spec.rb +36 -2
  90. data/spec/mongo/collection/view/aggregation_spec.rb +2 -0
  91. data/spec/mongo/collection/view/change_stream_spec.rb +28 -28
  92. data/spec/mongo/collection/view/readable_spec.rb +1 -1
  93. data/spec/mongo/collection/view_spec.rb +3 -1
  94. data/spec/mongo/cursor_spec.rb +5 -5
  95. data/spec/mongo/error/parser_spec.rb +61 -1
  96. data/spec/mongo/grid/stream/read_spec.rb +2 -2
  97. data/spec/mongo/monitoring/event/cmap/connection_check_out_failed_spec.rb +23 -0
  98. data/spec/mongo/monitoring/event/cmap/connection_check_out_started_spec.rb +19 -0
  99. data/spec/mongo/monitoring/event/cmap/connection_checked_in_spec.rb +23 -0
  100. data/spec/mongo/monitoring/event/cmap/connection_checked_out_spec.rb +23 -0
  101. data/spec/mongo/monitoring/event/cmap/connection_closed_spec.rb +27 -0
  102. data/spec/mongo/monitoring/event/cmap/connection_created_spec.rb +24 -0
  103. data/spec/mongo/monitoring/event/cmap/connection_ready_spec.rb +24 -0
  104. data/spec/mongo/monitoring/event/cmap/pool_cleared_spec.rb +19 -0
  105. data/spec/mongo/monitoring/event/cmap/pool_closed_spec.rb +19 -0
  106. data/spec/mongo/monitoring/event/cmap/pool_created_spec.rb +26 -0
  107. data/spec/mongo/operation/delete/bulk_spec.rb +1 -6
  108. data/spec/mongo/operation/delete/command_spec.rb +1 -1
  109. data/spec/mongo/operation/delete/op_msg_spec.rb +1 -1
  110. data/spec/mongo/operation/delete_spec.rb +4 -4
  111. data/spec/mongo/operation/insert/bulk_spec.rb +1 -1
  112. data/spec/mongo/operation/insert/command_spec.rb +1 -1
  113. data/spec/mongo/operation/insert/op_msg_spec.rb +1 -1
  114. data/spec/mongo/operation/update/bulk_spec.rb +1 -1
  115. data/spec/mongo/operation/update/command_spec.rb +2 -2
  116. data/spec/mongo/operation/update/op_msg_spec.rb +2 -2
  117. data/spec/mongo/protocol/msg_spec.rb +11 -0
  118. data/spec/mongo/retryable_spec.rb +78 -25
  119. data/spec/mongo/server/connection_pool_spec.rb +661 -126
  120. data/spec/mongo/server/connection_spec.rb +55 -7
  121. data/spec/mongo/server_spec.rb +5 -0
  122. data/spec/mongo/uri/srv_protocol_spec.rb +135 -2
  123. data/spec/mongo/uri_option_parsing_spec.rb +511 -0
  124. data/spec/mongo/uri_spec.rb +42 -6
  125. data/spec/spec_helper.rb +1 -84
  126. data/spec/spec_tests/cmap_spec.rb +50 -0
  127. data/spec/spec_tests/command_monitoring_spec.rb +7 -18
  128. data/spec/spec_tests/crud_spec.rb +3 -49
  129. data/spec/spec_tests/data/cmap/connection-must-have-id.yml +21 -0
  130. data/spec/spec_tests/data/cmap/connection-must-order-ids.yml +21 -0
  131. data/spec/spec_tests/data/cmap/pool-checkin-destroy-closed.yml +24 -0
  132. data/spec/spec_tests/data/cmap/pool-checkin-destroy-stale.yml +24 -0
  133. data/spec/spec_tests/data/cmap/pool-checkin-make-available.yml +21 -0
  134. data/spec/spec_tests/data/cmap/pool-checkin.yml +18 -0
  135. data/spec/spec_tests/data/cmap/pool-checkout-connection.yml +13 -0
  136. data/spec/spec_tests/data/cmap/pool-checkout-error-closed.yml +28 -0
  137. data/spec/spec_tests/data/cmap/pool-checkout-multiple.yml +34 -0
  138. data/spec/spec_tests/data/cmap/pool-checkout-no-idle.yml +31 -0
  139. data/spec/spec_tests/data/cmap/pool-checkout-no-stale.yml +29 -0
  140. data/spec/spec_tests/data/cmap/pool-close-destroy-conns.yml +26 -0
  141. data/spec/spec_tests/data/cmap/pool-close.yml +11 -0
  142. data/spec/spec_tests/data/cmap/pool-create-max-size.yml +56 -0
  143. data/spec/spec_tests/data/cmap/pool-create-min-size.yml +27 -0
  144. data/spec/spec_tests/data/cmap/pool-create-with-options.yml +20 -0
  145. data/spec/spec_tests/data/cmap/pool-create.yml +12 -0
  146. data/spec/spec_tests/data/cmap/wait-queue-fairness.yml +94 -0
  147. data/spec/spec_tests/data/cmap/wait-queue-timeout.yml +41 -0
  148. data/spec/spec_tests/data/retryable_reads/aggregate-serverErrors.yml +157 -0
  149. data/spec/spec_tests/data/retryable_reads/aggregate.yml +87 -0
  150. data/spec/spec_tests/data/retryable_reads/changeStreams-client.watch-serverErrors.yml +149 -0
  151. data/spec/spec_tests/data/retryable_reads/changeStreams-client.watch.yml +61 -0
  152. data/spec/spec_tests/data/retryable_reads/changeStreams-db.coll.watch-serverErrors.yml +149 -0
  153. data/spec/spec_tests/data/retryable_reads/changeStreams-db.coll.watch.yml +65 -0
  154. data/spec/spec_tests/data/retryable_reads/changeStreams-db.watch-serverErrors.yml +153 -0
  155. data/spec/spec_tests/data/retryable_reads/changeStreams-db.watch.yml +61 -0
  156. data/spec/spec_tests/data/retryable_reads/count-serverErrors.yml +150 -0
  157. data/spec/spec_tests/data/retryable_reads/count.yml +64 -0
  158. data/spec/spec_tests/data/retryable_reads/countDocuments-serverErrors.yml +150 -0
  159. data/spec/spec_tests/data/retryable_reads/countDocuments.yml +64 -0
  160. data/spec/spec_tests/data/retryable_reads/distinct-serverErrors.yml +156 -0
  161. data/spec/spec_tests/data/retryable_reads/distinct.yml +71 -0
  162. data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-serverErrors.yml +148 -0
  163. data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount.yml +62 -0
  164. data/spec/spec_tests/data/retryable_reads/find-serverErrors.yml +160 -0
  165. data/spec/spec_tests/data/retryable_reads/find.yml +86 -0
  166. data/spec/spec_tests/data/retryable_reads/findOne-serverErrors.yml +154 -0
  167. data/spec/spec_tests/data/retryable_reads/findOne.yml +68 -0
  168. data/spec/spec_tests/data/retryable_reads/gridfs-download-serverErrors.yml +173 -0
  169. data/spec/spec_tests/data/retryable_reads/gridfs-download.yml +79 -0
  170. data/spec/spec_tests/data/retryable_reads/gridfs-downloadByName-serverErrors.yml +174 -0
  171. data/spec/spec_tests/data/retryable_reads/gridfs-downloadByName.yml +79 -0
  172. data/spec/spec_tests/data/retryable_reads/listCollectionNames-serverErrors.yml +143 -0
  173. data/spec/spec_tests/data/retryable_reads/listCollectionNames.yml +59 -0
  174. data/spec/spec_tests/data/retryable_reads/listCollectionObjects-serverErrors.yml +144 -0
  175. data/spec/spec_tests/data/retryable_reads/listCollectionObjects.yml +59 -0
  176. data/spec/spec_tests/data/retryable_reads/listCollections-serverErrors.yml +143 -0
  177. data/spec/spec_tests/data/retryable_reads/listCollections.yml +59 -0
  178. data/spec/spec_tests/data/retryable_reads/listDatabaseNames-serverErrors.yml +143 -0
  179. data/spec/spec_tests/data/retryable_reads/listDatabaseNames.yml +59 -0
  180. data/spec/spec_tests/data/retryable_reads/listDatabaseObjects-serverErrors.yml +144 -0
  181. data/spec/spec_tests/data/retryable_reads/listDatabaseObjects.yml +59 -0
  182. data/spec/spec_tests/data/retryable_reads/listDatabases-serverErrors.yml +144 -0
  183. data/spec/spec_tests/data/retryable_reads/listDatabases.yml +59 -0
  184. data/spec/spec_tests/data/retryable_reads/listIndexNames-serverErrors.yml +144 -0
  185. data/spec/spec_tests/data/retryable_reads/listIndexNames.yml +60 -0
  186. data/spec/spec_tests/data/retryable_reads/listIndexes-serverErrors.yml +145 -0
  187. data/spec/spec_tests/data/retryable_reads/listIndexes.yml +60 -0
  188. data/spec/spec_tests/data/retryable_reads/mapReduce.yml +60 -0
  189. data/spec/spec_tests/data/retryable_writes/bulkWrite-serverErrors.yml +10 -7
  190. data/spec/spec_tests/data/retryable_writes/bulkWrite.yml +15 -22
  191. data/spec/spec_tests/data/retryable_writes/deleteMany.yml +22 -0
  192. data/spec/spec_tests/data/retryable_writes/deleteOne-serverErrors.yml +8 -7
  193. data/spec/spec_tests/data/retryable_writes/deleteOne.yml +5 -8
  194. data/spec/spec_tests/data/retryable_writes/findOneAndDelete-serverErrors.yml +8 -7
  195. data/spec/spec_tests/data/retryable_writes/findOneAndDelete.yml +5 -8
  196. data/spec/spec_tests/data/retryable_writes/findOneAndReplace-serverErrors.yml +8 -7
  197. data/spec/spec_tests/data/retryable_writes/findOneAndReplace.yml +5 -8
  198. data/spec/spec_tests/data/retryable_writes/findOneAndUpdate-serverErrors.yml +8 -7
  199. data/spec/spec_tests/data/retryable_writes/findOneAndUpdate.yml +5 -8
  200. data/spec/spec_tests/data/retryable_writes/insertMany-serverErrors.yml +8 -7
  201. data/spec/spec_tests/data/retryable_writes/insertMany.yml +5 -8
  202. data/spec/spec_tests/data/retryable_writes/insertOne-serverErrors.yml +10 -45
  203. data/spec/spec_tests/data/retryable_writes/insertOne.yml +5 -8
  204. data/spec/spec_tests/data/retryable_writes/replaceOne-serverErrors.yml +8 -7
  205. data/spec/spec_tests/data/retryable_writes/replaceOne.yml +5 -8
  206. data/spec/spec_tests/data/retryable_writes/updateMany.yml +27 -0
  207. data/spec/spec_tests/data/retryable_writes/updateOne-serverErrors.yml +8 -7
  208. data/spec/spec_tests/data/retryable_writes/updateOne.yml +5 -14
  209. data/spec/spec_tests/data/transactions/abort.yml +7 -2
  210. data/spec/spec_tests/data/transactions/bulk.yml +7 -2
  211. data/spec/spec_tests/data/transactions/causal-consistency.yml +11 -4
  212. data/spec/spec_tests/data/transactions/commit.yml +11 -4
  213. data/spec/spec_tests/data/transactions/count.yml +64 -0
  214. data/spec/spec_tests/data/transactions/delete.yml +7 -2
  215. data/spec/spec_tests/data/transactions/error-labels.yml +8 -2
  216. data/spec/spec_tests/data/transactions/errors.yml +7 -2
  217. data/spec/spec_tests/data/transactions/findOneAndDelete.yml +7 -2
  218. data/spec/spec_tests/data/transactions/findOneAndReplace.yml +7 -2
  219. data/spec/spec_tests/data/transactions/findOneAndUpdate.yml +7 -2
  220. data/spec/spec_tests/data/transactions/insert.yml +9 -2
  221. data/spec/spec_tests/data/transactions/isolation.yml +7 -2
  222. data/spec/spec_tests/data/transactions/read-concern.yml +15 -6
  223. data/spec/spec_tests/data/transactions/read-pref.yml +7 -2
  224. data/spec/spec_tests/data/transactions/reads.yml +8 -48
  225. data/spec/spec_tests/data/transactions/retryable-abort.yml +7 -2
  226. data/spec/spec_tests/data/transactions/retryable-commit.yml +7 -2
  227. data/spec/spec_tests/data/transactions/retryable-writes.yml +7 -2
  228. data/spec/spec_tests/data/transactions/run-command.yml +7 -2
  229. data/spec/spec_tests/data/transactions/transaction-options.yml +7 -2
  230. data/spec/spec_tests/data/transactions/update.yml +7 -2
  231. data/spec/spec_tests/data/transactions/write-concern.yml +7 -2
  232. data/spec/spec_tests/data/transactions_api/callback-aborts.yml +6 -1
  233. data/spec/spec_tests/data/transactions_api/callback-commits.yml +6 -1
  234. data/spec/spec_tests/data/transactions_api/callback-retry.yml +6 -1
  235. data/spec/spec_tests/data/transactions_api/commit-retry.yml +6 -1
  236. data/spec/spec_tests/data/transactions_api/commit-transienttransactionerror-4.2.yml +6 -3
  237. data/spec/spec_tests/data/transactions_api/commit-transienttransactionerror.yml +6 -1
  238. data/spec/spec_tests/data/transactions_api/commit-writeconcernerror.yml +6 -1
  239. data/spec/spec_tests/data/transactions_api/commit.yml +6 -1
  240. data/spec/spec_tests/data/transactions_api/transaction-options.yml +6 -1
  241. data/spec/spec_tests/retryable_reads_spec.rb +11 -0
  242. data/spec/spec_tests/retryable_writes_spec.rb +4 -69
  243. data/spec/spec_tests/transactions_api_spec.rb +42 -37
  244. data/spec/spec_tests/transactions_spec.rb +42 -33
  245. data/spec/support/authorization.rb +12 -0
  246. data/spec/support/change_streams/operation.rb +1 -1
  247. data/spec/support/client_registry.rb +20 -0
  248. data/spec/support/cluster_config.rb +16 -15
  249. data/spec/support/cluster_tools.rb +346 -0
  250. data/spec/support/cmap.rb +367 -0
  251. data/spec/support/cmap/verifier.rb +46 -0
  252. data/spec/support/command_monitoring.rb +4 -6
  253. data/spec/support/common_shortcuts.rb +6 -0
  254. data/spec/support/connection_string.rb +2 -2
  255. data/spec/support/crud.rb +171 -184
  256. data/spec/support/crud/operation.rb +43 -0
  257. data/spec/support/crud/outcome.rb +53 -0
  258. data/spec/support/crud/read.rb +102 -12
  259. data/spec/support/crud/requirement.rb +69 -0
  260. data/spec/support/crud/spec.rb +68 -0
  261. data/spec/support/crud/test.rb +141 -0
  262. data/spec/support/crud/verifier.rb +96 -18
  263. data/spec/support/crud/write.rb +18 -3
  264. data/spec/support/event_subscriber.rb +15 -0
  265. data/spec/support/primary_socket.rb +2 -2
  266. data/spec/support/spec_config.rb +89 -20
  267. data/spec/support/transactions.rb +2 -306
  268. data/spec/support/transactions/operation.rb +7 -7
  269. data/spec/support/transactions/spec.rb +28 -0
  270. data/spec/support/transactions/test.rb +191 -0
  271. data/spec/support/utils.rb +123 -0
  272. metadata +202 -9
  273. metadata.gz.sig +0 -0
  274. data/lib/mongo/server/connection_pool/queue.rb +0 -359
  275. data/spec/mongo/server/connection_pool/queue_spec.rb +0 -353
  276. data/spec/support/transactions/verifier.rb +0 -97
@@ -0,0 +1,53 @@
1
+ # Copyright (C) 2014-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 CRUD
17
+ class Outcome
18
+ def initialize(spec)
19
+ if spec.nil?
20
+ raise ArgumentError, 'Outcome specification cannot be nil'
21
+ end
22
+ @result = spec['result']
23
+ @collection = spec['collection']
24
+ @error = spec['error']
25
+ end
26
+
27
+ def error?
28
+ !!@error
29
+ end
30
+
31
+ def collection_data?
32
+ !!collection_data
33
+ end
34
+
35
+ # The expected data in the collection as an outcome after running an
36
+ # operation.
37
+ #
38
+ # @return [ Array<Hash> ] The list of documents expected to be in the collection.
39
+ def collection_data
40
+ @collection && @collection['data']
41
+ end
42
+
43
+ def collection_name
44
+ @collection && @collection['name']
45
+ end
46
+
47
+ # The expected result of running an operation.
48
+ #
49
+ # @return [ Array<Hash> ] The expected result.
50
+ attr_reader :result
51
+ end
52
+ end
53
+ end
@@ -42,23 +42,45 @@ module Mongo
42
42
  'nearest' => :nearest
43
43
  }.freeze
44
44
 
45
- # The operation name.
46
- #
47
- # @return [ String ] name The operation name.
48
- #
49
- # @since 2.0.0
50
- attr_reader :name
51
-
52
45
  # Instantiate the operation.
53
46
  #
54
47
  # @return [ Hash ] spec The operation spec.
55
48
  #
56
49
  # @since 2.0.0
57
- def initialize(spec)
50
+ def initialize(spec, outcome_spec = nil)
58
51
  @spec = spec
52
+ @outcome = Outcome.new(outcome_spec || spec)
59
53
  @name = spec['name']
60
54
  end
61
55
 
56
+ # The operation name.
57
+ #
58
+ # @return [ String ] name The operation name.
59
+ #
60
+ # @since 2.0.0
61
+ attr_reader :name
62
+
63
+ attr_reader :outcome
64
+
65
+ def object
66
+ @spec['object'] || 'collection'
67
+ end
68
+
69
+ # Which collection to verify results from.
70
+ # Returns the collection name specified on the operation, or
71
+ # the collection name for the entire spec file.
72
+ def verify_collection_name
73
+ if outcome && outcome.collection_name
74
+ outcome.collection_name
75
+ else
76
+ spec.collection_name.tap do |cn|
77
+ if cn.nil?
78
+ raise "Collection name cannot be nil"
79
+ end
80
+ end
81
+ end
82
+ end
83
+
62
84
  # Execute the operation.
63
85
  #
64
86
  # @example Execute the operation.
@@ -69,11 +91,17 @@ module Mongo
69
91
  # @return [ Result, Array<Hash> ] The result of executing the operation.
70
92
  #
71
93
  # @since 2.0.0
72
- def execute(collection)
73
- send(camel_to_snake(name), collection)
94
+ def execute(target)
95
+ op_name = Utils.underscore(name)
96
+ if target.is_a?(Mongo::Database)
97
+ op_name = "db_#{op_name}"
98
+ elsif target.is_a?(Mongo::Client)
99
+ op_name= "client_#{op_name}"
100
+ end
101
+ send(op_name, target)
74
102
  end
75
103
 
76
- # Whether the operation is expected to have restuls.
104
+ # Whether the operation is expected to have results.
77
105
  #
78
106
  # @example Whether the operation is expected to have results.
79
107
  # operation.has_results?
@@ -105,8 +133,10 @@ module Mongo
105
133
  end
106
134
 
107
135
  def estimated_document_count(collection)
136
+ # estimated_document_count defaults options to {}
137
+ args = arguments || {}
108
138
  options = ARGUMENT_MAP.reduce({}) do |opts, (key, value)|
109
- opts.merge!(key => arguments[value]) if arguments[value]
139
+ opts.merge!(key => args[value]) if args[value]
110
140
  opts
111
141
  end
112
142
  collection.estimated_document_count(options)
@@ -125,6 +155,66 @@ module Mongo
125
155
  (read_preference ? collection.with(read: read_preference) : collection).find(filter, opts).to_a
126
156
  end
127
157
 
158
+ def find_one(collection)
159
+ find(collection).first
160
+ end
161
+
162
+ def client_list_databases(client)
163
+ client.list_databases
164
+ end
165
+
166
+ def client_list_database_names(client)
167
+ client.list_databases({}, true)
168
+ end
169
+
170
+ def client_list_database_objects(client)
171
+ client.list_mongo_databases
172
+ end
173
+
174
+ def db_list_collections(database)
175
+ database.list_collections
176
+ end
177
+
178
+ def db_list_collection_names(database)
179
+ database.collection_names
180
+ end
181
+
182
+ def db_list_collection_objects(database)
183
+ database.collections
184
+ end
185
+
186
+ def list_indexes(collection)
187
+ collection.indexes.to_a
188
+ end
189
+
190
+ def watch(collection)
191
+ collection.watch
192
+ end
193
+
194
+ def db_watch(database)
195
+ database.watch
196
+ end
197
+
198
+ def client_watch(client)
199
+ client.watch
200
+ end
201
+
202
+ def download(fs_bucket)
203
+ stream = fs_bucket.open_download_stream(BSON::ObjectId.from_string(arguments['id']['$oid']))
204
+ stream.read
205
+ end
206
+
207
+ def download_by_name(fs_bucket)
208
+ stream = fs_bucket.open_download_stream_by_name(arguments['filename'])
209
+ stream.read
210
+ end
211
+
212
+ def map_reduce(collection)
213
+ view = Mongo::Collection::View.new(collection)
214
+ mr = Mongo::Collection::View::MapReduce.new(view, arguments['map']['$code'], arguments['reduce']['$code'])
215
+ mr.to_a
216
+ end
217
+
128
218
  def options
129
219
  ARGUMENT_MAP.reduce({}) do |opts, (key, value)|
130
220
  value = if arguments[value].is_a?(Hash) && arguments[value]['$numberLong']
@@ -0,0 +1,69 @@
1
+ module Mongo
2
+ module CRUD
3
+ class Requirement
4
+ YAML_KEYS = %w(minServerVersion maxServerVersion topology).freeze
5
+
6
+ def initialize(spec)
7
+ @min_server_version = spec['minServerVersion']
8
+ @max_server_version = spec['maxServerVersion']
9
+ @topologies = if topologies = spec['topology']
10
+ topologies.map do |topology|
11
+ {'replicaset' => :replica_set, 'single' => :single, 'sharded' => :sharded}[topology]
12
+ end
13
+ else
14
+ nil
15
+ end
16
+ end
17
+
18
+ attr_reader :min_server_version
19
+ attr_reader :max_server_version
20
+ attr_reader :topologies
21
+
22
+ def short_min_server_version
23
+ if min_server_version
24
+ min_server_version.split('.')[0..1].join('.')
25
+ else
26
+ nil
27
+ end
28
+ end
29
+
30
+ def short_max_server_version
31
+ if max_server_version
32
+ max_server_version.split('.')[0..1].join('.')
33
+ else
34
+ nil
35
+ end
36
+ end
37
+
38
+ def satisfied?
39
+ cc = ClusterConfig.instance
40
+ ok = true
41
+ if short_min_server_version
42
+ ok &&= cc.fcv_ish >= short_min_server_version
43
+ end
44
+ if max_server_version
45
+ ok &&= cc.server_version <= max_server_version
46
+ end
47
+ if topologies
48
+ ok &&= topologies.include?(cc.topology)
49
+ end
50
+ ok
51
+ end
52
+
53
+ def description
54
+ versions = [min_server_version, max_server_version].compact
55
+ if versions.any?
56
+ versions = versions.join('-')
57
+ else
58
+ versions = nil
59
+ end
60
+ topologies = if self.topologies
61
+ self.topologies.map(&:to_s).join(',')
62
+ else
63
+ nil
64
+ end
65
+ [versions, topologies].compact.join('/')
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,68 @@
1
+ module Mongo
2
+ module CRUD
3
+ # Represents a CRUD specification test.
4
+ class Spec
5
+
6
+ # Instantiate the new spec.
7
+ #
8
+ # @example Create the spec.
9
+ # Spec.new(file)
10
+ #
11
+ # @param [ String ] file The name of the file.
12
+ #
13
+ # @since 2.0.0
14
+ def initialize(file)
15
+ contents = ERB.new(File.read(file)).result
16
+
17
+ # Since Ruby driver binds a client to a database, change the
18
+ # database name in the spec to the one we are using
19
+ contents.sub!(/"retryable-reads-tests"/, '"ruby-driver"')
20
+ contents.sub!(/"transaction-tests"/, '"ruby-driver"')
21
+ contents.sub!(/"withTransaction-tests"/, '"ruby-driver"')
22
+
23
+ @spec = YAML.load(ERB.new(contents).result)
24
+ @description = File.basename(file)
25
+ @data = @spec['data']
26
+ @tests = @spec['tests']
27
+
28
+ @requirements = if run_on = @spec['runOn']
29
+ run_on.map do |spec|
30
+ Requirement.new(spec)
31
+ end
32
+ elsif Requirement::YAML_KEYS.any? { |key| @spec.key?(key) }
33
+ [Requirement.new(@spec)]
34
+ else
35
+ nil
36
+ end
37
+ end
38
+
39
+ # @return [ String ] description The spec description.
40
+ #
41
+ # @since 2.0.0
42
+ attr_reader :description
43
+
44
+ attr_reader :requirements
45
+
46
+ def collection_name
47
+ # Older spec tests do not specify a collection name, thus
48
+ # we provide a default here
49
+ @spec['collection_name'] || 'crud_spec_test'
50
+ end
51
+
52
+ def bucket_name
53
+ @spec['bucket_name']
54
+ end
55
+
56
+ def database_name
57
+ @spec['database_name']
58
+ end
59
+
60
+ # Get a list of Test instances, one for each test definition.
61
+ def tests
62
+ @tests.map do |test|
63
+ Mongo::CRUD::CRUDTest.new(@data, test)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,141 @@
1
+ module Mongo
2
+ module CRUD
3
+
4
+ # Represents a single CRUD test.
5
+ #
6
+ # @since 2.0.0
7
+ class CRUDTest
8
+
9
+ # The test description.
10
+ #
11
+ # @return [ String ] description The test description.
12
+ #
13
+ # @since 2.0.0
14
+ attr_reader :description
15
+
16
+ # Spec tests have configureFailPoint as a string, make it a string here too
17
+ FAIL_POINT_BASE_COMMAND = BSON::Document.new(
18
+ 'configureFailPoint' => "onPrimaryTransactionalWrite",
19
+ ).freeze
20
+
21
+ # Instantiate the new CRUDTest.
22
+ #
23
+ # data can be an array of hashes, with each hash corresponding to a
24
+ # document to be inserted into the collection whose name is given in
25
+ # collection_name as configured in the YAML file. Alternatively data
26
+ # can be a map of collection names to arrays of hashes.
27
+ #
28
+ # @param [ Hash | Array<Hash> ] data The documents the collection
29
+ # must have before the test runs.
30
+ # @param [ Hash ] test The test specification.
31
+ #
32
+ # @since 2.0.0
33
+ def initialize(data, test)
34
+ @data = data
35
+ if test['failPoint']
36
+ @fail_point_command = FAIL_POINT_BASE_COMMAND.merge(test['failPoint'])
37
+ end
38
+ @description = test['description']
39
+ @client_options = Utils.convert_client_options(test['clientOptions'] || {})
40
+ if test['operations']
41
+ @operations = test['operations'].map do |op_spec|
42
+ Operation.get(op_spec)
43
+ end
44
+ else
45
+ @operations = [Operation.get(test['operation'], test['outcome'])]
46
+ end
47
+ @expectations = test['expectations']
48
+ end
49
+
50
+ attr_reader :client_options
51
+
52
+ # Operations to be performed by the test.
53
+ #
54
+ # For CRUD tests, there is one operation for test. For retryable writes,
55
+ # there are multiple operations for each test. In either case we build
56
+ # an array of operations.
57
+ attr_reader :operations
58
+
59
+ # The expected command monitoring events
60
+ attr_reader :expectations
61
+
62
+ # Run the test.
63
+ #
64
+ # The specified number of operations are executed, so that the
65
+ # test can assert on the outcome of each specified operation in turn.
66
+ #
67
+ # @param [ Client ] client The client the test
68
+ # should be run with.
69
+ # @param [ Integer ] num_ops Number of operations to run.
70
+ #
71
+ # @return [ Result, Array<Hash> ] The result(s) of running the test.
72
+ #
73
+ # @since 2.0.0
74
+ def run(spec, client, num_ops)
75
+ result = nil
76
+ 1.upto(num_ops) do |i|
77
+ 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
90
+ result = operation.execute(target)
91
+ end
92
+ result
93
+ end
94
+
95
+ class DataConverter
96
+ include Mongo::GridFS::Convertible
97
+ end
98
+
99
+ def setup_test(spec, client)
100
+ clear_fail_point(client)
101
+ if @data.is_a?(Array)
102
+ collection = client[spec.collection_name]
103
+ collection.delete_many
104
+ collection.insert_many(@data)
105
+ elsif @data.is_a?(Hash)
106
+ converter = DataConverter.new
107
+ @data.each do |collection_name, data|
108
+ collection = client[collection_name]
109
+ collection.delete_many
110
+ data = converter.transform_docs(data)
111
+ collection.insert_many(data)
112
+ end
113
+ else
114
+ raise "Unknown type of data: #{@data}"
115
+ end
116
+ set_up_fail_point(client)
117
+ end
118
+
119
+ def set_up_fail_point(client)
120
+ if @fail_point_command
121
+ client.use(:admin).command(@fail_point_command)
122
+ end
123
+ end
124
+
125
+ def clear_fail_point(client)
126
+ if @fail_point_command
127
+ client.use(:admin).command(@fail_point_command.merge(mode: "off"))
128
+ end
129
+ end
130
+
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
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end