mongo 1.8.6 → 1.12.5

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 (129) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/LICENSE +1 -1
  4. data/README.md +114 -282
  5. data/Rakefile +18 -4
  6. data/VERSION +1 -1
  7. data/bin/mongo_console +27 -5
  8. data/lib/mongo/bulk_write_collection_view.rb +387 -0
  9. data/lib/mongo/collection.rb +283 -222
  10. data/lib/mongo/collection_writer.rb +364 -0
  11. data/lib/mongo/{util → connection}/node.rb +58 -6
  12. data/lib/mongo/{util → connection}/pool.rb +61 -37
  13. data/lib/mongo/{util → connection}/pool_manager.rb +72 -22
  14. data/lib/mongo/{util → connection}/sharding_pool_manager.rb +13 -0
  15. data/lib/mongo/connection/socket/socket_util.rb +37 -0
  16. data/lib/mongo/connection/socket/ssl_socket.rb +95 -0
  17. data/lib/mongo/connection/socket/tcp_socket.rb +87 -0
  18. data/lib/mongo/connection/socket/unix_socket.rb +39 -0
  19. data/lib/mongo/connection/socket.rb +18 -0
  20. data/lib/mongo/connection.rb +19 -0
  21. data/lib/mongo/cursor.rb +183 -57
  22. data/lib/mongo/db.rb +302 -138
  23. data/lib/mongo/exception.rb +145 -0
  24. data/lib/mongo/functional/authentication.rb +455 -0
  25. data/lib/mongo/{util → functional}/logging.rb +23 -7
  26. data/lib/mongo/functional/read_preference.rb +183 -0
  27. data/lib/mongo/functional/scram.rb +556 -0
  28. data/lib/mongo/functional/uri_parser.rb +409 -0
  29. data/lib/mongo/{util → functional}/write_concern.rb +21 -9
  30. data/lib/mongo/functional.rb +20 -0
  31. data/lib/mongo/gridfs/grid.rb +19 -8
  32. data/lib/mongo/gridfs/grid_ext.rb +14 -0
  33. data/lib/mongo/gridfs/grid_file_system.rb +17 -4
  34. data/lib/mongo/gridfs/grid_io.rb +21 -9
  35. data/lib/mongo/gridfs.rb +18 -0
  36. data/lib/mongo/legacy.rb +76 -7
  37. data/lib/mongo/mongo_client.rb +246 -206
  38. data/lib/mongo/mongo_replica_set_client.rb +65 -15
  39. data/lib/mongo/mongo_sharded_client.rb +18 -3
  40. data/lib/mongo/networking.rb +47 -18
  41. data/lib/mongo/{util → utils}/conversions.rb +18 -3
  42. data/lib/mongo/{util → utils}/core_ext.rb +15 -32
  43. data/lib/mongo/{util → utils}/server_version.rb +15 -0
  44. data/lib/mongo/{util → utils}/support.rb +22 -55
  45. data/lib/mongo/utils/thread_local_variable_manager.rb +25 -0
  46. data/lib/mongo/utils.rb +19 -0
  47. data/lib/mongo.rb +44 -26
  48. data/mongo.gemspec +2 -2
  49. data/test/functional/authentication_test.rb +31 -10
  50. data/test/functional/bulk_api_stress_test.rb +133 -0
  51. data/test/functional/bulk_write_collection_view_test.rb +1198 -0
  52. data/test/functional/client_test.rb +627 -0
  53. data/test/functional/collection_test.rb +1419 -654
  54. data/test/functional/collection_writer_test.rb +83 -0
  55. data/test/functional/conversions_test.rb +46 -2
  56. data/test/functional/cursor_fail_test.rb +17 -9
  57. data/test/functional/cursor_message_test.rb +28 -15
  58. data/test/functional/cursor_test.rb +300 -165
  59. data/test/functional/db_api_test.rb +294 -264
  60. data/test/functional/db_connection_test.rb +15 -3
  61. data/test/functional/db_test.rb +165 -99
  62. data/test/functional/grid_file_system_test.rb +124 -112
  63. data/test/functional/grid_io_test.rb +17 -3
  64. data/test/functional/grid_test.rb +16 -2
  65. data/test/functional/pool_test.rb +99 -10
  66. data/test/functional/safe_test.rb +18 -4
  67. data/test/functional/ssl_test.rb +29 -0
  68. data/test/functional/support_test.rb +14 -0
  69. data/test/functional/timeout_test.rb +27 -27
  70. data/test/functional/uri_test.rb +268 -22
  71. data/test/functional/write_concern_test.rb +19 -5
  72. data/test/helpers/general.rb +50 -0
  73. data/test/helpers/test_unit.rb +476 -0
  74. data/test/replica_set/authentication_test.rb +28 -11
  75. data/test/replica_set/basic_test.rb +79 -23
  76. data/test/replica_set/client_test.rb +253 -124
  77. data/test/replica_set/connection_test.rb +59 -37
  78. data/test/replica_set/count_test.rb +18 -2
  79. data/test/replica_set/cursor_test.rb +30 -8
  80. data/test/replica_set/insert_test.rb +109 -2
  81. data/test/replica_set/max_values_test.rb +85 -10
  82. data/test/replica_set/pinning_test.rb +66 -2
  83. data/test/replica_set/query_test.rb +17 -3
  84. data/test/replica_set/read_preference_test.rb +115 -96
  85. data/test/replica_set/refresh_test.rb +59 -9
  86. data/test/replica_set/replication_ack_test.rb +32 -11
  87. data/test/replica_set/ssl_test.rb +32 -0
  88. data/test/sharded_cluster/basic_test.rb +73 -25
  89. data/test/shared/authentication/basic_auth_shared.rb +260 -0
  90. data/test/shared/authentication/bulk_api_auth_shared.rb +249 -0
  91. data/test/shared/authentication/gssapi_shared.rb +176 -0
  92. data/test/shared/authentication/sasl_plain_shared.rb +96 -0
  93. data/test/shared/authentication/scram_shared.rb +92 -0
  94. data/test/shared/ssl_shared.rb +235 -0
  95. data/test/test_helper.rb +47 -196
  96. data/test/threading/basic_test.rb +42 -2
  97. data/test/tools/mongo_config.rb +175 -35
  98. data/test/tools/mongo_config_test.rb +15 -1
  99. data/test/unit/client_test.rb +186 -57
  100. data/test/unit/collection_test.rb +44 -54
  101. data/test/unit/connection_test.rb +160 -71
  102. data/test/unit/cursor_test.rb +37 -3
  103. data/test/unit/db_test.rb +38 -14
  104. data/test/unit/grid_test.rb +15 -1
  105. data/test/unit/mongo_sharded_client_test.rb +30 -14
  106. data/test/unit/node_test.rb +16 -1
  107. data/test/unit/pool_manager_test.rb +21 -4
  108. data/test/unit/read_pref_test.rb +386 -1
  109. data/test/unit/read_test.rb +27 -13
  110. data/test/unit/safe_test.rb +22 -8
  111. data/test/unit/sharding_pool_manager_test.rb +25 -4
  112. data/test/unit/write_concern_test.rb +23 -9
  113. data.tar.gz.sig +0 -0
  114. metadata +80 -54
  115. metadata.gz.sig +0 -0
  116. data/lib/mongo/exceptions.rb +0 -65
  117. data/lib/mongo/util/read_preference.rb +0 -112
  118. data/lib/mongo/util/socket_util.rb +0 -20
  119. data/lib/mongo/util/ssl_socket.rb +0 -51
  120. data/lib/mongo/util/tcp_socket.rb +0 -62
  121. data/lib/mongo/util/thread_local_variable_manager.rb +0 -11
  122. data/lib/mongo/util/unix_socket.rb +0 -23
  123. data/lib/mongo/util/uri_parser.rb +0 -337
  124. data/test/functional/connection_test.rb +0 -449
  125. data/test/functional/threading_test.rb +0 -95
  126. data/test/replica_set/complex_connect_test.rb +0 -64
  127. data/test/shared/authentication.rb +0 -66
  128. data/test/unit/pool_test.rb +0 -9
  129. data/test/unit/util_test.rb +0 -55
@@ -0,0 +1,476 @@
1
+ # Copyright (C) 2009-2013 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
+ TEST_HOST = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost' unless defined? TEST_HOST
16
+ TEST_DATA = File.join(File.dirname(__FILE__), 'fixtures/data')
17
+ TEST_OP_TIMEOUT = 40
18
+ TEST_BASE = Test::Unit::TestCase
19
+
20
+ unless defined? TEST_PORT
21
+ TEST_PORT = if ENV['MONGO_RUBY_DRIVER_PORT']
22
+ ENV['MONGO_RUBY_DRIVER_PORT'].to_i
23
+ else
24
+ Mongo::MongoClient::DEFAULT_PORT
25
+ end
26
+ end
27
+
28
+ class Test::Unit::TestCase
29
+ include Mongo
30
+ include BSON
31
+
32
+ # Handles creating a pre-defined MongoDB cluster for integration testing.
33
+ #
34
+ # @param kind=nil [Symbol] Type of cluster (:rs or :sc).
35
+ # @param opts={} [Hash] Options to be passed through to the cluster manager.
36
+ #
37
+ # @return [ClusterManager] The cluster manager instance being used.
38
+ def ensure_cluster(kind=nil, opts={})
39
+ cluster_instance = nil
40
+ class_vars = TEST_BASE.class_eval { class_variables }
41
+ if class_vars.include?("@@cluster_#{kind}") || class_vars.include?("@@cluster_#{kind}".to_sym)
42
+ cluster_instance = TEST_BASE.class_eval { class_variable_get("@@cluster_#{kind}") }
43
+ end
44
+
45
+ unless cluster_instance
46
+ if kind == :rs
47
+ cluster_opts = Config::DEFAULT_REPLICA_SET.dup
48
+ else
49
+ cluster_opts = Config::DEFAULT_SHARDED_SIMPLE.dup
50
+ end
51
+
52
+ cluster_opts.merge!(opts)
53
+ cluster_opts.merge!(:dbpath => ENV['MONGO_DBPATH'] || 'data')
54
+ config = Config.cluster(cluster_opts)
55
+
56
+ cluster_instance = Config::ClusterManager.new(config)
57
+ TEST_BASE.class_eval { class_variable_set("@@cluster_#{kind}", cluster_instance) }
58
+ end
59
+
60
+ cluster_instance.start
61
+ instance_variable_set("@#{kind}", cluster_instance)
62
+
63
+ uri = "mongodb://#{TEST_USER}:#{TEST_USER_PWD}@" +
64
+ "#{cluster_instance.members_uri}"
65
+ uri += "?replicaset=#{@rs.repl_set_name}&sockettimeoutms=60000" if cluster_instance.replica_set?
66
+ instance_variable_set("@uri", uri)
67
+ end
68
+
69
+ # Generic helper to rescue and retry from a connection failure.
70
+ #
71
+ # @param max_retries=30 [Integer] The number of times to attempt a retry.
72
+ #
73
+ # @return [Object] The block result.
74
+ def rescue_connection_failure(max_retries=30)
75
+ retries = 0
76
+ begin
77
+ yield
78
+ rescue Mongo::ConnectionFailure => ex
79
+ retries += 1
80
+ raise ex if retries > max_retries
81
+ sleep(2)
82
+ retry
83
+ end
84
+ end
85
+
86
+ # Creates and connects a standard, pre-defined MongoClient instance.
87
+ #
88
+ # @param options={} [Hash] Options to be passed to the client instance.
89
+ # @param legacy=false [Boolean] When true, uses deprecated Mongo::Connection.
90
+ #
91
+ # @return [MongoClient] The client instance.
92
+ def self.standard_connection(options={}, legacy=false)
93
+ opts = options[:op_timeout] ? options : options.merge(:op_timeout => TEST_OP_TIMEOUT)
94
+ if legacy
95
+ silently do
96
+ # We have to create the Connection object directly here instead of using TEST_URI
97
+ # because Connection#from_uri ends up creating a MongoClient object.
98
+ conn = Connection.new(TEST_HOST, TEST_PORT, opts)
99
+ conn[TEST_DB].authenticate(TEST_USER, TEST_USER_PWD)
100
+ conn
101
+ end
102
+ else
103
+ MongoClient.from_uri(TEST_URI, opts)
104
+ end
105
+ end
106
+
107
+ # Creates and connects a standard, pre-defined MongoClient instance.
108
+ #
109
+ # @param options={} [Hash] Options to be passed to the client instance.
110
+ # @param legacy=false [Boolean] When true, uses deprecated Mongo::Connection.
111
+ #
112
+ # @return [MongoClient] The client instance.
113
+ def standard_connection(options={}, legacy=false)
114
+ self.class.standard_connection(options, legacy)
115
+ end
116
+
117
+ def self.host_port
118
+ "#{mongo_host}:#{mongo_port}"
119
+ end
120
+
121
+ def self.mongo_host
122
+ TEST_HOST
123
+ end
124
+
125
+ def self.mongo_port
126
+ TEST_PORT
127
+ end
128
+
129
+ def host_port
130
+ self.class.host_port
131
+ end
132
+
133
+ def mongo_host
134
+ self.class.mongo_host
135
+ end
136
+
137
+ def mongo_port
138
+ self.class.mongo_port
139
+ end
140
+
141
+ def method_name
142
+ caller[0]=~/`(.*?)'/
143
+ $1
144
+ end
145
+
146
+ def perform_step_down(member)
147
+ start = Time.now
148
+ timeout = 20 # seconds
149
+ begin
150
+ step_down_command = BSON::OrderedHash.new
151
+ step_down_command[:replSetStepDown] = 30
152
+ step_down_command[:force] = true
153
+ member['admin'].command(step_down_command)
154
+ rescue Mongo::OperationFailure => e
155
+ retry unless (Time.now - start) > timeout
156
+ raise e
157
+ end
158
+ end
159
+
160
+ def new_mock_socket(host='localhost', port=27017)
161
+ socket = Object.new
162
+ socket.stubs(:setsockopt).with(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
163
+ socket.stubs(:close)
164
+ socket.stubs(:closed?)
165
+ socket.stubs(:checkin)
166
+ socket.stubs(:pool)
167
+ socket.stubs(:pid)
168
+ socket
169
+ end
170
+
171
+ def new_mock_unix_socket(sockfile='/tmp/mongod.sock')
172
+ socket = Object.new
173
+ socket.stubs(:setsockopt).with(Socket::IPPROTO_TCP)
174
+ socket.stubs(:close)
175
+ socket.stubs(:closed?)
176
+ socket
177
+ end
178
+
179
+ def new_mock_db
180
+ Object.new
181
+ end
182
+
183
+ def mock_pool(tags={}, ping_time=15)
184
+ mock('pool').tap do |pool|
185
+ pool.stubs(:tags).returns(tags)
186
+ pool.stubs(:ping_time).returns(ping_time)
187
+ end
188
+ end
189
+
190
+ def assert_raise_error(klass, message=nil)
191
+ begin
192
+ yield
193
+ rescue => e
194
+ if klass.to_s != e.class.to_s
195
+ flunk "Expected exception class #{klass} but got #{e.class}.\n #{e.backtrace}"
196
+ end
197
+
198
+ if message && !e.message.include?(message)
199
+ p e.backtrace
200
+ flunk "#{e.message} does not include #{message}.\n#{e.backtrace}"
201
+ end
202
+ else
203
+ flunk "Expected assertion #{klass} but none was raised."
204
+ end
205
+ end
206
+
207
+ def match_document(key, expected, actual) # special cases for Regexp match, BSON::ObjectId, Range
208
+ if expected.is_a?(Hash) && actual.is_a?(Hash)
209
+ expected_keys = expected.keys.sort
210
+ actual_keys = actual.keys.sort
211
+ #currently allow extra fields in actual as the following check for equality of keys is commented out
212
+ #raise "field:#{key.inspect} - Hash keys expected:#{expected_keys.inspect} actual:#{actual_keys.inspect}" if expected_keys != actual_keys
213
+ expected_keys.each{|k| match_document(k, expected[k], actual[k])}
214
+ elsif expected.is_a?(Array) && actual.is_a?(Array)
215
+ raise "field:#{key.inspect} - Array size expected:#{expected.size} actual:#{actual.size}" if expected.size != actual.size
216
+ (0...expected.size).each{|i| match_document(i, expected[i], actual[i])}
217
+ elsif expected.is_a?(Regexp) && actual.is_a?(String)
218
+ raise "field:#{key.inspect} - Regexp expected:#{expected.inspect} actual:#{actual.inspect}" if expected !~ actual
219
+ elsif expected.is_a?(BSON::ObjectId) && actual.is_a?(BSON::ObjectId)
220
+ # match type but not value
221
+ elsif expected.is_a?(Range)
222
+ raise "field:#{key.inspect} - Range expected:#{expected.inspect} actual:#{actual.inspect}" if !expected.include?(actual)
223
+ elsif expected.is_a?(Set)
224
+ raise "field:#{key.inspect} - Set expected:#{expected.inspect} actual:#{actual.inspect}" if !expected.include?(actual)
225
+ else
226
+ raise "field:#{key.inspect} - expected:#{expected.inspect} actual:#{actual.inspect}" if expected != actual
227
+ end
228
+ true
229
+ end
230
+
231
+ def assert_match_document(expected, actual, message = '')
232
+ match = begin
233
+ match_document('', expected, actual)
234
+ rescue => ex
235
+ message = ex.message + ' - ' + message
236
+ false
237
+ end
238
+ assert(match, message)
239
+ end
240
+
241
+ def with_forced_timeout(client, &block)
242
+ authenticate_client(client)
243
+ cmd_line_args = client['admin'].command({ :getCmdLineOpts => 1 })['argv']
244
+ if cmd_line_args.include?('enableTestCommands=1') && client.server_version >= "2.5.3"
245
+ begin
246
+ #Force any query or command with valid non-zero max time to fail (SERVER-10650)
247
+ fail_point_cmd = OrderedHash.new
248
+ fail_point_cmd[:configureFailPoint] = 'maxTimeAlwaysTimeOut'
249
+ fail_point_cmd[:mode] = 'alwaysOn'
250
+ client['admin'].command(fail_point_cmd)
251
+ yield
252
+ fail_point_cmd[:mode] = 'off'
253
+ client['admin'].command(fail_point_cmd)
254
+ end
255
+ end
256
+ end
257
+
258
+ def with_default_journaling(client, &block)
259
+ authenticate_client(client)
260
+ cmd_line_args = client['admin'].command({ :getCmdLineOpts => 1 })['parsed']
261
+ unless client.server_version < "2.0" || cmd_line_args.include?('nojournal') ||
262
+ using_heap1_storage_engine?(cmd_line_args)
263
+ yield
264
+ end
265
+ end
266
+
267
+ def using_heap1_storage_engine?(cmd_line_args)
268
+ cmd_line_args.include?('storage') &&
269
+ cmd_line_args['storage']['engine'] == 'heap1'
270
+ end
271
+
272
+ def with_no_replication(client, &block)
273
+ if client.class == MongoClient
274
+ yield
275
+ end
276
+ end
277
+
278
+ def with_no_journaling(client, &block)
279
+ authenticate_client(client)
280
+ cmd_line_args = client['admin'].command({ :getCmdLineOpts => 1 })['parsed']
281
+ unless client.server_version < "2.0" || !cmd_line_args.include?('nojournal')
282
+ yield
283
+ end
284
+ end
285
+
286
+ def with_ipv6_enabled(client, &block)
287
+ authenticate_client(client)
288
+ cmd_line_args = client['admin'].command({ :getCmdLineOpts => 1 })['parsed']
289
+ if cmd_line_args.include?('ipv6')
290
+ yield
291
+ end
292
+ end
293
+
294
+ def with_write_commands(client, &block)
295
+ wire_version = Mongo::MongoClient::BATCH_COMMANDS
296
+ if client.primary_wire_version_feature?(wire_version)
297
+ yield wire_version
298
+ end
299
+ end
300
+
301
+ def with_preserved_env_uri(new_uri=nil, &block)
302
+ old_mongodb_uri = ENV['MONGODB_URI']
303
+ begin
304
+ ENV['MONGODB_URI'] = new_uri
305
+ yield
306
+ ensure
307
+ ENV['MONGODB_URI'] = old_mongodb_uri
308
+ end
309
+ end
310
+
311
+ def with_write_operations(client, &block)
312
+ wire_version = Mongo::MongoClient::RELEASE_2_4_AND_BEFORE
313
+ if client.primary_wire_version_feature?(wire_version)
314
+ client.class.class_eval(%Q{
315
+ alias :old_use_write_command? :use_write_command?
316
+ def use_write_command?(write_concern)
317
+ false
318
+ end
319
+ })
320
+ yield wire_version
321
+ client.class.class_eval(%Q{
322
+ alias :use_write_command? :old_use_write_command?
323
+ })
324
+ end
325
+ end
326
+
327
+ def with_write_commands_and_operations(client, &block)
328
+ with_write_commands(client, &block)
329
+ with_write_operations(client, &block)
330
+ end
331
+
332
+ def batch_commands?(wire_version)
333
+ wire_version >= Mongo::MongoClient::BATCH_COMMANDS
334
+ end
335
+
336
+ def subject_to_server_4754?(client)
337
+ # Until SERVER-4754 is resolved, profiling info is not collected
338
+ # when mongod is started with --auth in versions < 2.2
339
+ authenticate_client(client)
340
+ cmd_line_args = client['admin'].command({ :getCmdLineOpts => 1 })['parsed']
341
+ client.server_version < '2.2' && cmd_line_args.include?('auth')
342
+ end
343
+
344
+ # When testing under narrowed localhost exception, the admin user must have
345
+ # special permissions to run the db_eval command.
346
+ def grant_admin_user_eval_role(client)
347
+ if auth_enabled?(client) && client.server_version >= "2.6"
348
+ # we need to have anyAction on anyResource to run db_eval()
349
+ admin = client['admin']
350
+ any_priv = BSON::OrderedHash.new
351
+ any_priv[:resource] = { :anyResource => true }
352
+ any_priv[:actions] = ['anyAction']
353
+
354
+ create_role = BSON::OrderedHash.new
355
+ create_role[:createRole] = 'db_eval'
356
+ create_role[:privileges] = [any_priv]
357
+ create_role[:roles] = []
358
+
359
+ begin
360
+ admin.command(create_role)
361
+ rescue Mongo::OperationFailure => ex
362
+ # role already exists
363
+ end
364
+
365
+ grant_role = BSON::OrderedHash.new
366
+ grant_role[:grantRolesToUser] = TEST_USER
367
+ grant_role[:roles] = ['db_eval']
368
+ admin.command(grant_role)
369
+ end
370
+ end
371
+
372
+ # Return true if auth is enabled, false otherwise.
373
+ def auth_enabled?(client)
374
+ begin
375
+ cmd_line_args = client['admin'].command({ :getCmdLineOpts => 1 })['parsed']
376
+ return true if cmd_line_args.include?('auth') || cmd_line_args.include?('keyFile')
377
+ if security = cmd_line_args["security"]
378
+ return true if security["authorization"] == "enabled"
379
+ end
380
+ rescue OperationFailure => ex
381
+ # under narrowed localhost exception in > 2.7.1, getCmdLineOpts is not allowed
382
+ # unless you're authenticated.
383
+ return true if ex.message.include?("authorized") ||
384
+ (client.server_version >= "2.7.1" &&
385
+ ex.error_code == Mongo::ErrorCode::UNAUTHORIZED)
386
+ end
387
+ end
388
+
389
+ def with_auth(client, &block)
390
+ yield if auth_enabled?(client)
391
+ end
392
+
393
+ def authenticate_client(client)
394
+ client[TEST_DB].authenticate(TEST_USER, TEST_USER_PWD) unless client.auths.any? {|a| a[:source] == TEST_DB}
395
+ client
396
+ end
397
+
398
+ def self.ensure_admin_user
399
+ 10.times do
400
+ begin
401
+ client = Mongo::MongoClient.new(TEST_HOST, TEST_PORT)
402
+ db = client[TEST_DB]
403
+ begin
404
+ db.authenticate(TEST_USER, TEST_USER_PWD, nil, 'admin')
405
+ rescue Mongo::AuthenticationError => ex
406
+ roles = [ 'dbAdminAnyDatabase',
407
+ 'userAdminAnyDatabase',
408
+ 'readWriteAnyDatabase',
409
+ 'clusterAdmin' ]
410
+ db.add_user(TEST_USER, TEST_USER_PWD, nil, :roles => roles)
411
+ end
412
+ TEST_BASE.class_eval { class_variable_set("@@connected_single_mongod", true) }
413
+ break
414
+ rescue Mongo::ConnectionFailure
415
+ # mongod not available yet, wait a second and try again
416
+ sleep(1)
417
+ end
418
+ #puts "Not connected to a MongoD" unless client.connected?
419
+ end
420
+ end
421
+
422
+ def self.cleanup_users_and_dbs
423
+ not_cluster = TEST_BASE.class_eval { class_variables }.none? { |v| v =~ /@@cluster_/ }
424
+
425
+ if @@connected_single_mongod && not_cluster
426
+ client = Mongo::MongoClient.from_uri(TEST_URI, :op_timeout => TEST_OP_TIMEOUT)
427
+ db = client[TEST_DB]
428
+ begin
429
+ begin
430
+ db.authenticate(TEST_USER, TEST_USER_PWD)
431
+
432
+ rescue Mongo::ConnectionFailure, Mongo::MongoArgumentError
433
+ rescue Mongo::AuthenticationError
434
+ Test::Unit::TestCase.ensure_admin_user
435
+ db.authenticate(TEST_USER, TEST_USER_PWD)
436
+ end
437
+
438
+ client.database_names.each do |db_name|
439
+ if db_name =~ /^ruby_test*/
440
+ puts "[CLEAN-UP] Dropping '#{db_name}'..."
441
+ client.drop_database(db_name)
442
+ end
443
+ end
444
+
445
+ if client.server_version < '2.5'
446
+ db['system.users'].remove
447
+ else
448
+ db.command(:dropAllUsersFromDatabase => 1)
449
+ end
450
+
451
+ rescue Mongo::ConnectionFailure
452
+ # Nothing we can do about the mongod not being available
453
+ end
454
+ end
455
+ end
456
+ end
457
+
458
+
459
+ Test::Unit.at_start do
460
+ TEST_DB = ENV['TEST_DB'] || 'admin'
461
+ TEST_USER = ENV['TEST_USER'] || 'admin_user'
462
+ TEST_USER_PWD = ENV['TEST_USER_PWD'] || 'password'
463
+ TEST_URI = ENV['TEST_URI'] ||
464
+ "mongodb://#{TEST_USER}:#{TEST_USER_PWD}@#{TEST_HOST}:#{TEST_PORT}/#{TEST_DB}"
465
+ TEST_BASE.class_eval { class_variable_set("@@connected_single_mongod", false) }
466
+ Test::Unit::TestCase.ensure_admin_user
467
+ end
468
+
469
+ # Before and after hooks for the entire test run
470
+ # handles mop up after the cluster manager is done.
471
+ Test::Unit.at_exit do
472
+ Test::Unit::TestCase.cleanup_users_and_dbs
473
+ TEST_BASE.class_eval { class_variables }.select { |v| v =~ /@@cluster_/ }.each do |cluster|
474
+ TEST_BASE.class_eval { class_variable_get(cluster) }.stop
475
+ end
476
+ end
@@ -1,20 +1,37 @@
1
+ # Copyright (C) 2009-2013 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
+
1
15
  require 'test_helper'
2
- require 'shared/authentication'
16
+ require 'shared/authentication/basic_auth_shared'
17
+ require 'shared/authentication/sasl_plain_shared'
18
+ require 'shared/authentication/bulk_api_auth_shared'
19
+ require 'shared/authentication/gssapi_shared'
3
20
 
4
21
  class ReplicaSetAuthenticationTest < Test::Unit::TestCase
5
22
  include Mongo
6
- include AuthenticationTests
23
+
24
+ include BasicAuthTests
25
+ include SASLPlainTests
26
+ include BulkAPIAuthTests
27
+ include GSSAPITests
7
28
 
8
29
  def setup
9
30
  ensure_cluster(:rs)
10
- @client = MongoReplicaSetClient.new(@rs.repl_set_seeds, :name => @rs.repl_set_name, :connect_timeout => 60)
11
- @db = @client[MONGO_TEST_DB]
12
- init_auth
13
- end
14
-
15
- def test_authenticate_with_connection_uri
16
- @db.add_user('eunice', 'uritest')
17
- assert MongoReplicaSetClient.from_uri(
18
- "mongodb://eunice:uritest@#{@rs.repl_set_seeds.join(',')}/#{@db.name}?replicaSet=#{@rs.repl_set_name}")
31
+ @client = MongoReplicaSetClient.from_uri(@uri, :op_timeout => TEST_OP_TIMEOUT)
32
+ @admin = @client['admin']
33
+ @version = @client.server_version
34
+ @db = @client['ruby-test']
35
+ @host_info = @rs.repl_set_seeds.join(',')
19
36
  end
20
37
  end
@@ -1,13 +1,27 @@
1
+ # Copyright (C) 2009-2013 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
+
1
15
  require 'test_helper'
2
16
 
3
- class BasicTest < Test::Unit::TestCase
17
+ class ReplicaSetBasicTest < Test::Unit::TestCase
4
18
 
5
19
  def setup
6
20
  ensure_cluster(:rs)
7
21
  end
8
22
 
9
23
  def test_connect
10
- client = MongoReplicaSetClient.new(@rs.repl_set_seeds, :name => @rs.repl_set_name)
24
+ client = MongoReplicaSetClient.new(@rs.repl_set_seeds, :name => @rs.repl_set_name, :op_timeout => TEST_OP_TIMEOUT)
11
25
  assert client.connected?
12
26
  assert_equal @rs.primary_name, client.primary.join(':')
13
27
  assert_equal @rs.secondary_names.sort, client.secondaries.collect{|s| s.join(':')}.sort
@@ -59,9 +73,7 @@ class BasicTest < Test::Unit::TestCase
59
73
  end
60
74
 
61
75
  def test_accessors
62
- seeds = @rs.repl_set_seeds
63
- args = {:name => @rs.repl_set_name}
64
- client = MongoReplicaSetClient.new(seeds, args)
76
+ client = MongoReplicaSetClient.from_uri(@uri)
65
77
  assert_equal @rs.primary_name, [client.host, client.port].join(':')
66
78
  assert_equal client.host, client.primary_pool.host
67
79
  assert_equal client.port, client.primary_pool.port
@@ -74,30 +86,76 @@ class BasicTest < Test::Unit::TestCase
74
86
  client.close
75
87
  end
76
88
 
89
+ def test_write_commands_and_operations
90
+ @client = MongoReplicaSetClient.from_uri(@uri)
91
+ @coll = @client[TEST_DB]['test-write-commands-and-operations']
92
+ with_write_commands_and_operations(@client) do
93
+ @coll.remove
94
+ @coll.insert({:foo => "bar"})
95
+ assert_equal(1, @coll.count)
96
+ end
97
+ end
98
+
99
+ def test_wnote_does_not_raise_exception_with_err_nil
100
+ @client = MongoReplicaSetClient.from_uri(@uri)
101
+ if @client.server_version < '2.5.5'
102
+ @coll = @client[TEST_DB]['test-wnote']
103
+ begin
104
+ result = @coll.remove({:foo => 1}, :w => 2)
105
+ rescue => ex
106
+ assert(false, "should not raise an exception for a wnote response field from a remove that does not match any documents")
107
+ end
108
+ assert_nil result["err"]
109
+ assert_true result.has_key?("wnote")
110
+ end
111
+ end
112
+
113
+ def test_sockets_used_by_forked_process
114
+ @client = MongoReplicaSetClient.from_uri(@uri)
115
+ primary_node = @client.manager.primary_pool.node
116
+ primary_socket = primary_node.socket
117
+ primary_socket.instance_variable_set(:@pid, primary_socket.pid + 1)
118
+ primary_node.set_config
119
+ assert primary_socket != primary_node.socket
120
+ end
121
+
77
122
  context "Socket pools" do
78
123
  context "checking out writers" do
79
124
  setup do
80
- seeds = @rs.repl_set_seeds
81
- args = {:name => @rs.repl_set_name}
82
- @client = MongoReplicaSetClient.new(seeds, args)
83
- @coll = @client[MONGO_TEST_DB]['test-connection-exceptions']
125
+ @client = MongoReplicaSetClient.from_uri(@uri)
126
+ @coll = @client[TEST_DB]['test-connection-exceptions']
84
127
  end
85
128
 
86
129
  should "close the connection on send_message for major exceptions" do
87
- @client.expects(:checkout_writer).raises(SystemStackError)
88
- @client.expects(:close)
89
- begin
90
- @coll.insert({:foo => "bar"})
91
- rescue SystemStackError
130
+ with_write_operations(@client) do # explicit even if w 0 maps to write operations
131
+ @client.expects(:checkout_writer).raises(SystemStackError)
132
+ @client.expects(:close)
133
+ begin
134
+ @coll.insert({:foo => "bar"}, :w => 0)
135
+ rescue SystemStackError
136
+ end
137
+ end
138
+ end
139
+
140
+ should "close the connection on send_write_command for major exceptions" do
141
+ with_write_commands(@client) do
142
+ @client.expects(:checkout_reader).raises(SystemStackError)
143
+ @client.expects(:close)
144
+ begin
145
+ @coll.insert({:foo => "bar"})
146
+ rescue SystemStackError
147
+ end
92
148
  end
93
149
  end
94
150
 
95
151
  should "close the connection on send_message_with_gle for major exceptions" do
96
- @client.expects(:checkout_writer).raises(SystemStackError)
97
- @client.expects(:close)
98
- begin
99
- @coll.insert({:foo => "bar"})
100
- rescue SystemStackError
152
+ with_write_operations(@client) do
153
+ @client.expects(:checkout_writer).raises(SystemStackError)
154
+ @client.expects(:close)
155
+ begin
156
+ @coll.insert({:foo => "bar"})
157
+ rescue SystemStackError
158
+ end
101
159
  end
102
160
  end
103
161
 
@@ -113,10 +171,8 @@ class BasicTest < Test::Unit::TestCase
113
171
 
114
172
  context "checking out readers" do
115
173
  setup do
116
- seeds = @rs.repl_set_seeds
117
- args = {:name => @rs.repl_set_name}
118
- @client = MongoReplicaSetClient.new(seeds, args)
119
- @coll = @client[MONGO_TEST_DB]['test-connection-exceptions']
174
+ @client = MongoReplicaSetClient.from_uri(@uri)
175
+ @coll = @client[TEST_DB]['test-connection-exceptions']
120
176
  end
121
177
 
122
178
  should "close the connection on receive_message for major exceptions" do