mongo 2.0.6 → 2.1.0

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 (317) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +5 -2
  3. data/lib/mongo/address/ipv4.rb +6 -1
  4. data/lib/mongo/address/unix.rb +2 -2
  5. data/lib/mongo/address.rb +18 -10
  6. data/lib/mongo/auth/cr/conversation.rb +1 -1
  7. data/lib/mongo/auth/ldap/conversation.rb +7 -3
  8. data/lib/mongo/auth/scram/conversation.rb +9 -3
  9. data/lib/mongo/auth/user/view.rb +23 -2
  10. data/lib/mongo/auth/x509/conversation.rb +1 -1
  11. data/lib/mongo/bulk_write/combineable.rb +51 -0
  12. data/lib/mongo/bulk_write/ordered_combiner.rb +55 -0
  13. data/lib/mongo/bulk_write/result.rb +191 -0
  14. data/lib/mongo/bulk_write/result_combiner.rb +117 -0
  15. data/lib/mongo/bulk_write/transformable.rb +132 -0
  16. data/lib/mongo/bulk_write/unordered_combiner.rb +52 -0
  17. data/lib/mongo/bulk_write/validatable.rb +62 -0
  18. data/lib/mongo/bulk_write.rb +159 -23
  19. data/lib/mongo/client.rb +52 -16
  20. data/lib/mongo/cluster/topology/replica_set.rb +27 -9
  21. data/lib/mongo/cluster/topology/sharded.rb +1 -1
  22. data/lib/mongo/cluster/topology/unknown.rb +5 -2
  23. data/lib/mongo/cluster.rb +42 -7
  24. data/lib/mongo/collection/view/aggregation.rb +48 -9
  25. data/lib/mongo/collection/view/immutable.rb +6 -6
  26. data/lib/mongo/collection/view/iterable.rb +18 -4
  27. data/lib/mongo/collection/view/map_reduce.rb +58 -17
  28. data/lib/mongo/collection/view/readable.rb +173 -42
  29. data/lib/mongo/collection/view/writable.rb +37 -23
  30. data/lib/mongo/collection/view.rb +2 -2
  31. data/lib/mongo/collection.rb +370 -33
  32. data/lib/mongo/cursor.rb +15 -3
  33. data/lib/mongo/database/view.rb +5 -4
  34. data/lib/mongo/database.rb +14 -4
  35. data/lib/mongo/dbref.rb +113 -0
  36. data/lib/mongo/error/closed_stream.rb +34 -0
  37. data/lib/mongo/error/extra_file_chunk.rb +34 -0
  38. data/lib/mongo/error/{invalid_uri_option.rb → file_not_found.rb} +11 -12
  39. data/lib/mongo/error/invalid_file.rb +2 -2
  40. data/lib/mongo/error/invalid_file_revision.rb +37 -0
  41. data/lib/mongo/error/invalid_uri.rb +5 -4
  42. data/lib/mongo/error/missing_file_chunk.rb +38 -0
  43. data/lib/mongo/error/operation_failure.rb +1 -1
  44. data/lib/mongo/error/parser.rb +1 -1
  45. data/lib/mongo/error/unchangeable_collection_option.rb +38 -0
  46. data/lib/mongo/error/unexpected_chunk_length.rb +39 -0
  47. data/lib/mongo/error.rb +13 -2
  48. data/lib/mongo/event/description_changed.rb +1 -1
  49. data/lib/mongo/grid/file/chunk.rb +6 -6
  50. data/lib/mongo/grid/file/{metadata.rb → info.rb} +41 -39
  51. data/lib/mongo/grid/file.rb +13 -10
  52. data/lib/mongo/grid/fs_bucket.rb +448 -0
  53. data/lib/mongo/grid/stream/read.rb +208 -0
  54. data/lib/mongo/grid/stream/write.rb +187 -0
  55. data/lib/mongo/grid/stream.rb +64 -0
  56. data/lib/mongo/grid.rb +2 -1
  57. data/lib/mongo/index/view.rb +3 -3
  58. data/lib/mongo/index.rb +5 -0
  59. data/lib/mongo/loggable.rb +34 -57
  60. data/lib/mongo/logger.rb +16 -78
  61. data/lib/mongo/monitoring/command_log_subscriber.rb +112 -0
  62. data/lib/mongo/monitoring/event/command_failed.rb +96 -0
  63. data/lib/mongo/monitoring/event/command_started.rb +89 -0
  64. data/lib/mongo/monitoring/event/command_succeeded.rb +118 -0
  65. data/lib/mongo/monitoring/event/secure.rb +58 -0
  66. data/lib/mongo/monitoring/event.rb +18 -0
  67. data/lib/mongo/monitoring/publishable.rb +106 -0
  68. data/lib/mongo/monitoring.rb +195 -0
  69. data/lib/mongo/operation/{aggregate.rb → commands/aggregate.rb} +3 -41
  70. data/lib/mongo/operation/commands/collections_info/result.rb +39 -0
  71. data/lib/mongo/operation/commands/collections_info.rb +68 -0
  72. data/lib/mongo/operation/{command.rb → commands/command.rb} +2 -18
  73. data/lib/mongo/operation/commands/indexes.rb +70 -0
  74. data/lib/mongo/operation/commands/list_collections/result.rb +112 -0
  75. data/lib/mongo/operation/commands/list_collections.rb +54 -0
  76. data/lib/mongo/operation/commands/list_indexes/result.rb +116 -0
  77. data/lib/mongo/operation/commands/list_indexes.rb +56 -0
  78. data/lib/mongo/operation/{map_reduce → commands/map_reduce}/result.rb +1 -1
  79. data/lib/mongo/operation/{map_reduce.rb → commands/map_reduce.rb} +3 -41
  80. data/lib/mongo/operation/commands/parallel_scan/result.rb +72 -0
  81. data/lib/mongo/operation/commands/parallel_scan.rb +56 -0
  82. data/lib/mongo/operation/commands/user_query.rb +69 -0
  83. data/lib/mongo/{bulk_write/ordered_bulk_write.rb → operation/commands/users_info/result.rb} +18 -30
  84. data/lib/mongo/operation/commands/users_info.rb +53 -0
  85. data/lib/mongo/operation/commands.rb +24 -0
  86. data/lib/mongo/operation/executable.rb +4 -68
  87. data/lib/mongo/operation/kill_cursors.rb +3 -3
  88. data/lib/mongo/operation/read/get_more.rb +2 -22
  89. data/lib/mongo/{bulk_write/unordered_bulk_write.rb → operation/read/query/result.rb} +20 -26
  90. data/lib/mongo/operation/read/query.rb +4 -21
  91. data/lib/mongo/operation/read.rb +0 -4
  92. data/lib/mongo/operation/{read_preferrable.rb → read_preference.rb} +3 -2
  93. data/lib/mongo/operation/result.rb +13 -1
  94. data/lib/mongo/operation/specifiable.rb +42 -0
  95. data/lib/mongo/operation/write/bulk/bulkable.rb +82 -0
  96. data/lib/mongo/operation/write/bulk/delete/result.rb +74 -0
  97. data/lib/mongo/operation/write/bulk/delete.rb +71 -0
  98. data/lib/mongo/operation/write/bulk/insert/result.rb +129 -0
  99. data/lib/mongo/operation/write/bulk/insert.rb +96 -0
  100. data/lib/mongo/operation/write/bulk/legacy_mergable.rb +87 -0
  101. data/lib/mongo/operation/write/bulk/mergable.rb +71 -0
  102. data/lib/mongo/operation/write/bulk/update/result.rb +174 -0
  103. data/lib/mongo/operation/write/bulk/update.rb +81 -0
  104. data/lib/mongo/operation/write/bulk.rb +6 -3
  105. data/lib/mongo/operation/write/command/create_index.rb +0 -1
  106. data/lib/mongo/operation/write/command/create_user.rb +0 -1
  107. data/lib/mongo/operation/write/command/delete.rb +0 -1
  108. data/lib/mongo/operation/write/command/drop_index.rb +0 -1
  109. data/lib/mongo/operation/write/command/insert.rb +0 -1
  110. data/lib/mongo/operation/write/command/remove_user.rb +0 -1
  111. data/lib/mongo/operation/write/command/update.rb +0 -1
  112. data/lib/mongo/operation/write/command/update_user.rb +0 -1
  113. data/lib/mongo/operation/write/command/writable.rb +13 -18
  114. data/lib/mongo/operation/write/create_index.rb +4 -27
  115. data/lib/mongo/operation/write/create_user.rb +4 -30
  116. data/lib/mongo/operation/write/delete.rb +6 -29
  117. data/lib/mongo/operation/write/drop_index.rb +3 -3
  118. data/lib/mongo/operation/write/gle.rb +48 -0
  119. data/lib/mongo/operation/write/idable.rb +5 -0
  120. data/lib/mongo/operation/write/insert.rb +2 -24
  121. data/lib/mongo/operation/write/remove_user.rb +4 -27
  122. data/lib/mongo/operation/write/update.rb +13 -36
  123. data/lib/mongo/operation/write/update_user.rb +4 -30
  124. data/lib/mongo/operation/write/write_command_enabled.rb +53 -0
  125. data/lib/mongo/operation/write.rb +2 -0
  126. data/lib/mongo/operation.rb +32 -4
  127. data/lib/mongo/options/mapper.rb +4 -2
  128. data/lib/mongo/options/redacted.rb +156 -0
  129. data/lib/mongo/options.rb +1 -0
  130. data/lib/mongo/protocol/delete.rb +75 -15
  131. data/lib/mongo/protocol/get_more.rb +65 -13
  132. data/lib/mongo/protocol/insert.rb +85 -13
  133. data/lib/mongo/protocol/kill_cursors.rb +59 -14
  134. data/lib/mongo/protocol/message.rb +12 -12
  135. data/lib/mongo/protocol/query.rb +163 -37
  136. data/lib/mongo/protocol/reply.rb +103 -0
  137. data/lib/mongo/protocol/serializers.rb +1 -1
  138. data/lib/mongo/protocol/update.rb +82 -14
  139. data/lib/mongo/retryable.rb +83 -0
  140. data/lib/mongo/server/connectable.rb +21 -25
  141. data/lib/mongo/server/connection.rb +75 -4
  142. data/lib/mongo/server/connection_pool/queue.rb +15 -0
  143. data/lib/mongo/server/connection_pool.rb +12 -0
  144. data/lib/mongo/server/description/features.rb +2 -1
  145. data/lib/mongo/server/description.rb +52 -1
  146. data/lib/mongo/server/monitor/connection.rb +26 -2
  147. data/lib/mongo/server/monitor.rb +19 -3
  148. data/lib/mongo/server.rb +39 -5
  149. data/lib/mongo/server_selector/selectable.rb +40 -31
  150. data/lib/mongo/server_selector.rb +19 -10
  151. data/lib/mongo/socket/ssl.rb +28 -16
  152. data/lib/mongo/socket/tcp.rb +3 -3
  153. data/lib/mongo/socket/unix.rb +5 -8
  154. data/lib/mongo/socket.rb +11 -4
  155. data/lib/mongo/uri.rb +248 -137
  156. data/lib/mongo/version.rb +1 -1
  157. data/lib/mongo.rb +5 -3
  158. data/spec/mongo/address/unix_spec.rb +1 -1
  159. data/spec/mongo/address_spec.rb +25 -0
  160. data/spec/mongo/auth/cr_spec.rb +9 -1
  161. data/spec/mongo/auth/ldap/conversation_spec.rb +43 -0
  162. data/spec/mongo/auth/ldap_spec.rb +9 -1
  163. data/spec/mongo/auth/scram_spec.rb +9 -1
  164. data/spec/mongo/auth/user/view_spec.rb +26 -1
  165. data/spec/mongo/auth/x509_spec.rb +9 -1
  166. data/spec/mongo/bulk_write/ordered_combiner_spec.rb +271 -0
  167. data/spec/mongo/bulk_write/unordered_combiner_spec.rb +239 -0
  168. data/spec/mongo/bulk_write_spec.rb +428 -0
  169. data/spec/mongo/client_spec.rb +167 -17
  170. data/spec/mongo/cluster/topology/replica_set_spec.rb +18 -9
  171. data/spec/mongo/cluster/topology/sharded_spec.rb +11 -3
  172. data/spec/mongo/cluster/topology/single_spec.rb +12 -4
  173. data/spec/mongo/cluster_spec.rb +55 -10
  174. data/spec/mongo/collection/view/aggregation_spec.rb +188 -1
  175. data/spec/mongo/collection/view/explainable_spec.rb +1 -1
  176. data/spec/mongo/collection/view/immutable_spec.rb +103 -0
  177. data/spec/mongo/collection/view/map_reduce_spec.rb +99 -4
  178. data/spec/mongo/collection/view/readable_spec.rb +238 -6
  179. data/spec/mongo/collection/view/writable_spec.rb +4 -4
  180. data/spec/mongo/collection/view_spec.rb +459 -71
  181. data/spec/mongo/collection_spec.rb +1291 -9
  182. data/spec/mongo/command_monitoring_spec.rb +51 -0
  183. data/spec/mongo/connection_string_spec.rb +115 -0
  184. data/spec/mongo/crud_spec.rb +2 -2
  185. data/spec/mongo/cursor_spec.rb +3 -3
  186. data/spec/mongo/database_spec.rb +47 -11
  187. data/spec/mongo/dbref_spec.rb +149 -0
  188. data/spec/mongo/grid/file/chunk_spec.rb +5 -5
  189. data/spec/mongo/grid/file/{metadata_spec.rb → info_spec.rb} +29 -17
  190. data/spec/mongo/grid/file_spec.rb +8 -8
  191. data/spec/mongo/grid/fs_bucket_spec.rb +1020 -0
  192. data/spec/mongo/grid/stream/read_spec.rb +275 -0
  193. data/spec/mongo/grid/stream/write_spec.rb +440 -0
  194. data/spec/mongo/grid/stream_spec.rb +48 -0
  195. data/spec/mongo/gridfs_spec.rb +50 -0
  196. data/spec/mongo/logger_spec.rb +0 -40
  197. data/spec/mongo/monitoring/command_log_subscriber_spec.rb +76 -0
  198. data/spec/mongo/monitoring/event/command_started_spec.rb +26 -0
  199. data/spec/mongo/monitoring/event/command_succeeded_spec.rb +26 -0
  200. data/spec/mongo/monitoring/event/secure_spec.rb +57 -0
  201. data/spec/mongo/monitoring_spec.rb +168 -0
  202. data/spec/mongo/operation/commands/aggregate_spec.rb +69 -0
  203. data/spec/mongo/operation/{read → commands}/collections_info_spec.rb +1 -1
  204. data/spec/mongo/operation/{command_spec.rb → commands/command_spec.rb} +0 -18
  205. data/spec/mongo/operation/{read → commands}/indexes_spec.rb +1 -1
  206. data/spec/mongo/operation/{map_reduce_spec.rb → commands/map_reduce_spec.rb} +1 -19
  207. data/spec/mongo/operation/kill_cursors_spec.rb +1 -17
  208. data/spec/mongo/operation/read/get_more_spec.rb +0 -16
  209. data/spec/mongo/operation/read/query_spec.rb +19 -16
  210. data/spec/mongo/operation/{read_preferrable_spec.rb → read_preference_spec.rb} +11 -11
  211. data/spec/mongo/operation/write/bulk/{bulk_delete_spec.rb → delete_spec.rb} +18 -29
  212. data/spec/mongo/operation/write/bulk/{bulk_insert_spec.rb → insert_spec.rb} +3 -14
  213. data/spec/mongo/operation/write/bulk/{bulk_update_spec.rb → update_spec.rb} +8 -19
  214. data/spec/mongo/operation/write/command/delete_spec.rb +0 -16
  215. data/spec/mongo/operation/write/command/insert_spec.rb +0 -16
  216. data/spec/mongo/operation/write/command/update_spec.rb +0 -16
  217. data/spec/mongo/operation/write/delete_spec.rb +4 -4
  218. data/spec/mongo/operation/write/insert_spec.rb +2 -13
  219. data/spec/mongo/operation/write/update_spec.rb +7 -7
  220. data/spec/mongo/options/redacted_spec.rb +350 -0
  221. data/spec/mongo/protocol/kill_cursors_spec.rb +5 -3
  222. data/spec/mongo/protocol/query_spec.rb +15 -30
  223. data/spec/mongo/retryable_spec.rb +147 -0
  224. data/spec/mongo/server/connection_pool/queue_spec.rb +16 -0
  225. data/spec/mongo/server/connection_pool_spec.rb +50 -6
  226. data/spec/mongo/server/connection_spec.rb +49 -4
  227. data/spec/mongo/server/description_spec.rb +49 -3
  228. data/spec/mongo/server/monitor_spec.rb +51 -0
  229. data/spec/mongo/server_discovery_and_monitoring_spec.rb +32 -59
  230. data/spec/mongo/server_selection_rtt_spec.rb +37 -57
  231. data/spec/mongo/server_selection_spec.rb +19 -9
  232. data/spec/mongo/server_selector/nearest_spec.rb +35 -27
  233. data/spec/mongo/server_selector/primary_preferred_spec.rb +32 -30
  234. data/spec/mongo/server_selector/primary_spec.rb +21 -14
  235. data/spec/mongo/server_selector/secondary_preferred_spec.rb +28 -26
  236. data/spec/mongo/server_selector/secondary_spec.rb +24 -22
  237. data/spec/mongo/server_selector_spec.rb +87 -24
  238. data/spec/mongo/server_spec.rb +94 -8
  239. data/spec/mongo/socket/ssl_spec.rb +123 -13
  240. data/spec/mongo/socket/unix_spec.rb +52 -0
  241. data/spec/mongo/uri_spec.rb +295 -67
  242. data/spec/spec_helper.rb +40 -24
  243. data/spec/support/authorization.rb +23 -9
  244. data/spec/support/certificates/client.pem +4 -4
  245. data/spec/support/command_monitoring/bulkWrite.yml +73 -0
  246. data/spec/support/command_monitoring/command.yml +42 -0
  247. data/spec/support/command_monitoring/deleteMany.yml +55 -0
  248. data/spec/support/command_monitoring/deleteOne.yml +55 -0
  249. data/spec/support/command_monitoring/find.yml +219 -0
  250. data/spec/support/command_monitoring/insertMany.yml +81 -0
  251. data/spec/support/command_monitoring/insertOne.yml +51 -0
  252. data/spec/support/command_monitoring/updateMany.yml +67 -0
  253. data/spec/support/command_monitoring/updateOne.yml +95 -0
  254. data/spec/support/command_monitoring.rb +365 -0
  255. data/spec/support/connection_string.rb +228 -0
  256. data/spec/support/connection_string_tests/invalid-uris.yml +193 -0
  257. data/spec/support/connection_string_tests/valid-auth.yml +256 -0
  258. data/spec/support/connection_string_tests/valid-host_identifiers.yml +121 -0
  259. data/spec/support/connection_string_tests/valid-options.yml +30 -0
  260. data/spec/support/connection_string_tests/valid-unix_socket-absolute.yml +197 -0
  261. data/spec/support/connection_string_tests/valid-unix_socket-relative.yml +213 -0
  262. data/spec/support/connection_string_tests/valid-warnings.yml +55 -0
  263. data/spec/support/crud/read.rb +22 -19
  264. data/spec/support/crud/write.rb +58 -27
  265. data/spec/support/crud.rb +10 -2
  266. data/spec/support/gridfs.rb +637 -0
  267. data/spec/support/gridfs_tests/delete.yml +157 -0
  268. data/spec/support/gridfs_tests/download.yml +210 -0
  269. data/spec/support/gridfs_tests/download_by_name.yml +113 -0
  270. data/spec/support/gridfs_tests/upload.yml +158 -0
  271. data/spec/support/matchers.rb +1 -1
  272. data/spec/support/sdam/rs/equal_electionids.yml +44 -0
  273. data/spec/support/sdam/rs/new_primary_new_electionid.yml +95 -0
  274. data/spec/support/sdam/rs/null_election_id.yml +144 -0
  275. data/spec/support/sdam/rs/primary_disconnect_electionid.yml +124 -0
  276. data/spec/support/sdam/rs/primary_mismatched_me.yml +37 -0
  277. data/spec/support/sdam/rs/primary_to_no_primary_mismatched_me.yml +75 -0
  278. data/spec/support/sdam/rs/secondary_mismatched_me.yml +37 -0
  279. data/spec/support/sdam/sharded/mongos_disconnect.yml +104 -0
  280. data/spec/support/sdam/single/direct_connection_rsarbiter.yml +1 -1
  281. data/spec/support/sdam/single/direct_connection_rsprimary.yml +1 -1
  282. data/spec/support/sdam/single/direct_connection_rssecondary.yml +1 -1
  283. data/spec/support/sdam/single/direct_connection_slave.yml +1 -1
  284. data/spec/support/sdam/single/direct_connection_standalone.yml +1 -1
  285. data/spec/support/sdam/single/not_ok_response.yml +0 -1
  286. data/spec/support/server_discovery_and_monitoring.rb +22 -3
  287. data/spec/support/server_selection.rb +3 -1
  288. data/spec/support/shared/bulk_write.rb +218 -22
  289. data/spec/support/shared/server_selector.rb +80 -14
  290. data.tar.gz.sig +0 -0
  291. metadata +188 -59
  292. metadata.gz.sig +0 -0
  293. data/lib/mongo/bulk_write/bulk_writable.rb +0 -196
  294. data/lib/mongo/bulk_write/deletable.rb +0 -56
  295. data/lib/mongo/bulk_write/insertable.rb +0 -48
  296. data/lib/mongo/bulk_write/replacable.rb +0 -57
  297. data/lib/mongo/bulk_write/updatable.rb +0 -68
  298. data/lib/mongo/grid/fs.rb +0 -149
  299. data/lib/mongo/operation/list_collections/result.rb +0 -114
  300. data/lib/mongo/operation/list_indexes/result.rb +0 -118
  301. data/lib/mongo/operation/read/collections_info.rb +0 -68
  302. data/lib/mongo/operation/read/indexes.rb +0 -69
  303. data/lib/mongo/operation/read/list_collections.rb +0 -76
  304. data/lib/mongo/operation/read/list_indexes.rb +0 -78
  305. data/lib/mongo/operation/write/bulk/bulk_delete/result.rb +0 -75
  306. data/lib/mongo/operation/write/bulk/bulk_delete.rb +0 -145
  307. data/lib/mongo/operation/write/bulk/bulk_insert/result.rb +0 -130
  308. data/lib/mongo/operation/write/bulk/bulk_insert.rb +0 -132
  309. data/lib/mongo/operation/write/bulk/bulk_mergable.rb +0 -67
  310. data/lib/mongo/operation/write/bulk/bulk_update/result.rb +0 -162
  311. data/lib/mongo/operation/write/bulk/bulk_update.rb +0 -154
  312. data/lib/mongo/operation/write/bulk/legacy_bulk_mergable.rb +0 -83
  313. data/spec/mongo/bulk/bulk_write_spec.rb +0 -262
  314. data/spec/mongo/grid/fs_spec.rb +0 -160
  315. data/spec/mongo/loggable_spec.rb +0 -63
  316. data/spec/mongo/operation/aggregate_spec.rb +0 -127
  317. /data/lib/mongo/operation/{aggregate → commands/aggregate}/result.rb +0 -0
@@ -0,0 +1,637 @@
1
+ # Copyright (C) 2014-2015 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
+
16
+ # Matcher for determining whether the operation completed successfully.
17
+ #
18
+ # @since 2.1.0
19
+ RSpec::Matchers.define :completes_successfully do |test|
20
+
21
+ match do |actual|
22
+ actual == test.expected_result || test.expected_result.nil?
23
+ end
24
+ end
25
+
26
+ # Matcher for determining whether the actual chunks collection matches
27
+ # the expected chunks collection.
28
+ #
29
+ # @since 2.1.0
30
+ RSpec::Matchers.define :match_chunks_collection do |expected|
31
+
32
+ match do |actual|
33
+ return true if expected.nil?
34
+ if expected.find.to_a.empty?
35
+ actual.find.to_a.empty?
36
+ else
37
+ actual.find.all? do |doc|
38
+ if matching_doc = expected.find(files_id: doc['files_id'], n: doc['n']).first
39
+ matching_doc.all? do |k, v|
40
+ doc[k] == v || k == '_id'
41
+ end
42
+ else
43
+ false
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ # Matcher for determining whether the actual files collection matches
51
+ # the expected files collection.
52
+ #
53
+ # @since 2.1.0
54
+ RSpec::Matchers.define :match_files_collection do |expected|
55
+
56
+ match do |actual|
57
+ return true if expected.nil?
58
+ actual.find.all? do |doc|
59
+ if matching_doc = expected.find(_id: doc['_id']).first
60
+ matching_doc.all? do |k, v|
61
+ doc[k] == v
62
+ end
63
+ else
64
+ false
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ # Matcher for determining whether the operation raised the correct error.
71
+ #
72
+ # @since 2.1.0
73
+ RSpec::Matchers.define :match_error do |error|
74
+
75
+ match do |actual|
76
+ Mongo::GridFS::Test::ERROR_MAPPING[error] == actual.class
77
+ end
78
+ end
79
+
80
+
81
+ module Mongo
82
+ module GridFS
83
+
84
+ # Represents a GridFS specification test.
85
+ #
86
+ # @since 2.1.0
87
+ class Spec
88
+
89
+ # @return [ String ] description The spec description.
90
+ #
91
+ # @since 2.1.0
92
+ attr_reader :description
93
+
94
+ # Instantiate the new spec.
95
+ #
96
+ # @example Create the spec.
97
+ # Spec.new(file)
98
+ #
99
+ # @param [ String ] file The name of the file.
100
+ #
101
+ # @since 2.1.0
102
+ def initialize(file)
103
+ @spec = YAML.load(ERB.new(File.new(file).read).result)
104
+ @description = File.basename(file)
105
+ @data = @spec['data']
106
+ end
107
+
108
+ # Get a list of Tests for each test definition.
109
+ #
110
+ # @example Get the list of Tests.
111
+ # spec.tests
112
+ #
113
+ # @return [ Array<Test> ] The list of Tests.
114
+ #
115
+ # @since 2.1.0
116
+ def tests
117
+ @tests ||= @spec['tests'].collect do |test|
118
+ Test.new(@data, test)
119
+ end
120
+ end
121
+ end
122
+
123
+ # Contains shared helper functions for converting YAML test values to Ruby objects.
124
+ #
125
+ # @since 2.1.0
126
+ module Convertible
127
+
128
+ # Convert an integer to the corresponding CRUD method suffix.
129
+ #
130
+ # @param [ Integer ] int The limit.
131
+ #
132
+ # @return [ String ] The CRUD method suffix.
133
+ #
134
+ # @since 2.1.0
135
+ def limit(int)
136
+ int == 0 ? 'many' : 'one'
137
+ end
138
+
139
+ # Convert an id value to a BSON::ObjectId.
140
+ #
141
+ # @param [ Object ] v The value to convert.
142
+ # @param [ Hash ] opts The options.
143
+ #
144
+ # @option opts [ BSON::ObjectId ] :id The id override.
145
+ #
146
+ # @return [ BSON::ObjectId ] The object id.
147
+ #
148
+ # @since 2.1.0
149
+ def convert__id(v, opts = {})
150
+ to_oid(v, opts[:id])
151
+ end
152
+
153
+ # Convert a value to a date.
154
+ #
155
+ # @param [ Object ] v The value to convert.
156
+ # @param [ Hash ] opts The options.
157
+ #
158
+ # @return [ Time ] The upload date time value.
159
+ #
160
+ # @since 2.1.0
161
+ def convert_uploadDate(v, opts = {})
162
+ v.is_a?(Time) ? v : v['$date'] ? Time.parse(v['$date']) : upload_date
163
+ end
164
+
165
+ # Convert an file id value to a BSON::ObjectId.
166
+ #
167
+ # @param [ Object ] v The value to convert.
168
+ # @param [ Hash ] opts The options.
169
+ #
170
+ # @option opts [ BSON::ObjectId ] :id The id override.
171
+ #
172
+ # @return [ BSON::ObjectId ] The object id.
173
+ #
174
+ # @since 2.1.0
175
+ def convert_files_id(v, opts = {})
176
+ to_oid(v, opts[:files_id])
177
+ end
178
+
179
+ # Convert a value to BSON::Binary data.
180
+ #
181
+ # @param [ Object ] v The value to convert.
182
+ # @param [ Hash ] opts The options.
183
+ #
184
+ # @return [ BSON::Binary ] The converted data.
185
+ #
186
+ # @since 2.1.0
187
+ def convert_data(v, opts = {})
188
+ v.is_a?(BSON::Binary) ? v : BSON::Binary.new(to_hex(v['$hex'], opts), :generic)
189
+ end
190
+
191
+ # Transform documents to have the correct object types for serialization.
192
+ #
193
+ # @param [ Array<Hash> ] docs The documents to transform.
194
+ # @param [ Hash ] opts The options.
195
+ #
196
+ # @return [ Array<Hash> ] The transformed documents.
197
+ #
198
+ # @since 2.1.0
199
+ def transform_docs(docs, opts = {})
200
+ docs.collect do |doc|
201
+ doc.each do |k, v|
202
+ doc[k] = send("convert_#{k}", v, opts) if respond_to?("convert_#{k}")
203
+ end
204
+ doc
205
+ end
206
+ end
207
+
208
+ # Convert a string to a hex value.
209
+ #
210
+ # @param [ String ] string The value to convert.
211
+ # @param [ Hash ] opts The options.
212
+ #
213
+ # @return [ String ] The hex value.
214
+ #
215
+ # @since 2.1.0
216
+ def to_hex(string, opts = {})
217
+ [ string ].pack('H*')
218
+ end
219
+
220
+ # Convert an object id represented in json to a BSON::ObjectId.
221
+ # A new BSON::ObjectId is returned if the json document is empty.
222
+ #
223
+ # @param [ Object ] value The value to convert.
224
+ # @param [ Object ] id The id override.
225
+ #
226
+ # @return [ BSON::ObjectId ] The object id.
227
+ #
228
+ # @since 2.1.0
229
+ def to_oid(value, id = nil)
230
+ if id
231
+ id
232
+ elsif value.is_a?(BSON::ObjectId)
233
+ value
234
+ elsif value['$oid']
235
+ BSON::ObjectId.from_string(value['$oid'])
236
+ else
237
+ BSON::ObjectId.new
238
+ end
239
+ end
240
+
241
+ # Convert options.
242
+ #
243
+ # @return [ Hash ] The options.
244
+ #
245
+ # @since 2.1.0
246
+ def options
247
+ @act['arguments']['options'].reduce({}) do |opts, (k, v)|
248
+ opts.merge!(chunk_size: v) if k == "chunkSizeBytes"
249
+ opts.merge!(upload_date: upload_date)
250
+ opts.merge!(content_type: v) if k == "contentType"
251
+ opts.merge!(metadata: v) if k == "metadata"
252
+ opts
253
+ end
254
+ end
255
+ end
256
+
257
+ # Represents a single GridFS test.
258
+ #
259
+ # @since 2.1.0
260
+ class Test
261
+ include Convertible
262
+ extend Forwardable
263
+
264
+ def_delegators :@operation, :expected_files_collection,
265
+ :expected_chunks_collection,
266
+ :result,
267
+ :expected_error,
268
+ :expected_result,
269
+ :error?
270
+
271
+ # The test description.
272
+ #
273
+ # @return [ String ] The test description.
274
+ #
275
+ # @since 2.1.0
276
+ attr_reader :description
277
+
278
+ # The upload date to use in the test.
279
+ #
280
+ # @return [ Time ] The upload date.
281
+ #
282
+ # @since 2.1.0
283
+ attr_reader :upload_date
284
+
285
+ # Mapping of test error strings to driver classes.
286
+ #
287
+ # @since 2.1.0
288
+ ERROR_MAPPING = {
289
+ 'FileNotFound' => Mongo::Error::FileNotFound,
290
+ 'ChunkIsMissing' => Mongo::Error::MissingFileChunk,
291
+ 'ChunkIsWrongSize' => Mongo::Error::UnexpectedChunkLength,
292
+ 'ExtraChunk' => Mongo::Error::ExtraFileChunk,
293
+ 'RevisionNotFound' => Mongo::Error::InvalidFileRevision
294
+ }
295
+
296
+ # Instantiate the new GridFS::Test.
297
+ #
298
+ # @example Create the test.
299
+ # Test.new(data, test)
300
+ #
301
+ # @param [ Array<Hash> ] data The documents the files and chunks
302
+ # collections must have before the test runs.
303
+ # @param [ Hash ] test The test specification.
304
+ #
305
+ # @since 2.1.0
306
+ def initialize(data, test)
307
+ @pre_data = data
308
+ @description = test['description']
309
+ @upload_date = Time.now
310
+ if test['assert']['error']
311
+ @operation = UnsuccessfulOp.new(self, test)
312
+ else
313
+ @operation = SuccessfulOp.new(self, test)
314
+ end
315
+ end
316
+
317
+ # Whether the expected and actual collections should be compared after the test runs.
318
+ #
319
+ # @return [ true, false ] Whether the actual and expected collections should be compared.
320
+ #
321
+ # @since 2.1.0
322
+ def assert_data?
323
+ @operation.assert['data']
324
+ end
325
+
326
+ # Run the test.
327
+ #
328
+ # @example Run the test
329
+ # test.run(fs)
330
+ #
331
+ # @param [ Mongo::Grid::FSBucket ] fs The Grid::FSBucket to use in the test.
332
+ #
333
+ # @since 2.1.0
334
+ def run(fs)
335
+ setup(fs)
336
+ @operation.run(fs)
337
+ end
338
+
339
+ # Clear the files and chunks collection in the FSBucket and other collections used in the test.
340
+ #
341
+ # @example Clear the test collections
342
+ # test.clear_collections(fs)
343
+ #
344
+ # @param [ Mongo::Grid::FSBucket ] fs The Grid::FSBucket whose collections should be cleared.
345
+ #
346
+ # @since 2.1.0
347
+ def clear_collections(fs)
348
+ fs.files_collection.delete_many
349
+ fs.chunks_collection.delete_many
350
+ @operation.clear_collections(fs)
351
+ end
352
+
353
+ private
354
+
355
+ def setup(fs)
356
+ insert_pre_data(fs)
357
+ @operation.arrange(fs)
358
+ end
359
+
360
+ def files_data
361
+ @files_data ||= transform_docs(@pre_data['files'])
362
+ end
363
+
364
+ def chunks_data
365
+ @chunks_data ||= transform_docs(@pre_data['chunks'])
366
+ end
367
+
368
+ def insert_pre_files_data(fs)
369
+ fs.files_collection.insert_many(files_data)
370
+ fs.database['expected.files'].insert_many(files_data) if assert_data?
371
+ end
372
+
373
+ def insert_pre_chunks_data(fs)
374
+ fs.chunks_collection.insert_many(chunks_data)
375
+ fs.database['expected.chunks'].insert_many(chunks_data) if assert_data?
376
+ end
377
+
378
+ def insert_pre_data(fs)
379
+ insert_pre_files_data(fs) unless files_data.empty?
380
+ insert_pre_chunks_data(fs) unless chunks_data.empty?
381
+ end
382
+
383
+ # Contains logic and helper methods shared between a successful and
384
+ # non-successful GridFS test operation.
385
+ #
386
+ # @since 2.1.0
387
+ module Operable
388
+ extend Forwardable
389
+
390
+ def_delegators :@test, :upload_date
391
+
392
+ # The test operation name.
393
+ #
394
+ # @return [ String ] The operation name.
395
+ #
396
+ # @since 2.1.0
397
+ attr_reader :op
398
+
399
+ # The test assertion.
400
+ #
401
+ # @return [ Hash ] The test assertion definition.
402
+ #
403
+ # @since 2.1.0
404
+ attr_reader :assert
405
+
406
+ # The operation result.
407
+ #
408
+ # @return [ Object ] The operation result.
409
+ #
410
+ # @since 2.1.0
411
+ attr_reader :result
412
+
413
+ # The collection containing the expected files.
414
+ #
415
+ # @return [ Mongo::Collection ] The expected files collection.
416
+ #
417
+ # @since 2.1.0
418
+ attr_reader :expected_files_collection
419
+
420
+ # The collection containing the expected chunks.
421
+ #
422
+ # @return [ Mongo::Collection ] The expected chunks collection.
423
+ #
424
+ # @since 2.1.0
425
+ attr_reader :expected_chunks_collection
426
+
427
+ # Instantiate the new test operation.
428
+ #
429
+ # @example Create the test operation.
430
+ # Test.new(data, test)
431
+ #
432
+ # @param [ Test ] test The test.
433
+ # @param [ Hash ] spec The test specification.
434
+ #
435
+ # @since 2.1.0
436
+ def initialize(test, spec)
437
+ @test = test
438
+ @arrange = spec['arrange']
439
+ @act = spec['act']
440
+ @op = @act['operation']
441
+ @arguments = @act['arguments']
442
+ @assert = spec['assert']
443
+ end
444
+
445
+ # Arrange the data before running the operation.
446
+ # This sets up the correct scenario for the test.
447
+ #
448
+ # @example Arrange the data.
449
+ # operation.arrange(fs)
450
+ #
451
+ # @param [ Grid::FSBucket ] fs The FSBucket used in the test.
452
+ #
453
+ # @since 2.1.0
454
+ def arrange(fs)
455
+ if @arrange
456
+ @arrange['data'].each do |data|
457
+ send("#{data.keys.first}_exp_data", fs, data)
458
+ end
459
+ end
460
+ end
461
+
462
+ # Run the test operation.
463
+ #
464
+ # @example Execute the operation.
465
+ # operation.run(fs)
466
+ #
467
+ # @param [ Grid::FSBucket ] fs The FSBucket used in the test.
468
+ #
469
+ # @result [ Object ] The operation result.
470
+ #
471
+ # @since 2.1.0
472
+ def run(fs)
473
+ @expected_files_collection = fs.database['expected.files']
474
+ @expected_chunks_collection = fs.database['expected.chunks']
475
+ act(fs)
476
+ prepare_expected_collections(fs)
477
+ result
478
+ end
479
+
480
+ private
481
+
482
+ def prepare_expected_collections(fs)
483
+ if @test.assert_data?
484
+ @assert['data'].each do |data|
485
+ op = "#{data.keys.first}_exp_data"
486
+ send(op, fs, data)
487
+ end
488
+ end
489
+ end
490
+
491
+ def insert_exp_data(fs, data)
492
+ coll = fs.database[data['insert']]
493
+ if coll.name =~ /.files/
494
+ opts = { id: @result }
495
+ else
496
+ opts = { files_id: @result }
497
+ end
498
+ coll.insert_many(transform_docs(data['documents'], opts))
499
+ end
500
+
501
+ def delete_exp_data(fs, data)
502
+ coll = fs.database[data['delete']]
503
+ data['deletes'].each do |del|
504
+ id = del['q'].keys.first
505
+ coll.find(id => to_oid(del['q'][id])).send("delete_#{limit(del['limit'])}")
506
+ end
507
+ end
508
+
509
+ def update_exp_data(fs, data)
510
+ coll = fs.database[data['update']]
511
+ data['updates'].each do |update|
512
+ sel = update['q'].merge('files_id' => to_oid(update['q']['files_id']))
513
+ data = BSON::Binary.new(to_hex(update['u']['$set']['data']['$hex']), :generic)
514
+ u = update['u'].merge('$set' => { 'data' => data })
515
+ coll.find(sel).update_one(u)
516
+ end
517
+ end
518
+
519
+ def upload(fs)
520
+ io = StringIO.new(to_hex(@arguments['source']['$hex']))
521
+ fs.upload_from_stream(@arguments['filename'], io, options)
522
+ end
523
+
524
+ def download(fs)
525
+ io = StringIO.new.set_encoding(BSON::BINARY)
526
+ fs.download_to_stream(to_oid(@arguments['id']), io)
527
+ io.string
528
+ end
529
+
530
+ def download_by_name(fs)
531
+ io = StringIO.new.set_encoding(BSON::BINARY)
532
+ if @arguments['options']
533
+ fs.download_to_stream_by_name(@arguments['filename'], io, revision: @arguments['options']['revision'])
534
+ else
535
+ fs.download_to_stream_by_name(@arguments['filename'], io)
536
+ end
537
+ io.string
538
+ end
539
+
540
+ def delete(fs)
541
+ fs.delete(to_oid(@arguments['id']))
542
+ end
543
+ end
544
+
545
+ # A GridFS test operation that is expected to succeed.
546
+ #
547
+ # @since 2.1.0
548
+ class SuccessfulOp
549
+ include Convertible
550
+ include Test::Operable
551
+
552
+ # The expected result of executing the operation.
553
+ #
554
+ # @example Get the expected result.
555
+ # operation.expected_result
556
+ #
557
+ # @result [ Object ] The operation result.
558
+ #
559
+ # @since 2.1.0
560
+ def expected_result
561
+ if @assert['result'] == '&result'
562
+ @result
563
+ elsif @assert['result'] != 'void'
564
+ to_hex(@assert['result']['$hex'])
565
+ end
566
+ end
567
+
568
+ # Execute the operation.
569
+ #
570
+ # @example Execute the operation.
571
+ # operation.act(fs)
572
+ #
573
+ # @param [ Grid::FSBucket ] fs The FSBucket used in the test.
574
+ #
575
+ # @result [ Object ] The operation result.
576
+ #
577
+ # @since 2.1.0
578
+ def act(fs)
579
+ @result = send(op, fs)
580
+ end
581
+
582
+ # Whether this operation is expected to raise an error.
583
+ #
584
+ # @return [ false ] The operation is expected to succeed.
585
+ #
586
+ # @since 2.1.0
587
+ def error?
588
+ false
589
+ end
590
+ end
591
+
592
+ class UnsuccessfulOp
593
+ include Convertible
594
+ include Test::Operable
595
+
596
+ # Whether this operation is expected to raise an error.
597
+ #
598
+ # @return [ true ] The operation is expected to fail.
599
+ #
600
+ # @since 2.1.0
601
+ def error?
602
+ true
603
+ end
604
+
605
+ # The expected error.
606
+ #
607
+ # @example Execute the operation.
608
+ # operation.expected_error
609
+ #
610
+ # @return [ String ] The expected error name.
611
+ #
612
+ # @since 2.1.0
613
+ def expected_error
614
+ @assert['error']
615
+ end
616
+
617
+ # Execute the operation.
618
+ #
619
+ # @example Execute the operation.
620
+ # operation.act(fs)
621
+ #
622
+ # @param [ Grid::FSBucket ] fs The FSBucket used in the test.
623
+ #
624
+ # @result [ Mongo::Error ] The error encountered.
625
+ #
626
+ # @since 2.1.0
627
+ def act(fs)
628
+ begin
629
+ send(op, fs)
630
+ rescue => ex
631
+ @result = ex
632
+ end
633
+ end
634
+ end
635
+ end
636
+ end
637
+ end