mongo 2.11.0.rc0 → 2.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +2 -0
  5. data/lib/mongo/auth.rb +11 -2
  6. data/lib/mongo/auth/cr/conversation.rb +1 -1
  7. data/lib/mongo/auth/ldap/conversation.rb +1 -1
  8. data/lib/mongo/auth/scram/conversation.rb +4 -1
  9. data/lib/mongo/auth/user.rb +15 -1
  10. data/lib/mongo/auth/user/view.rb +10 -4
  11. data/lib/mongo/auth/x509.rb +11 -1
  12. data/lib/mongo/auth/x509/conversation.rb +15 -6
  13. data/lib/mongo/background_thread.rb +28 -13
  14. data/lib/mongo/client.rb +23 -15
  15. data/lib/mongo/collection/view/change_stream.rb +5 -1
  16. data/lib/mongo/collection/view/readable.rb +5 -2
  17. data/lib/mongo/collection/view/writable.rb +3 -1
  18. data/lib/mongo/cursor/builder/get_more_command.rb +4 -1
  19. data/lib/mongo/cursor/builder/kill_cursors_command.rb +16 -5
  20. data/lib/mongo/cursor/builder/op_get_more.rb +2 -2
  21. data/lib/mongo/cursor/builder/op_kill_cursors.rb +17 -5
  22. data/lib/mongo/error/operation_failure.rb +3 -3
  23. data/lib/mongo/monitoring/command_log_subscriber.rb +5 -3
  24. data/lib/mongo/monitoring/event/command_started.rb +13 -3
  25. data/lib/mongo/monitoring/publishable.rb +4 -2
  26. data/lib/mongo/operation/create_user/command.rb +1 -0
  27. data/lib/mongo/operation/remove_user/command.rb +1 -0
  28. data/lib/mongo/operation/update_user/command.rb +1 -0
  29. data/lib/mongo/protocol/get_more.rb +2 -1
  30. data/lib/mongo/protocol/kill_cursors.rb +6 -13
  31. data/lib/mongo/protocol/serializers.rb +10 -4
  32. data/lib/mongo/retryable.rb +1 -1
  33. data/lib/mongo/server/connection.rb +6 -2
  34. data/lib/mongo/server/connection_base.rb +2 -1
  35. data/lib/mongo/server/monitor.rb +1 -1
  36. data/lib/mongo/server/pending_connection.rb +6 -0
  37. data/lib/mongo/socket/ssl.rb +1 -1
  38. data/lib/mongo/uri.rb +5 -41
  39. data/lib/mongo/version.rb +1 -1
  40. data/mongo.gemspec +11 -2
  41. data/spec/README.md +105 -9
  42. data/spec/USERS.md +72 -0
  43. data/spec/integration/auth_spec.rb +20 -6
  44. data/spec/integration/client_construction_spec.rb +3 -1
  45. data/spec/integration/client_options_spec.rb +437 -0
  46. data/spec/integration/command_monitoring_spec.rb +4 -1
  47. data/spec/integration/connection_pool_populator_spec.rb +4 -0
  48. data/spec/integration/connection_spec.rb +4 -2
  49. data/spec/integration/cursor_reaping_spec.rb +1 -1
  50. data/spec/integration/get_more_spec.rb +32 -0
  51. data/spec/integration/retryable_errors_spec.rb +99 -0
  52. data/spec/integration/retryable_writes_errors_spec.rb +11 -10
  53. data/spec/lite_spec_helper.rb +2 -1
  54. data/spec/mongo/auth/scram_spec.rb +1 -0
  55. data/spec/mongo/auth/user/view_spec.rb +102 -1
  56. data/spec/mongo/auth/user_spec.rb +56 -15
  57. data/spec/mongo/auth/x509_spec.rb +31 -1
  58. data/spec/mongo/bulk_write_spec.rb +2 -2
  59. data/spec/mongo/collection/view/change_stream_spec.rb +2 -2
  60. data/spec/mongo/collection/view/readable_spec.rb +8 -4
  61. data/spec/mongo/cursor/builder/get_more_command_spec.rb +4 -2
  62. data/spec/mongo/cursor/builder/op_get_more_spec.rb +4 -2
  63. data/spec/mongo/cursor_spec.rb +3 -3
  64. data/spec/mongo/retryable_spec.rb +31 -52
  65. data/spec/mongo/server/connection_auth_spec.rb +3 -0
  66. data/spec/mongo/server/connection_pool_spec.rb +4 -0
  67. data/spec/mongo/server/connection_spec.rb +12 -4
  68. data/spec/mongo/server/monitor_spec.rb +19 -1
  69. data/spec/mongo/socket/ssl_spec.rb +1 -1
  70. data/spec/mongo/uri/srv_protocol_spec.rb +0 -13
  71. data/spec/mongo/uri_option_parsing_spec.rb +0 -8
  72. data/spec/mongo/uri_spec.rb +6 -20
  73. data/spec/runners/connection_string.rb +116 -0
  74. data/spec/runners/read_write_concern_document.rb +67 -0
  75. data/spec/spec_tests/change_streams_spec.rb +17 -2
  76. data/spec/spec_tests/connection_string_spec.rb +2 -59
  77. data/spec/spec_tests/data/change_streams/change-streams-errors.yml +3 -3
  78. data/spec/spec_tests/data/change_streams/change-streams.yml +88 -20
  79. data/spec/spec_tests/data/cmap/connection-must-have-id.yml +6 -0
  80. data/spec/spec_tests/data/cmap/connection-must-order-ids.yml +6 -0
  81. data/spec/spec_tests/data/cmap/pool-checkin-destroy-closed.yml +3 -0
  82. data/spec/spec_tests/data/cmap/pool-checkin-destroy-stale.yml +3 -0
  83. data/spec/spec_tests/data/cmap/pool-checkin-make-available.yml +3 -0
  84. data/spec/spec_tests/data/cmap/pool-checkin.yml +1 -0
  85. data/spec/spec_tests/data/cmap/pool-checkout-connection.yml +2 -0
  86. data/spec/spec_tests/data/cmap/pool-checkout-error-closed.yml +5 -0
  87. data/spec/spec_tests/data/cmap/pool-checkout-multiple.yml +3 -0
  88. data/spec/spec_tests/data/cmap/pool-checkout-no-idle.yml +4 -0
  89. data/spec/spec_tests/data/cmap/pool-checkout-no-stale.yml +4 -0
  90. data/spec/spec_tests/data/cmap/pool-close-destroy-conns.yml +2 -0
  91. data/spec/spec_tests/data/cmap/pool-create-max-size.yml +15 -0
  92. data/spec/spec_tests/data/cmap/pool-create-min-size.yml +4 -0
  93. data/spec/spec_tests/data/cmap/wait-queue-fairness.yml +31 -1
  94. data/spec/spec_tests/data/cmap/wait-queue-timeout.yml +5 -0
  95. data/spec/spec_tests/data/read_write_concern/connection-string/read-concern.yml +32 -0
  96. data/spec/spec_tests/data/read_write_concern/connection-string/write-concern.yml +82 -0
  97. data/spec/spec_tests/data/read_write_concern/document/read-concern.yml +37 -0
  98. data/spec/spec_tests/data/read_write_concern/document/write-concern.yml +100 -0
  99. data/spec/spec_tests/data/retryable_reads/aggregate-merge.yml +39 -0
  100. data/spec/spec_tests/data/retryable_reads/aggregate-serverErrors.yml +1 -1
  101. data/spec/spec_tests/data/retryable_reads/changeStreams-client.watch-serverErrors.yml +2 -2
  102. data/spec/spec_tests/data/retryable_reads/changeStreams-client.watch.yml +1 -1
  103. data/spec/spec_tests/data/retryable_reads/changeStreams-db.coll.watch-serverErrors.yml +2 -2
  104. data/spec/spec_tests/data/retryable_reads/changeStreams-db.coll.watch.yml +1 -1
  105. data/spec/spec_tests/data/retryable_reads/changeStreams-db.watch-serverErrors.yml +2 -2
  106. data/spec/spec_tests/data/retryable_reads/changeStreams-db.watch.yml +1 -1
  107. data/spec/spec_tests/data/retryable_reads/count-serverErrors.yml +1 -1
  108. data/spec/spec_tests/data/retryable_reads/countDocuments-serverErrors.yml +1 -1
  109. data/spec/spec_tests/data/retryable_reads/distinct-serverErrors.yml +1 -1
  110. data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-serverErrors.yml +1 -1
  111. data/spec/spec_tests/data/retryable_reads/find-serverErrors.yml +1 -1
  112. data/spec/spec_tests/data/retryable_reads/findOne-serverErrors.yml +1 -1
  113. data/spec/spec_tests/data/retryable_reads/gridfs-download-serverErrors.yml +1 -1
  114. data/spec/spec_tests/data/retryable_reads/gridfs-downloadByName-serverErrors.yml +1 -1
  115. data/spec/spec_tests/data/retryable_reads/listCollectionNames-serverErrors.yml +1 -1
  116. data/spec/spec_tests/data/retryable_reads/listCollectionObjects-serverErrors.yml +1 -1
  117. data/spec/spec_tests/data/retryable_reads/listCollections-serverErrors.yml +1 -1
  118. data/spec/spec_tests/data/retryable_reads/listDatabaseNames-serverErrors.yml +1 -1
  119. data/spec/spec_tests/data/retryable_reads/listDatabaseObjects-serverErrors.yml +1 -1
  120. data/spec/spec_tests/data/retryable_reads/listDatabases-serverErrors.yml +1 -1
  121. data/spec/spec_tests/data/retryable_reads/listIndexNames-serverErrors.yml +1 -1
  122. data/spec/spec_tests/data/retryable_reads/listIndexes-serverErrors.yml +1 -1
  123. data/spec/spec_tests/data/transactions/read-concern.yml +6 -6
  124. data/spec/spec_tests/data/transactions/transaction-options-repl.yml +117 -0
  125. data/spec/spec_tests/data/transactions/transaction-options.yml +14 -121
  126. data/spec/spec_tests/data/transactions/write-concern.yml +3 -0
  127. data/spec/spec_tests/data/transactions_api/transaction-options.yml +11 -12
  128. data/spec/spec_tests/dns_seedlist_discovery_spec.rb +17 -7
  129. data/spec/spec_tests/read_write_concern_connection_string_spec.rb +8 -0
  130. data/spec/spec_tests/read_write_concern_document_spec.rb +74 -0
  131. data/spec/spec_tests/retryable_reads_spec.rb +32 -1
  132. data/spec/spec_tests/uri_options_spec.rb +4 -2
  133. data/spec/support/auth.rb +5 -14
  134. data/spec/support/certificates/client-x509.crt +78 -0
  135. data/spec/support/certificates/client-x509.key +27 -0
  136. data/spec/support/certificates/client-x509.pem +105 -0
  137. data/spec/support/change_streams.rb +8 -11
  138. data/spec/support/client_registry.rb +26 -12
  139. data/spec/support/cluster_tools.rb +2 -2
  140. data/spec/support/cmap.rb +11 -7
  141. data/spec/support/command_monitoring.rb +8 -8
  142. data/spec/support/connection_string.rb +56 -28
  143. data/spec/support/constraints.rb +8 -0
  144. data/spec/support/crud/spec.rb +5 -8
  145. data/spec/support/event_subscriber.rb +7 -0
  146. data/spec/support/gridfs.rb +4 -7
  147. data/spec/support/server_discovery_and_monitoring.rb +3 -8
  148. data/spec/support/server_selection.rb +4 -9
  149. data/spec/support/server_selection_rtt.rb +4 -7
  150. data/spec/support/spec_config.rb +47 -19
  151. data/spec/support/spec_setup.rb +5 -0
  152. data/spec/support/utils.rb +46 -8
  153. metadata +637 -597
  154. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b7c88c591ffb30fe10134db69727372a4d1c3801a11dce59804ebe53d475d08f
4
- data.tar.gz: 16ce4f803cd46df9e0bc6948048fc4c0ea5356d437fbf75b149d38cd872ccca1
3
+ metadata.gz: d27047092172489df2f36b02e09050990a7aae2685a055bf4a30d33a43b86325
4
+ data.tar.gz: 0f14e016a1dbae9ccda55d77927a773d58a10967b959b9480b052c2df9410386
5
5
  SHA512:
6
- metadata.gz: eb30b7789af0a8816ce50e4b5c3be68e0b0a6f3a0b2da8d4c13a6f6bc8ad826b6a6b505e99df369ed49b24543baa28ff08db655ce3701c1fd2f13b55d4bb9374
7
- data.tar.gz: 7490c21d89f2b2c88aaa69d8203973869c409c637c0a212cb2d3cd2783ca258cd6a2df6729375e39894303b39541fd0296faee7c691d1b3e4c3553f6c6169385
6
+ metadata.gz: 3cf2e4bfd5860003b7131c72fae1b58a0a56906a73d67e9e08c465cd5cf0b79f99af431e55597733f3baf9d68a9617cec47647d4bb7b9c8e84eedeeff96509b9
7
+ data.tar.gz: 190be385cbcfdae0293448281010b8d6c4ca785b37236fe57362921eaeb7cfdb5115dd0159e51622946b97170fa105a375fd0a73ceb4600b268e599aa687dcf1
Binary file
data.tar.gz.sig CHANGED
Binary file
data/Rakefile CHANGED
@@ -29,6 +29,7 @@ namespace :spec do
29
29
  task :prepare do
30
30
  $: << File.join(File.dirname(__FILE__), 'spec')
31
31
 
32
+ require 'support/utils'
32
33
  require 'support/spec_setup'
33
34
  SpecSetup.new.run
34
35
  end
@@ -40,6 +41,7 @@ namespace :spec do
40
41
  # Since this task is usually used for troubleshooting of test suite
41
42
  # configuration, leave driver log level at the default of debug to
42
43
  # have connection diagnostics printed during handshakes and such.
44
+ require 'support/utils'
43
45
  require 'support/spec_config'
44
46
  require 'support/client_registry'
45
47
  SpecConfig.instance.print_summary
@@ -109,9 +109,10 @@ module Mongo
109
109
  # @param [ Mongo::Auth::User ] user The unauthorized user.
110
110
  # @param [ String ] used_mechanism Auth mechanism actually used for
111
111
  # authentication. This is a full string like SCRAM-SHA-256.
112
+ # @param [ String ] message The error message returned by the server.
112
113
  #
113
114
  # @since 2.0.0
114
- def initialize(user, used_mechanism = nil)
115
+ def initialize(user, used_mechanism: nil, message: nil)
115
116
  specified_mechanism = if user.mechanism
116
117
  " (mechanism: #{user.mechanism})"
117
118
  else
@@ -122,7 +123,15 @@ module Mongo
122
123
  else
123
124
  ''
124
125
  end
125
- msg = "User #{user.name}#{specified_mechanism} is not authorized to access #{user.database}#{used_mechanism}"
126
+ used_user = if user.mechanism == :mongodb_x509
127
+ 'Client certificate'
128
+ else
129
+ "User #{user.name}"
130
+ end
131
+ msg = "#{used_user}#{specified_mechanism} is not authorized to access #{user.database} (auth source: #{user.auth_source})#{used_mechanism}"
132
+ if message
133
+ msg += ': ' + message
134
+ end
126
135
  super(msg)
127
136
  end
128
137
  end
@@ -131,7 +131,7 @@ module Mongo
131
131
 
132
132
  def validate!(reply)
133
133
  if reply.documents[0][Operation::Result::OK] != 1
134
- raise Unauthorized.new(user, MECHANISM)
134
+ raise Unauthorized.new(user, used_mechanism: MECHANISM)
135
135
  end
136
136
  @nonce = reply.documents[0][Auth::NONCE]
137
137
  @reply = reply
@@ -98,7 +98,7 @@ module Mongo
98
98
 
99
99
  def validate!(reply)
100
100
  if reply.documents[0][Operation::Result::OK] != 1
101
- raise Unauthorized.new(user, MECHANISM)
101
+ raise Unauthorized.new(user, used_mechanism: MECHANISM)
102
102
  end
103
103
  @reply = reply
104
104
  end
@@ -519,7 +519,10 @@ module Mongo
519
519
 
520
520
  def validate!(reply)
521
521
  if reply.documents[0][Operation::Result::OK] != 1
522
- raise Unauthorized.new(user, full_mechanism)
522
+ raise Unauthorized.new(user,
523
+ used_mechanism: full_mechanism,
524
+ message: reply.documents[0]['errmsg'],
525
+ )
523
526
  end
524
527
  @reply = reply
525
528
  end
@@ -159,7 +159,7 @@ module Mongo
159
159
  # @since 2.0.0
160
160
  def initialize(options)
161
161
  @database = options[:database] || Database::ADMIN
162
- @auth_source = options[:auth_source] || @database
162
+ @auth_source = options[:auth_source] || self.class.default_auth_source(options)
163
163
  @name = options[:user]
164
164
  @password = options[:password] || options[:pwd]
165
165
  @mechanism = options[:auth_mech]
@@ -205,6 +205,20 @@ module Mongo
205
205
  #
206
206
  # @return [ String ] The client key for the user.
207
207
  attr_reader :client_key
208
+
209
+ # Generate default auth source based on the URI and options
210
+ #
211
+ # @api private
212
+ def self.default_auth_source(options)
213
+ case options[:auth_mech]
214
+ when :gssapi, :mongodb_x509
215
+ '$external'
216
+ when :plain
217
+ options[:database] || '$external'
218
+ else
219
+ options[:database] || Database::ADMIN
220
+ end
221
+ end
208
222
  end
209
223
  end
210
224
  end
@@ -37,6 +37,7 @@ module Mongo
37
37
  # @param [ Hash ] options The user options.
38
38
  #
39
39
  # @option options [ Session ] :session The session to use for the operation.
40
+ # @option options [ Hash ] :write_concern The write concern options.
40
41
  #
41
42
  # @return [ Result ] The command response.
42
43
  #
@@ -47,7 +48,8 @@ module Mongo
47
48
  Operation::CreateUser.new(
48
49
  user: user,
49
50
  db_name: database.name,
50
- session: session
51
+ session: session,
52
+ write_concern: options[:write_concern] && WriteConcern.get(options[:write_concern]),
51
53
  ).execute(next_primary(nil, session))
52
54
  end
53
55
  end
@@ -73,6 +75,7 @@ module Mongo
73
75
  # @param [ Hash ] options The options for the remove operation.
74
76
  #
75
77
  # @option options [ Session ] :session The session to use for the operation.
78
+ # @option options [ Hash ] :write_concern The write concern options.
76
79
  #
77
80
  # @return [ Result ] The command response.
78
81
  #
@@ -82,7 +85,8 @@ module Mongo
82
85
  Operation::RemoveUser.new(
83
86
  user_name: name,
84
87
  db_name: database.name,
85
- session: session
88
+ session: session,
89
+ write_concern: options[:write_concern] && WriteConcern.get(options[:write_concern]),
86
90
  ).execute(next_primary(nil, session))
87
91
  end
88
92
  end
@@ -96,6 +100,7 @@ module Mongo
96
100
  # @param [ Hash ] options The user options.
97
101
  #
98
102
  # @option options [ Session ] :session The session to use for the operation.
103
+ # @option options [ Hash ] :write_concern The write concern options.
99
104
  #
100
105
  # @return [ Result ] The response.
101
106
  #
@@ -106,7 +111,8 @@ module Mongo
106
111
  Operation::UpdateUser.new(
107
112
  user: user,
108
113
  db_name: database.name,
109
- session: session
114
+ session: session,
115
+ write_concern: options[:write_concern] && WriteConcern.get(options[:write_concern]),
110
116
  ).execute(next_primary(nil, session))
111
117
  end
112
118
  end
@@ -121,7 +127,7 @@ module Mongo
121
127
  #
122
128
  # @option options [ Session ] :session The session to use for the operation.
123
129
  #
124
- # @return [ Hash ] A document containing information on a particular user.
130
+ # @return [ Array ] An array wrapping a document containing information on a particular user.
125
131
  #
126
132
  # @since 2.1.0
127
133
  def info(name, options = {})
@@ -17,7 +17,7 @@ require 'mongo/auth/x509/conversation'
17
17
  module Mongo
18
18
  module Auth
19
19
 
20
- # Defines behavior for x.509 authentication.
20
+ # Defines behavior for X.509 authentication.
21
21
  #
22
22
  # @since 2.0.0
23
23
  class X509
@@ -39,6 +39,16 @@ module Mongo
39
39
  #
40
40
  # @since 2.0.0
41
41
  def initialize(user)
42
+ # The only valid database for X.509 authentication is $external.
43
+ if user.auth_source != '$external'
44
+ user_name_msg = if user.name
45
+ " #{user.name}"
46
+ else
47
+ ''
48
+ end
49
+ raise Auth::InvalidConfiguration, "User#{user_name_msg} specifies auth source '#{user.auth_source}', but the only valid auth source for X.509 is '$external'"
50
+ end
51
+
42
52
  @user = user
43
53
  end
44
54
 
@@ -16,7 +16,7 @@ module Mongo
16
16
  module Auth
17
17
  class X509
18
18
 
19
- # Defines behavior around a single x.509 conversation between the
19
+ # Defines behavior around a single X.509 conversation between the
20
20
  # client and server.
21
21
  #
22
22
  # @since 2.0.0
@@ -34,7 +34,7 @@ module Mongo
34
34
  # @return [ User ] user The user for the conversation.
35
35
  attr_reader :user
36
36
 
37
- # Finalize the x.509 conversation. This is meant to be iterated until
37
+ # Finalize the X.509 conversation. This is meant to be iterated until
38
38
  # the provided reply indicates the conversation is finished.
39
39
  #
40
40
  # @example Finalize the conversation.
@@ -50,7 +50,7 @@ module Mongo
50
50
  validate!(reply)
51
51
  end
52
52
 
53
- # Start the x.509 conversation. This returns the first message that
53
+ # Start the X.509 conversation. This returns the first message that
54
54
  # needs to be sent to the server.
55
55
  #
56
56
  # @example Start the conversation.
@@ -58,7 +58,7 @@ module Mongo
58
58
  #
59
59
  # @param [ Mongo::Server::Connection ] connection The connection being authenticated.
60
60
  #
61
- # @return [ Protocol::Query ] The first x.509 conversation message.
61
+ # @return [ Protocol::Query ] The first X.509 conversation message.
62
62
  #
63
63
  # @since 2.0.0
64
64
  def start(connection = nil)
@@ -66,7 +66,16 @@ module Mongo
66
66
  login[:user] = user.name if user.name
67
67
  if connection && connection.features.op_msg_enabled?
68
68
  selector = login
69
- selector[Protocol::Msg::DATABASE_IDENTIFIER] = user.auth_source
69
+ # The only valid database for X.509 authentication is $external.
70
+ if user.auth_source != '$external'
71
+ user_name_msg = if user.name
72
+ " #{user.name}"
73
+ else
74
+ ''
75
+ end
76
+ raise Auth::InvalidConfiguration, "User#{user_name_msg} specifies auth source '#{user.auth_source}', but the only valid auth source for X.509 is '$external'"
77
+ end
78
+ selector[Protocol::Msg::DATABASE_IDENTIFIER] = '$external'
70
79
  cluster_time = connection.mongos? && connection.cluster_time
71
80
  selector[Operation::CLUSTER_TIME] = cluster_time if cluster_time
72
81
  Protocol::Msg.new([], {}, selector)
@@ -96,7 +105,7 @@ module Mongo
96
105
 
97
106
  def validate!(reply)
98
107
  if reply.documents[0][Operation::Result::OK] != 1
99
- raise Unauthorized.new(user, MECHANISM)
108
+ raise Unauthorized.new(user, used_mechanism: MECHANISM)
100
109
  end
101
110
  @reply = reply
102
111
  end
@@ -30,6 +30,14 @@ module Mongo
30
30
  #
31
31
  # @api public for backwards compatibility only
32
32
  def run!
33
+ if @stop_requested && @thread
34
+ wait_for_stop
35
+ if @thread.alive?
36
+ log_warn("Starting a new background thread in #{self}, but the previous background thread is still running")
37
+ @thread = nil
38
+ end
39
+ @stop_requested = false
40
+ end
33
41
  if running?
34
42
  @thread
35
43
  else
@@ -81,6 +89,25 @@ module Mongo
81
89
  # the middle of an operation.
82
90
  @thread.kill
83
91
 
92
+ wait_for_stop
93
+ end
94
+
95
+ private
96
+
97
+ def start!
98
+ @thread = Thread.new do
99
+ catch(:done) do
100
+ until @stop_requested
101
+ do_work
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ # Waits for the thread to die, with a timeout.
108
+ #
109
+ # Returns true if the thread died, false otherwise.
110
+ def wait_for_stop
84
111
  # Wait for the thread to die. This is important in order to reliably
85
112
  # clean up resources like connections knowing that no background
86
113
  # thread will reconnect because it is still working.
@@ -106,23 +133,11 @@ module Mongo
106
133
  false
107
134
  else
108
135
  @thread = nil
136
+ @stop_requested = false
109
137
  true
110
138
  end
111
139
  end
112
140
 
113
- private
114
-
115
- # @return [ Thread ] The created Thread instance.
116
- def start!
117
- @thread = Thread.new do
118
- catch(:done) do
119
- until @stop_requested
120
- do_work
121
- end
122
- end
123
- end
124
- end
125
-
126
141
  # Override this method to do the work in the background thread.
127
142
  def do_work
128
143
  end
@@ -363,7 +363,8 @@ module Mongo
363
363
  # @option options [ Hash ] :write Deprecated. Equivalent to :write_concern
364
364
  # option.
365
365
  # @option options [ Hash ] :write_concern The write concern options.
366
- # Can be :w => Integer|String, :fsync => Boolean, :j => Boolean.
366
+ # Can be :w => Integer|String, :wtimeout => Integer (in milliseconds),
367
+ # :j => Boolean, :fsync => Boolean.
367
368
  # @option options [ Integer ] :zlib_compression_level The Zlib compression level to use, if using compression.
368
369
  # See Ruby's Zlib module for valid levels.
369
370
  # @option options [ Hash ] :resolv_options For internal driver use only.
@@ -371,11 +372,7 @@ module Mongo
371
372
  #
372
373
  # @since 2.0.0
373
374
  def initialize(addresses_or_uri, options = nil)
374
- if options
375
- options = options.dup
376
- else
377
- options = {}
378
- end
375
+ options = options ? options.dup : {}
379
376
 
380
377
  srv_uri = nil
381
378
  if addresses_or_uri.is_a?(::String)
@@ -401,18 +398,12 @@ module Mongo
401
398
  @srv_records = nil
402
399
  end
403
400
 
404
- unless options[:retry_reads] == false
405
- options[:retry_reads] = true
406
- end
407
- unless options[:retry_writes] == false
408
- options[:retry_writes] = true
409
- end
410
-
411
401
  # Special handling for sdam_proc as it is only used during client
412
402
  # construction
413
403
  sdam_proc = options.delete(:sdam_proc)
414
404
 
415
- @options = validate_new_options!(Database::DEFAULT_OPTIONS.merge(options))
405
+ options = default_options(options).merge(options)
406
+ @options = validate_new_options!(options)
416
407
  =begin WriteConcern object support
417
408
  if @options[:write_concern].is_a?(WriteConcern::Base)
418
409
  # Cache the instance so that we do not needlessly reconstruct it.
@@ -814,6 +805,23 @@ module Mongo
814
805
 
815
806
  private
816
807
 
808
+ # Generate default client options based on the URI and options
809
+ # passed into the Client constructor.
810
+ def default_options(options)
811
+ Database::DEFAULT_OPTIONS.dup.tap do |default_options|
812
+ if options[:auth_mech] || options[:user]
813
+ default_options[:auth_source] = Auth::User.default_auth_source(options)
814
+ end
815
+
816
+ if options[:auth_mech] == :gssapi
817
+ default_options[:auth_mech_properties] = { service_name: 'mongodb' }
818
+ end
819
+
820
+ default_options[:retry_reads] = true
821
+ default_options[:retry_writes] = true
822
+ end
823
+ end
824
+
817
825
  # If options[:session] is set, validates that session and returns it.
818
826
  # If deployment supports sessions, creates a new session and returns it.
819
827
  # The session is implicit unless options[:implicit] is given.
@@ -914,7 +922,7 @@ module Mongo
914
922
  raise Mongo::Auth::InvalidConfiguration.new('password is not supported for mongodb_x509')
915
923
  end
916
924
 
917
- if ![:external, nil].include?(auth_source) && [:gssapi, :mongodb_x509].include?(auth_mech)
925
+ if !['$external', nil].include?(auth_source) && [:gssapi, :mongodb_x509].include?(auth_mech)
918
926
  raise Mongo::Auth::InvalidConfiguration.new("#{auth_source} is an invalid auth source for #{auth_mech}; valid options are $external and nil")
919
927
  end
920
928
 
@@ -296,7 +296,11 @@ module Mongo
296
296
  end
297
297
 
298
298
  def change_doc
299
- { fullDocument: ( @options[:full_document] || FULL_DOCUMENT_DEFAULT ) }.tap do |doc|
299
+ {}.tap do |doc|
300
+ if @options[:full_document]
301
+ doc[:fullDocument] = @options[:full_document]
302
+ end
303
+
300
304
  if resuming?
301
305
  # We have a resume token once we retrieved any documents.
302
306
  # However, if the first getMore fails and the user didn't pass
@@ -244,6 +244,9 @@ module Mongo
244
244
  #
245
245
  # @since 2.0.0
246
246
  def distinct(field_name, opts = {})
247
+ if field_name.nil?
248
+ raise ArgumentError, 'Field name for distinct operation must be not nil'
249
+ end
247
250
  cmd = { :distinct => collection.name,
248
251
  :key => field_name.to_s,
249
252
  :query => filter }
@@ -602,7 +605,7 @@ module Mongo
602
605
  cmd.execute(server).cursor_ids.map do |cursor_id|
603
606
  result = if server.features.find_command_enabled?
604
607
  Operation::GetMore.new({
605
- :selector => {:getMore => cursor_id,
608
+ :selector => {:getMore => BSON::Int64.new(cursor_id),
606
609
  :collection => collection.name},
607
610
  :db_name => database.name,
608
611
  :session => session,
@@ -610,7 +613,7 @@ module Mongo
610
613
  else
611
614
  Operation::GetMore.new({
612
615
  :to_return => 0,
613
- :cursor_id => cursor_id,
616
+ :cursor_id => BSON::Int64.new(cursor_id),
614
617
  :db_name => database.name,
615
618
  :coll_name => collection.name
616
619
  }).execute(server)