mongo 2.4.3 → 2.5.0.beta

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 (235) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +3 -2
  3. data.tar.gz.sig +0 -0
  4. data/lib/mongo.rb +3 -2
  5. data/lib/mongo/auth/cr.rb +6 -4
  6. data/lib/mongo/auth/cr/conversation.rb +33 -17
  7. data/lib/mongo/auth/ldap.rb +4 -2
  8. data/lib/mongo/auth/ldap/conversation.rb +19 -9
  9. data/lib/mongo/auth/scram.rb +7 -4
  10. data/lib/mongo/auth/scram/conversation.rb +62 -24
  11. data/lib/mongo/auth/user.rb +10 -0
  12. data/lib/mongo/auth/user/view.rb +44 -22
  13. data/lib/mongo/auth/x509.rb +4 -2
  14. data/lib/mongo/auth/x509/conversation.rb +19 -9
  15. data/lib/mongo/bulk_write.rb +33 -27
  16. data/lib/mongo/bulk_write/combineable.rb +5 -0
  17. data/lib/mongo/bulk_write/transformable.rb +2 -0
  18. data/lib/mongo/bulk_write/validatable.rb +4 -0
  19. data/lib/mongo/client.rb +123 -12
  20. data/lib/mongo/cluster.rb +52 -11
  21. data/lib/mongo/cluster/app_metadata.rb +8 -2
  22. data/lib/mongo/cluster/cursor_reaper.rb +0 -1
  23. data/lib/mongo/cluster/topology.rb +1 -1
  24. data/lib/mongo/collection.rb +114 -27
  25. data/lib/mongo/collection/view.rb +8 -2
  26. data/lib/mongo/collection/view/aggregation.rb +11 -7
  27. data/lib/mongo/collection/view/builder/aggregation.rb +5 -1
  28. data/lib/mongo/collection/view/builder/find_command.rb +5 -3
  29. data/lib/mongo/collection/view/builder/map_reduce.rb +11 -3
  30. data/lib/mongo/collection/view/builder/op_query.rb +1 -1
  31. data/lib/mongo/collection/view/change_stream.rb +160 -0
  32. data/lib/mongo/collection/view/change_stream/retryable.rb +57 -0
  33. data/lib/mongo/collection/view/iterable.rb +11 -10
  34. data/lib/mongo/collection/view/map_reduce.rb +22 -18
  35. data/lib/mongo/collection/view/readable.rb +51 -37
  36. data/lib/mongo/collection/view/writable.rb +72 -40
  37. data/lib/mongo/cursor.rb +25 -4
  38. data/lib/mongo/cursor/builder/get_more_command.rb +4 -2
  39. data/lib/mongo/database.rb +22 -11
  40. data/lib/mongo/database/view.rb +16 -12
  41. data/lib/mongo/error.rb +5 -0
  42. data/lib/mongo/error/invalid_session.rb +36 -0
  43. data/lib/mongo/error/missing_resume_token.rb +39 -0
  44. data/lib/mongo/error/operation_failure.rb +17 -0
  45. data/lib/mongo/error/parser.rb +3 -2
  46. data/lib/mongo/error/unknown_payload_type.rb +41 -0
  47. data/lib/mongo/error/unsupported_array_filters.rb +51 -0
  48. data/lib/mongo/error/unsupported_message_type.rb +23 -0
  49. data/lib/mongo/grid/fs_bucket.rb +5 -4
  50. data/lib/mongo/grid/stream/read.rb +3 -2
  51. data/lib/mongo/grid/stream/write.rb +2 -2
  52. data/lib/mongo/index/view.rb +35 -25
  53. data/lib/mongo/monitoring/event/secure.rb +14 -0
  54. data/lib/mongo/operation.rb +16 -0
  55. data/lib/mongo/operation/commands.rb +1 -0
  56. data/lib/mongo/operation/commands/aggregate.rb +9 -5
  57. data/lib/mongo/operation/commands/aggregate/result.rb +1 -1
  58. data/lib/mongo/operation/commands/collections_info.rb +6 -6
  59. data/lib/mongo/operation/commands/command.rb +2 -1
  60. data/lib/mongo/operation/commands/create.rb +6 -2
  61. data/lib/mongo/operation/commands/drop.rb +6 -2
  62. data/lib/mongo/operation/commands/drop_database.rb +6 -2
  63. data/lib/mongo/operation/commands/explain.rb +27 -0
  64. data/lib/mongo/operation/commands/explain/result.rb +52 -0
  65. data/lib/mongo/operation/commands/indexes.rb +1 -1
  66. data/lib/mongo/operation/commands/list_collections.rb +1 -1
  67. data/lib/mongo/operation/commands/list_collections/result.rb +1 -1
  68. data/lib/mongo/operation/commands/list_indexes.rb +1 -1
  69. data/lib/mongo/operation/commands/list_indexes/result.rb +1 -1
  70. data/lib/mongo/operation/commands/map_reduce.rb +8 -4
  71. data/lib/mongo/operation/commands/map_reduce/result.rb +13 -1
  72. data/lib/mongo/operation/commands/user_query.rb +1 -1
  73. data/lib/mongo/operation/commands/users_info.rb +6 -2
  74. data/lib/mongo/operation/executable.rb +4 -1
  75. data/lib/mongo/operation/read_preference.rb +10 -5
  76. data/lib/mongo/operation/result.rb +26 -2
  77. data/lib/mongo/operation/specifiable.rb +13 -1
  78. data/lib/mongo/operation/uses_command_op_msg.rb +47 -0
  79. data/lib/mongo/operation/write/bulk/bulkable.rb +4 -1
  80. data/lib/mongo/operation/write/bulk/insert/result.rb +4 -4
  81. data/lib/mongo/operation/write/command/create_index.rb +6 -1
  82. data/lib/mongo/operation/write/command/delete.rb +28 -4
  83. data/lib/mongo/operation/write/command/drop_index.rb +6 -1
  84. data/lib/mongo/operation/write/command/insert.rb +22 -18
  85. data/lib/mongo/operation/write/command/update.rb +24 -9
  86. data/lib/mongo/operation/write/command/writable.rb +14 -1
  87. data/lib/mongo/operation/write/insert.rb +4 -1
  88. data/lib/mongo/operation/write/insert/result.rb +2 -2
  89. data/lib/mongo/operation/write/update.rb +7 -1
  90. data/lib/mongo/operation/write/write_command_enabled.rb +20 -3
  91. data/lib/mongo/protocol.rb +3 -0
  92. data/lib/mongo/protocol/bit_vector.rb +2 -2
  93. data/lib/mongo/protocol/compressed.rb +135 -0
  94. data/lib/mongo/protocol/delete.rb +8 -6
  95. data/lib/mongo/protocol/get_more.rb +8 -6
  96. data/lib/mongo/protocol/insert.rb +8 -6
  97. data/lib/mongo/protocol/kill_cursors.rb +8 -6
  98. data/lib/mongo/protocol/message.rb +31 -3
  99. data/lib/mongo/protocol/msg.rb +172 -0
  100. data/lib/mongo/protocol/query.rb +26 -6
  101. data/lib/mongo/protocol/registry.rb +76 -0
  102. data/lib/mongo/protocol/reply.rb +10 -5
  103. data/lib/mongo/protocol/serializers.rb +224 -0
  104. data/lib/mongo/protocol/update.rb +8 -6
  105. data/lib/mongo/retryable.rb +4 -2
  106. data/lib/mongo/server.rb +6 -3
  107. data/lib/mongo/server/connectable.rb +1 -1
  108. data/lib/mongo/server/connection.rb +30 -8
  109. data/lib/mongo/server/description.rb +25 -1
  110. data/lib/mongo/server/description/features.rb +4 -1
  111. data/lib/mongo/server/monitor.rb +5 -0
  112. data/lib/mongo/server/monitor/connection.rb +50 -2
  113. data/lib/mongo/server_selector/nearest.rb +10 -4
  114. data/lib/mongo/server_selector/primary.rb +20 -0
  115. data/lib/mongo/server_selector/primary_preferred.rb +10 -4
  116. data/lib/mongo/server_selector/secondary.rb +10 -4
  117. data/lib/mongo/server_selector/secondary_preferred.rb +24 -4
  118. data/lib/mongo/session.rb +180 -0
  119. data/lib/mongo/session/server_session.rb +73 -0
  120. data/lib/mongo/session/session_pool.rb +161 -0
  121. data/lib/mongo/uri.rb +11 -0
  122. data/lib/mongo/version.rb +1 -1
  123. data/mongo.gemspec +2 -1
  124. data/spec/mongo/auth/cr_spec.rb +12 -0
  125. data/spec/mongo/auth/ldap_spec.rb +2 -0
  126. data/spec/mongo/auth/scram/conversation_spec.rb +6 -6
  127. data/spec/mongo/auth/scram_spec.rb +25 -1
  128. data/spec/mongo/auth/user/view_spec.rb +268 -76
  129. data/spec/mongo/auth/x509_spec.rb +2 -0
  130. data/spec/mongo/bulk_write_spec.rb +435 -5
  131. data/spec/mongo/client_spec.rb +356 -39
  132. data/spec/mongo/cluster/app_metadata_spec.rb +2 -2
  133. data/spec/mongo/cluster_spec.rb +176 -0
  134. data/spec/mongo/collection/view/aggregation_spec.rb +33 -12
  135. data/spec/mongo/collection/view/builder/find_command_spec.rb +46 -6
  136. data/spec/mongo/collection/view/change_stream_spec.rb +814 -0
  137. data/spec/mongo/collection/view/map_reduce_spec.rb +94 -17
  138. data/spec/mongo/collection/view/readable_spec.rb +3 -12
  139. data/spec/mongo/collection_spec.rb +1048 -42
  140. data/spec/mongo/cursor/builder/get_more_command_spec.rb +19 -0
  141. data/spec/mongo/cursor_spec.rb +2 -2
  142. data/spec/mongo/database_spec.rb +50 -1
  143. data/spec/mongo/grid/fs_bucket_spec.rb +225 -137
  144. data/spec/mongo/grid/stream/read_spec.rb +2 -2
  145. data/spec/mongo/index/view_spec.rb +146 -8
  146. data/spec/mongo/monitoring/event/secure_spec.rb +42 -0
  147. data/spec/mongo/operation/read/query_spec.rb +2 -1
  148. data/spec/mongo/operation/specifiable_spec.rb +2 -2
  149. data/spec/mongo/operation/write/command/delete_spec.rb +96 -13
  150. data/spec/mongo/operation/write/command/insert_spec.rb +111 -12
  151. data/spec/mongo/operation/write/command/update_spec.rb +93 -10
  152. data/spec/mongo/operation/write/delete_spec.rb +1 -1
  153. data/spec/mongo/operation/write/insert_spec.rb +1 -1
  154. data/spec/mongo/operation/write/update_spec.rb +1 -1
  155. data/spec/mongo/protocol/compressed_spec.rb +66 -0
  156. data/spec/mongo/protocol/delete_spec.rb +14 -0
  157. data/spec/mongo/protocol/get_more_spec.rb +14 -0
  158. data/spec/mongo/protocol/insert_spec.rb +14 -0
  159. data/spec/mongo/protocol/kill_cursors_spec.rb +14 -0
  160. data/spec/mongo/protocol/msg_spec.rb +499 -0
  161. data/spec/mongo/protocol/query_spec.rb +45 -0
  162. data/spec/mongo/protocol/registry_spec.rb +31 -0
  163. data/spec/mongo/protocol/reply_spec.rb +14 -0
  164. data/spec/mongo/protocol/update_spec.rb +14 -0
  165. data/spec/mongo/retryable_spec.rb +6 -2
  166. data/spec/mongo/sdam_spec.rb +4 -0
  167. data/spec/mongo/server/connection_spec.rb +4 -2
  168. data/spec/mongo/server/description_spec.rb +28 -1
  169. data/spec/mongo/session/server_session_spec.rb +16 -0
  170. data/spec/mongo/session/session_pool_spec.rb +194 -0
  171. data/spec/mongo/uri_spec.rb +31 -2
  172. data/spec/spec_helper.rb +104 -0
  173. data/spec/support/authorization.rb +6 -1
  174. data/spec/support/crud.rb +3 -1
  175. data/spec/support/crud/write.rb +6 -1
  176. data/spec/support/crud_tests/write/findOneAndUpdate-arrayFilters.yml +69 -0
  177. data/spec/support/crud_tests/write/updateMany-arrayFilters.yml +63 -0
  178. data/spec/support/crud_tests/write/updateOne-arrayFilters.yml +109 -0
  179. data/spec/support/sdam/rs/discover_arbiters.yml +1 -1
  180. data/spec/support/sdam/rs/discover_passives.yml +2 -2
  181. data/spec/support/sdam/rs/discover_primary.yml +1 -1
  182. data/spec/support/sdam/rs/discover_secondary.yml +1 -1
  183. data/spec/support/sdam/rs/discovery.yml +4 -4
  184. data/spec/support/sdam/rs/equal_electionids.yml +1 -0
  185. data/spec/support/sdam/rs/ghost_discovered.yml +1 -1
  186. data/spec/support/sdam/rs/hosts_differ_from_seeds.yml +1 -1
  187. data/spec/support/sdam/rs/ls_timeout.yml +88 -0
  188. data/spec/support/sdam/rs/member_reconfig.yml +2 -2
  189. data/spec/support/sdam/rs/member_standalone.yml +2 -2
  190. data/spec/support/sdam/rs/new_primary.yml +2 -2
  191. data/spec/support/sdam/rs/new_primary_new_electionid.yml +3 -0
  192. data/spec/support/sdam/rs/new_primary_new_setversion.yml +3 -0
  193. data/spec/support/sdam/rs/new_primary_wrong_set_name.yml +2 -2
  194. data/spec/support/sdam/rs/non_rs_member.yml +1 -1
  195. data/spec/support/sdam/rs/normalize_case.yml +1 -1
  196. data/spec/support/sdam/rs/null_election_id.yml +4 -0
  197. data/spec/support/sdam/rs/primary_becomes_standalone.yml +2 -2
  198. data/spec/support/sdam/rs/primary_changes_set_name.yml +2 -2
  199. data/spec/support/sdam/rs/primary_disconnect.yml +2 -2
  200. data/spec/support/sdam/rs/primary_disconnect_electionid.yml +5 -0
  201. data/spec/support/sdam/rs/primary_disconnect_setversion.yml +5 -0
  202. data/spec/support/sdam/rs/primary_hint_from_secondary_with_mismatched_me.yml +58 -0
  203. data/spec/support/sdam/rs/primary_reports_new_member.yml +4 -4
  204. data/spec/support/sdam/rs/primary_to_no_primary_mismatched_me.yml +2 -2
  205. data/spec/support/sdam/rs/primary_wrong_set_name.yml +1 -1
  206. data/spec/support/sdam/rs/response_from_removed.yml +2 -2
  207. data/spec/support/sdam/rs/rsother_discovered.yml +1 -1
  208. data/spec/support/sdam/rs/sec_not_auth.yml +1 -1
  209. data/spec/support/sdam/rs/secondary_wrong_set_name.yml +1 -1
  210. data/spec/support/sdam/rs/secondary_wrong_set_name_with_primary.yml +2 -2
  211. data/spec/support/sdam/rs/setversion_without_electionid.yml +2 -0
  212. data/spec/support/sdam/rs/stepdown_change_set_name.yml +2 -2
  213. data/spec/support/sdam/rs/unexpected_mongos.yml +1 -1
  214. data/spec/support/sdam/rs/use_setversion_without_electionid.yml +3 -0
  215. data/spec/support/sdam/rs/wrong_set_name.yml +1 -1
  216. data/spec/support/sdam/sharded/ls_timeout_mongos.yml +97 -0
  217. data/spec/support/sdam/sharded/mongos_disconnect.yml +3 -3
  218. data/spec/support/sdam/sharded/multiple_mongoses.yml +1 -1
  219. data/spec/support/sdam/sharded/non_mongos_removed.yml +1 -1
  220. data/spec/support/sdam/sharded/normalize_uri_case.yml +1 -1
  221. data/spec/support/sdam/single/direct_connection_external_ip.yml +1 -1
  222. data/spec/support/sdam/single/direct_connection_mongos.yml +1 -1
  223. data/spec/support/sdam/single/direct_connection_rsarbiter.yml +1 -1
  224. data/spec/support/sdam/single/direct_connection_rsprimary.yml +1 -1
  225. data/spec/support/sdam/single/direct_connection_rssecondary.yml +1 -1
  226. data/spec/support/sdam/single/direct_connection_slave.yml +1 -1
  227. data/spec/support/sdam/single/direct_connection_standalone.yml +1 -1
  228. data/spec/support/sdam/single/ls_timeout_standalone.yml +35 -0
  229. data/spec/support/sdam/single/not_ok_response.yml +1 -1
  230. data/spec/support/sdam/single/standalone_removed.yml +1 -1
  231. data/spec/support/sdam/single/unavailable_seed.yml +1 -1
  232. data/spec/support/server_discovery_and_monitoring.rb +4 -0
  233. data/spec/support/shared/session.rb +236 -0
  234. metadata +53 -15
  235. metadata.gz.sig +0 -0
@@ -0,0 +1,73 @@
1
+ # Copyright (C) 2017 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
+
17
+ class Session
18
+
19
+ # An object representing the server-side session.
20
+ #
21
+ # @api private
22
+ #
23
+ # @since 2.5.0
24
+ class ServerSession
25
+
26
+ # Regex for removing dashes from the UUID string.
27
+ #
28
+ # @since 2.5.0
29
+ DASH_REGEX = /\-/.freeze
30
+
31
+ # Pack directive for the UUID.
32
+ #
33
+ # @since 2.5.0
34
+ UUID_PACK = 'H*'.freeze
35
+
36
+ # The last time the server session was used.
37
+ #
38
+ # @since 2.5.0
39
+ attr_reader :last_use
40
+
41
+ # Initialize a ServerSession.
42
+ #
43
+ # @example
44
+ # ServerSession.new
45
+ #
46
+ # @since 2.5.0
47
+ def initialize
48
+ set_last_use!
49
+ end
50
+
51
+ # Update the last_use attribute of the server session to now.
52
+ #
53
+ # @example Set the last use field to now.
54
+ # server_session.set_last_use!
55
+ #
56
+ # @since 2.5.0
57
+ def set_last_use!
58
+ @last_use = Time.now
59
+ end
60
+
61
+ # The session id of this server session.
62
+ #
63
+ # @example Get the session id.
64
+ # server_session.session_id
65
+ #
66
+ # @since 2.5.0
67
+ def session_id
68
+ @session_id ||= (bytes = [SecureRandom.uuid.gsub(DASH_REGEX, '')].pack(UUID_PACK)
69
+ BSON::Document.new(id: BSON::Binary.new(bytes, :uuid)))
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,161 @@
1
+ # Copyright (C) 2017 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
+
17
+ class Session
18
+
19
+ # A pool of server sessions.
20
+ #
21
+ # @api private
22
+ #
23
+ # @since 2.5.0
24
+ class SessionPool
25
+
26
+ # The command sent to the server to end a session.
27
+ #
28
+ # @since 2.5.0
29
+ END_SESSION = { :endSessions => 1 }.freeze
30
+
31
+ # Create a SessionPool.
32
+ #
33
+ # @example
34
+ # SessionPool.create(client)
35
+ #
36
+ # @param [ Mongo::Client ] client The client that will be associated with this
37
+ # session pool.
38
+ #
39
+ # @since 2.5.0
40
+ def self.create(client)
41
+ pool = new(client)
42
+ client.instance_variable_set(:@session_pool, pool)
43
+ end
44
+
45
+ # Initialize a SessionPool.
46
+ #
47
+ # @example
48
+ # SessionPool.new(client)
49
+ #
50
+ # @param [ Mongo::Client ] client The client that will be associated with this
51
+ # session pool.
52
+ #
53
+ # @since 2.5.0
54
+ def initialize(client)
55
+ @queue = []
56
+ @mutex = Mutex.new
57
+ @client = client
58
+ end
59
+
60
+ # Checkout a session to be used in the context of a block and return the session back to
61
+ # the pool after the block completes.
62
+ #
63
+ # @example Checkout, use a session, and return it back to the pool after the block.
64
+ # pool.with_session do |session|
65
+ # ...
66
+ # end
67
+ #
68
+ # @yieldparam [ ServerSession ] The server session.
69
+ #
70
+ # @since 2.5.0
71
+ def with_session
72
+ server_session = checkout
73
+ result = yield(server_session)
74
+ result
75
+ ensure
76
+ begin; checkin(server_session) if server_session; rescue; end
77
+ end
78
+
79
+ # Checkout a server session from the pool.
80
+ #
81
+ # @example Checkout a session.
82
+ # pool.checkout
83
+ #
84
+ # @return [ ServerSession ] The server session.
85
+ #
86
+ # @since 2.5.0
87
+ def checkout
88
+ @mutex.synchronize do
89
+ loop do
90
+ if @queue.empty?
91
+ return ServerSession.new
92
+ else
93
+ session = @queue.shift
94
+ unless about_to_expire?(session)
95
+ return session
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ # Checkin a server session to the pool.
103
+ #
104
+ # @example Checkin a session.
105
+ # pool.checkin(session)
106
+ #
107
+ # @param [ Session::ServerSession ] The session to checkin.
108
+ #
109
+ # @since 2.5.0
110
+ def checkin(session)
111
+ @mutex.synchronize do
112
+ prune!
113
+ unless about_to_expire?(session)
114
+ @queue.unshift(session)
115
+ end
116
+ end
117
+ end
118
+
119
+ # End all sessions in the pool by sending the endSessions command to the server.
120
+ #
121
+ # @example End all sessions.
122
+ # pool.end_sessions
123
+ #
124
+ # @since 2.5.0
125
+ def end_sessions
126
+ if @client
127
+ ids = @queue.collect { |s| s.session_id }
128
+
129
+ while !ids.empty?
130
+ begin
131
+ Operation::Commands::Command.new({
132
+ :selector => END_SESSION.merge(ids: ids.shift(10_000)),
133
+ :db_name => Database::ADMIN
134
+ }).execute(@client.cluster.next_primary)
135
+ rescue
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ private
142
+
143
+ def about_to_expire?(session)
144
+ if @client.logical_session_timeout
145
+ idle_time_minutes = (Time.now - session.last_use) / 60
146
+ (idle_time_minutes + 1) >= @client.logical_session_timeout
147
+ end
148
+ end
149
+
150
+ def prune!
151
+ while !@queue.empty?
152
+ if about_to_expire?(@queue[-1])
153
+ @queue.pop
154
+ else
155
+ break
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
data/lib/mongo/uri.rb CHANGED
@@ -395,6 +395,8 @@ module Mongo
395
395
 
396
396
  # Client Options
397
397
  uri_option 'appname', :app_name
398
+ uri_option 'compressors', :compressors, :type => :array
399
+ uri_option 'zlibcompressionlevel', :zlib_compression_level
398
400
 
399
401
  # Casts option values that do not have a specifically provided
400
402
  # transformation to the appropriate type.
@@ -572,5 +574,14 @@ module Mongo
572
574
  set.merge(decode(k).downcase.to_sym => decode(v))
573
575
  end
574
576
  end
577
+
578
+ # Extract values from the string and put them into an array.
579
+ #
580
+ # @param [ String ] value The string to build an array from.
581
+ #
582
+ # @return [ Array ] The array built from the string.
583
+ def array(value)
584
+ value.split(',')
585
+ end
575
586
  end
576
587
  end
data/lib/mongo/version.rb CHANGED
@@ -17,5 +17,5 @@ module Mongo
17
17
  # The current version of the driver.
18
18
  #
19
19
  # @since 2.0.0
20
- VERSION = '2.4.3'.freeze
20
+ VERSION = '2.5.0.beta'.freeze
21
21
  end
data/mongo.gemspec CHANGED
@@ -29,5 +29,6 @@ Gem::Specification.new do |s|
29
29
  s.require_paths = ['lib']
30
30
  s.bindir = 'bin'
31
31
 
32
- s.add_dependency 'bson', '>=4.2.1', '<5.0.0'
32
+ #s.add_dependency 'bson', '>=4.3.0', '<5.0.0'
33
+ s.add_dependency 'bson', '4.3.0.beta'
33
34
  end
@@ -18,6 +18,8 @@ describe Mongo::Auth::CR do
18
18
  double('cluster').tap do |cl|
19
19
  allow(cl).to receive(:topology).and_return(topology)
20
20
  allow(cl).to receive(:app_metadata).and_return(app_metadata)
21
+ allow(cl).to receive(:cluster_time).and_return(nil)
22
+ allow(cl).to receive(:update_cluster_time)
21
23
  end
22
24
  end
23
25
 
@@ -58,6 +60,16 @@ describe Mongo::Auth::CR do
58
60
  cr.login(connection)
59
61
  }.to raise_error(Mongo::Auth::Unauthorized)
60
62
  end
63
+
64
+ context 'when compression is used', if: testing_compression? do
65
+
66
+ it 'does not compress the message' do
67
+ expect(Mongo::Protocol::Compressed).not_to receive(:new)
68
+ expect {
69
+ cr.login(connection)
70
+ }.to raise_error(Mongo::Auth::Unauthorized)
71
+ end
72
+ end
61
73
  end
62
74
  end
63
75
 
@@ -18,6 +18,8 @@ describe Mongo::Auth::LDAP do
18
18
  double('cluster').tap do |cl|
19
19
  allow(cl).to receive(:topology).and_return(topology)
20
20
  allow(cl).to receive(:app_metadata).and_return(app_metadata)
21
+ allow(cl).to receive(:cluster_time).and_return(nil)
22
+ allow(cl).to receive(:update_cluster_time)
21
23
  end
22
24
  end
23
25
 
@@ -48,7 +48,7 @@ describe Mongo::Auth::SCRAM::Conversation do
48
48
  describe '#continue' do
49
49
 
50
50
  let(:reply) do
51
- Mongo::Protocol::Reply.new
51
+ Mongo::Protocol::Message.new
52
52
  end
53
53
 
54
54
  let(:documents) do
@@ -62,7 +62,7 @@ describe Mongo::Auth::SCRAM::Conversation do
62
62
 
63
63
  before do
64
64
  expect(SecureRandom).to receive(:base64).once.and_return('NDA2NzU3MDY3MDYwMTgy')
65
- reply.instance_variable_set(:@documents, documents)
65
+ allow(reply).to receive(:documents).and_return(documents)
66
66
  end
67
67
 
68
68
  context 'when the server rnonce starts with the nonce' do
@@ -115,7 +115,7 @@ describe Mongo::Auth::SCRAM::Conversation do
115
115
  describe '#finalize' do
116
116
 
117
117
  let(:continue_reply) do
118
- Mongo::Protocol::Reply.new
118
+ Mongo::Protocol::Message.new
119
119
  end
120
120
 
121
121
  let(:continue_documents) do
@@ -134,7 +134,7 @@ describe Mongo::Auth::SCRAM::Conversation do
134
134
  end
135
135
 
136
136
  let(:reply) do
137
- Mongo::Protocol::Reply.new
137
+ Mongo::Protocol::Message.new
138
138
  end
139
139
 
140
140
  let(:documents) do
@@ -148,8 +148,8 @@ describe Mongo::Auth::SCRAM::Conversation do
148
148
 
149
149
  before do
150
150
  expect(SecureRandom).to receive(:base64).once.and_return('NDA2NzU3MDY3MDYwMTgy')
151
- continue_reply.instance_variable_set(:@documents, continue_documents)
152
- reply.instance_variable_set(:@documents, documents)
151
+ allow(continue_reply).to receive(:documents).and_return(continue_documents)
152
+ allow(reply).to receive(:documents).and_return(documents)
153
153
  end
154
154
 
155
155
  context 'when the verifier matches the server signature' do
@@ -18,6 +18,8 @@ describe Mongo::Auth::SCRAM do
18
18
  double('cluster').tap do |cl|
19
19
  allow(cl).to receive(:topology).and_return(topology)
20
20
  allow(cl).to receive(:app_metadata).and_return(app_metadata)
21
+ allow(cl).to receive(:cluster_time).and_return(nil)
22
+ allow(cl).to receive(:update_cluster_time)
21
23
  end
22
24
  end
23
25
 
@@ -54,6 +56,16 @@ describe Mongo::Auth::SCRAM do
54
56
  cr.login(connection)
55
57
  }.to raise_error(Mongo::Auth::Unauthorized)
56
58
  end
59
+
60
+ context 'when compression is used', if: testing_compression? do
61
+
62
+ it 'does not compress the message' do
63
+ expect(Mongo::Protocol::Compressed).not_to receive(:new)
64
+ expect {
65
+ cr.login(connection)
66
+ }.to raise_error(Mongo::Auth::Unauthorized)
67
+ end
68
+ end
57
69
  end
58
70
  end
59
71
 
@@ -67,8 +79,20 @@ describe Mongo::Auth::SCRAM do
67
79
  cr.login(connection).documents[0]
68
80
  end
69
81
 
70
- it 'logs the user into the connection', if: list_command_enabled? do
82
+ after do
83
+ root_user.instance_variable_set(:@client_key, nil)
84
+ end
85
+
86
+ it 'logs the user into the connection and caches the client key', if: list_command_enabled? do
71
87
  expect(login['ok']).to eq(1)
88
+ expect(root_user.send(:client_key)).not_to be_nil
89
+ end
90
+
91
+ it 'raises an exception when an incorrect client key is set', if: list_command_enabled? do
92
+ root_user.instance_variable_set(:@client_key, "incorrect client key")
93
+ expect {
94
+ cr.login(connection)
95
+ }.to raise_error(Mongo::Auth::Unauthorized)
72
96
  end
73
97
  end
74
98
  end
@@ -6,33 +6,67 @@ describe Mongo::Auth::User::View do
6
6
  described_class.new(root_authorized_client.database)
7
7
  end
8
8
 
9
+ after do
10
+ begin; view.remove('durran'); rescue; end
11
+ end
12
+
9
13
  describe '#create' do
10
14
 
11
- let!(:response) do
12
- view.create(
13
- 'durran',
14
- password: 'password', roles: [ Mongo::Auth::Roles::READ_WRITE ]
15
- )
16
- end
15
+ context 'when a session is not used' do
17
16
 
18
- after do
19
- view.remove('durran')
20
- end
17
+ let!(:response) do
18
+ view.create(
19
+ 'durran',
20
+ password: 'password', roles: [Mongo::Auth::Roles::READ_WRITE]
21
+ )
22
+ end
21
23
 
22
- context 'when user creation was successful' do
24
+ context 'when user creation was successful' do
23
25
 
24
- it 'saves the user in the database' do
25
- expect(response).to be_successful
26
+ it 'saves the user in the database' do
27
+ expect(response).to be_successful
28
+ end
29
+
30
+ context 'when compression is used', if: testing_compression? do
31
+
32
+ it 'does not compress the message' do
33
+ # The dropUser command message will be compressed, so expect instantiation once.
34
+ expect(Mongo::Protocol::Compressed).to receive(:new).once.and_call_original
35
+ expect(response).to be_successful
36
+ end
37
+ end
38
+ end
39
+
40
+ context 'when creation was not successful' do
41
+
42
+ it 'raises an exception' do
43
+ expect {
44
+ view.create('durran', password: 'password')
45
+ }.to raise_error(Mongo::Error::OperationFailure)
46
+ end
26
47
  end
27
48
  end
28
49
 
29
- context 'when creation was not successful' do
50
+ context 'when a session is used' do
51
+
52
+ let(:operation) do
53
+ view.create(
54
+ 'durran',
55
+ password: 'password',
56
+ roles: [Mongo::Auth::Roles::READ_WRITE],
57
+ session: session
58
+ )
59
+ end
30
60
 
31
- it 'raises an exception' do
32
- expect {
33
- view.create('durran', password: 'password')
34
- }.to raise_error(Mongo::Error::OperationFailure)
61
+ let(:session) do
62
+ client.start_session
35
63
  end
64
+
65
+ let(:client) do
66
+ root_authorized_client
67
+ end
68
+
69
+ it_behaves_like 'an operation using a session'
36
70
  end
37
71
  end
38
72
 
@@ -41,114 +75,272 @@ describe Mongo::Auth::User::View do
41
75
  before do
42
76
  view.create(
43
77
  'durran',
44
- password: 'password', roles: [ Mongo::Auth::Roles::READ_WRITE ]
78
+ password: 'password', roles: [Mongo::Auth::Roles::READ_WRITE]
45
79
  )
46
80
  end
47
81
 
48
- after do
49
- view.remove('durran')
50
- end
51
-
52
82
  context 'when a user password is updated' do
53
83
 
54
- let!(:response) do
55
- view.update(
56
- 'durran',
57
- password: '123', roles: [ Mongo::Auth::Roles::READ_WRITE ]
58
- )
84
+ context 'when a session is not used' do
85
+
86
+ let!(:response) do
87
+ view.update(
88
+ 'durran',
89
+ password: '123', roles: [ Mongo::Auth::Roles::READ_WRITE ]
90
+ )
91
+ end
92
+
93
+ it 'updates the password' do
94
+ expect(response).to be_successful
95
+ end
96
+
97
+ context 'when compression is used', if: testing_compression? do
98
+
99
+ it 'does not compress the message' do
100
+ # The dropUser command message will be compressed, so expect instantiation once.
101
+ expect(Mongo::Protocol::Compressed).to receive(:new).once.and_call_original
102
+ expect(response).to be_successful
103
+ end
104
+ end
59
105
  end
60
106
 
61
- it 'updates the password' do
62
- expect(response).to be_successful
107
+ context 'when a session is used' do
108
+
109
+ let(:operation) do
110
+ view.update(
111
+ 'durran',
112
+ password: '123',
113
+ roles: [ Mongo::Auth::Roles::READ_WRITE ],
114
+ session: session
115
+ )
116
+ end
117
+
118
+ let(:session) do
119
+ client.start_session
120
+ end
121
+
122
+ let(:client) do
123
+ root_authorized_client
124
+ end
125
+
126
+ it_behaves_like 'an operation using a session'
63
127
  end
64
128
  end
65
129
 
66
130
  context 'when the roles of a user are updated' do
67
131
 
68
- let!(:response) do
69
- view.update(
70
- 'durran',
71
- password: 'password', roles: [ Mongo::Auth::Roles::READ ]
72
- )
132
+ context 'when a session is not used' do
133
+
134
+ let!(:response) do
135
+ view.update(
136
+ 'durran',
137
+ password: 'password', roles: [ Mongo::Auth::Roles::READ ]
138
+ )
139
+ end
140
+
141
+ it 'updates the roles' do
142
+ expect(response).to be_successful
143
+ end
144
+
145
+ context 'when compression is used', if: testing_compression? do
146
+
147
+ it 'does not compress the message' do
148
+ # The dropUser command message will be compressed, so expect instantiation once.
149
+ expect(Mongo::Protocol::Compressed).to receive(:new).once.and_call_original
150
+ expect(response).to be_successful
151
+ end
152
+ end
73
153
  end
74
154
 
75
- it 'updates the roles' do
76
- expect(response).to be_successful
155
+ context 'when a session is used' do
156
+
157
+ let(:operation) do
158
+ view.update(
159
+ 'durran',
160
+ password: 'password',
161
+ roles: [ Mongo::Auth::Roles::READ ],
162
+ session: session
163
+ )
164
+ end
165
+
166
+ let(:session) do
167
+ client.start_session
168
+ end
169
+
170
+ let(:client) do
171
+ root_authorized_client
172
+ end
173
+
174
+ it_behaves_like 'an operation using a session'
77
175
  end
78
176
  end
79
177
  end
80
178
 
81
179
  describe '#remove' do
82
180
 
83
- context 'when user removal was successful' do
181
+ context 'when a session is not used' do
84
182
 
85
- before do
86
- view.create(
87
- 'durran',
88
- password: 'password', roles: [ Mongo::Auth::Roles::READ_WRITE ]
89
- )
90
- end
183
+ context 'when user removal was successful' do
91
184
 
92
- let(:response) do
93
- view.remove('durran')
185
+ before do
186
+ view.create(
187
+ 'durran',
188
+ password: 'password', roles: [ Mongo::Auth::Roles::READ_WRITE ]
189
+ )
190
+ end
191
+
192
+ let(:response) do
193
+ view.remove('durran')
194
+ end
195
+
196
+ it 'saves the user in the database' do
197
+ expect(response).to be_successful
198
+ end
94
199
  end
95
200
 
96
- it 'saves the user in the database' do
97
- expect(response).to be_successful
201
+ context 'when removal was not successful' do
202
+
203
+ it 'raises an exception', if: write_command_enabled? do
204
+ expect {
205
+ view.remove('notauser')
206
+ }.to raise_error(Mongo::Error::OperationFailure)
207
+ end
208
+
209
+ it 'does not raise an exception', unless: write_command_enabled? do
210
+ expect(view.remove('notauser').written_count).to eq(0)
211
+ end
98
212
  end
99
213
  end
100
214
 
101
- context 'when removal was not successful' do
215
+ context 'when a session is used' do
216
+
217
+ context 'when user removal was successful' do
102
218
 
103
- it 'raises an exception', if: write_command_enabled? do
104
- expect {
105
- view.remove('notauser')
106
- }.to raise_error(Mongo::Error::OperationFailure)
219
+ before do
220
+ view.create(
221
+ 'durran',
222
+ password: 'password', roles: [ Mongo::Auth::Roles::READ_WRITE ]
223
+ )
224
+ end
225
+
226
+ let(:operation) do
227
+ view.remove('durran', session: session)
228
+ end
229
+
230
+ let(:session) do
231
+ client.start_session
232
+ end
233
+
234
+ let(:client) do
235
+ root_authorized_client
236
+ end
237
+
238
+ it_behaves_like 'an operation using a session'
107
239
  end
108
240
 
109
- it 'does not raise an exception', unless: write_command_enabled? do
110
- expect(view.remove('notauser').written_count).to eq(0)
241
+ context 'when removal was not successful' do
242
+
243
+ let(:failed_operation) do
244
+ view.remove('notauser', session: session)
245
+ end
246
+
247
+ let(:session) do
248
+ client.start_session
249
+ end
250
+
251
+ let(:client) do
252
+ root_authorized_client
253
+ end
254
+
255
+ it_behaves_like 'a failed operation using a session'
111
256
  end
112
257
  end
113
258
  end
114
259
 
115
260
  describe '#info' do
116
261
 
117
- context 'when a user exists in the database' do
262
+ context 'when a session is not used' do
118
263
 
119
- before do
120
- view.create(
121
- 'emily',
122
- password: 'password'
123
- )
124
- end
264
+ context 'when a user exists in the database' do
265
+
266
+ before do
267
+ view.create(
268
+ 'emily',
269
+ password: 'password'
270
+ )
271
+ end
272
+
273
+ after do
274
+ view.remove('emily')
275
+ end
125
276
 
126
- after do
127
- view.remove('emily')
277
+ it 'returns information for that user' do
278
+ expect(view.info('emily')).to_not be_empty
279
+ end
128
280
  end
129
281
 
130
- it 'returns information for that user' do
131
- expect(view.info('emily')).to_not be_empty
282
+ context 'when a user does not exist in the database' do
283
+
284
+ it 'returns nil' do
285
+ expect(view.info('emily')).to be_empty
286
+ end
132
287
  end
133
- end
134
288
 
135
- context 'when a user does not exist in the database' do
289
+ context 'when a user is not authorized' do
136
290
 
137
- it 'returns nil' do
138
- expect(view.info('emily')).to be_empty
291
+ let(:view) do
292
+ described_class.new(unauthorized_client.database)
293
+ end
294
+
295
+ it 'raises an OperationFailure', if: auth_enabled? do
296
+ expect{
297
+ view.info('emily')
298
+ }.to raise_exception(Mongo::Error::OperationFailure)
299
+ end
139
300
  end
140
301
  end
141
302
 
142
- context 'when a user is not authorized' do
303
+ context 'when a session is used' do
304
+
305
+ context 'when a user exists in the database' do
306
+
307
+ before do
308
+ view.create(
309
+ 'durran',
310
+ password: 'password'
311
+ )
312
+ end
313
+
314
+ let(:operation) do
315
+ view.info('durran', session: session)
316
+ end
317
+
318
+ let(:session) do
319
+ client.start_session
320
+ end
143
321
 
144
- let(:view) do
145
- described_class.new(unauthorized_client.database)
322
+ let(:client) do
323
+ root_authorized_client
324
+ end
325
+
326
+ it_behaves_like 'an operation using a session'
146
327
  end
147
328
 
148
- it 'raises an OperationFailure', if: auth_enabled? do
149
- expect{
150
- view.info('emily')
151
- }.to raise_exception(Mongo::Error::OperationFailure)
329
+ context 'when a user does not exist in the database' do
330
+
331
+ let(:operation) do
332
+ view.info('emily', session: session)
333
+ end
334
+
335
+ let(:session) do
336
+ client.start_session
337
+ end
338
+
339
+ let(:client) do
340
+ root_authorized_client
341
+ end
342
+
343
+ it_behaves_like 'an operation using a session'
152
344
  end
153
345
  end
154
346
  end