mongo 2.4.3 → 2.5.0.beta

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