mongo 1.10.0.rc0 → 1.10.0.rc1

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 (42) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/VERSION +1 -1
  5. data/lib/mongo/bulk_write_collection_view.rb +31 -3
  6. data/lib/mongo/collection.rb +69 -25
  7. data/lib/mongo/collection_writer.rb +3 -2
  8. data/lib/mongo/connection/node.rb +5 -0
  9. data/lib/mongo/cursor.rb +4 -1
  10. data/lib/mongo/db.rb +23 -41
  11. data/lib/mongo/functional.rb +2 -0
  12. data/lib/mongo/functional/authentication.rb +18 -3
  13. data/lib/mongo/functional/sasl_java.rb +48 -0
  14. data/lib/mongo/functional/uri_parser.rb +62 -50
  15. data/lib/mongo/mongo_client.rb +24 -9
  16. data/lib/mongo/mongo_replica_set_client.rb +16 -5
  17. data/lib/mongo/networking.rb +3 -3
  18. data/lib/mongo/utils/conversions.rb +2 -1
  19. data/test/functional/authentication_test.rb +6 -1
  20. data/test/functional/bulk_api_stress_test.rb +133 -0
  21. data/test/functional/bulk_write_collection_view_test.rb +573 -226
  22. data/test/functional/client_test.rb +3 -1
  23. data/test/functional/collection_test.rb +336 -17
  24. data/test/functional/conversions_test.rb +32 -0
  25. data/test/functional/cursor_test.rb +3 -3
  26. data/test/functional/db_api_test.rb +2 -2
  27. data/test/functional/db_test.rb +24 -0
  28. data/test/functional/uri_test.rb +49 -32
  29. data/test/helpers/test_unit.rb +8 -0
  30. data/test/replica_set/authentication_test.rb +5 -1
  31. data/test/replica_set/client_test.rb +5 -4
  32. data/test/replica_set/max_values_test.rb +6 -0
  33. data/test/shared/authentication/basic_auth_shared.rb +101 -30
  34. data/test/shared/authentication/bulk_api_auth_shared.rb +259 -0
  35. data/test/shared/authentication/gssapi_shared.rb +164 -0
  36. data/test/shared/ssl_shared.rb +49 -27
  37. data/test/unit/client_test.rb +4 -2
  38. data/test/unit/connection_test.rb +4 -2
  39. data/test/unit/cursor_test.rb +12 -0
  40. data/test/unit/db_test.rb +6 -0
  41. metadata +27 -20
  42. metadata.gz.sig +0 -0
@@ -103,7 +103,7 @@ class CursorTest < Test::Unit::TestCase
103
103
  end
104
104
  end
105
105
 
106
- def test_server_op_timeout_error
106
+ def test_max_time_ms_error
107
107
  cursor = @@coll.find
108
108
  cursor.stubs(:send_initial_query).returns(true)
109
109
 
@@ -117,10 +117,10 @@ class CursorTest < Test::Unit::TestCase
117
117
  end
118
118
  end
119
119
 
120
- def test_server_op_timeout
120
+ def test_max_time_ms
121
121
  with_forced_timeout(@@connection) do
122
122
  assert_raise ExecutionTimeout do
123
- cursor = @@coll.find.server_op_timeout(100)
123
+ cursor = @@coll.find.max_time_ms(100)
124
124
  cursor.to_a
125
125
  end
126
126
  end
@@ -325,11 +325,11 @@ class DBAPITest < Test::Unit::TestCase
325
325
  @@db.strict = true
326
326
 
327
327
  begin
328
- coll = @@db.create_collection('foobar', :capped => true, :size => 1024)
328
+ coll = @@db.create_collection('foobar', :capped => true, :size => 4096)
329
329
  options = coll.options
330
330
  assert_equal 'foobar', options['create'] if @@client.server_version < '2.5.5'
331
331
  assert_equal true, options['capped']
332
- assert_equal 1024, options['size']
332
+ assert_equal 4096, options['size']
333
333
  rescue => ex
334
334
  @@db.drop_collection('foobar')
335
335
  fail "did not expect exception \"#{ex.inspect}\""
@@ -260,6 +260,30 @@ class DBTest < Test::Unit::TestCase
260
260
  @@db.eval(function, 'hello', :nolock => true)
261
261
  end
262
262
 
263
+ if @@version >= '2.5.3'
264
+ def test_default_admin_roles
265
+ # admin user
266
+ db = Mongo::MongoClient.new()['admin']
267
+ db.logout
268
+ silently { db.add_user('admin', 'pass') }
269
+ db.authenticate('admin', 'pass')
270
+ info = db.command(:usersInfo => 'admin')['users'].first
271
+ assert_equal 'root', info['roles'].first['role']
272
+
273
+ # read-only admin user
274
+ silently { db.add_user('ro-admin', 'pass', true) }
275
+ db.logout
276
+ db.authenticate('ro-admin', 'pass')
277
+ info = db.command(:usersInfo => 'ro-admin')['users'].first
278
+ assert_equal 'readAnyDatabase', info['roles'].first['role']
279
+ db.logout
280
+
281
+ db.authenticate('admin', 'pass')
282
+ db.command(:dropAllUsersFromDatabase => 1)
283
+ db.logout
284
+ end
285
+ end
286
+
263
287
  if @@version >= "1.3.5"
264
288
  def test_db_stats
265
289
  stats = @@db.stats
@@ -31,39 +31,39 @@ class URITest < Test::Unit::TestCase
31
31
  assert_equal 27018, parser.nodes[0][1]
32
32
  end
33
33
 
34
- def test_ipv6_format
35
- parser = Mongo::URIParser.new('mongodb://[::1]:27018')
36
- assert_equal 1, parser.nodes.length
37
- assert_equal '::1', parser.nodes[0][0]
38
- assert_equal 27018, parser.nodes[0][1]
39
-
40
- parser = Mongo::URIParser.new('mongodb://[::1]')
41
- assert_equal 1, parser.nodes.length
42
- assert_equal '::1', parser.nodes[0][0]
43
- end
34
+ def test_ipv6_format
35
+ parser = Mongo::URIParser.new('mongodb://[::1]:27018')
36
+ assert_equal 1, parser.nodes.length
37
+ assert_equal '::1', parser.nodes[0][0]
38
+ assert_equal 27018, parser.nodes[0][1]
44
39
 
45
- def test_ipv6_format_multi
46
- parser = Mongo::URIParser.new('mongodb://[::1]:27017,[::1]:27018')
47
- assert_equal 2, parser.nodes.length
48
- assert_equal '::1', parser.nodes[0][0]
49
- assert_equal 27017, parser.nodes[0][1]
50
- assert_equal '::1', parser.nodes[1][0]
51
- assert_equal 27018, parser.nodes[1][1]
52
-
53
- parser = Mongo::URIParser.new('mongodb://[::1]:27017,localhost:27018')
54
- assert_equal 2, parser.nodes.length
55
- assert_equal '::1', parser.nodes[0][0]
56
- assert_equal 27017, parser.nodes[0][1]
57
- assert_equal 'localhost', parser.nodes[1][0]
58
- assert_equal 27018, parser.nodes[1][1]
59
-
60
- parser = Mongo::URIParser.new('mongodb://localhost:27017,[::1]:27018')
61
- assert_equal 2, parser.nodes.length
62
- assert_equal 'localhost', parser.nodes[0][0]
63
- assert_equal 27017, parser.nodes[0][1]
64
- assert_equal '::1', parser.nodes[1][0]
65
- assert_equal 27018, parser.nodes[1][1]
66
- end
40
+ parser = Mongo::URIParser.new('mongodb://[::1]')
41
+ assert_equal 1, parser.nodes.length
42
+ assert_equal '::1', parser.nodes[0][0]
43
+ end
44
+
45
+ def test_ipv6_format_multi
46
+ parser = Mongo::URIParser.new('mongodb://[::1]:27017,[::1]:27018')
47
+ assert_equal 2, parser.nodes.length
48
+ assert_equal '::1', parser.nodes[0][0]
49
+ assert_equal 27017, parser.nodes[0][1]
50
+ assert_equal '::1', parser.nodes[1][0]
51
+ assert_equal 27018, parser.nodes[1][1]
52
+
53
+ parser = Mongo::URIParser.new('mongodb://[::1]:27017,localhost:27018')
54
+ assert_equal 2, parser.nodes.length
55
+ assert_equal '::1', parser.nodes[0][0]
56
+ assert_equal 27017, parser.nodes[0][1]
57
+ assert_equal 'localhost', parser.nodes[1][0]
58
+ assert_equal 27018, parser.nodes[1][1]
59
+
60
+ parser = Mongo::URIParser.new('mongodb://localhost:27017,[::1]:27018')
61
+ assert_equal 2, parser.nodes.length
62
+ assert_equal 'localhost', parser.nodes[0][0]
63
+ assert_equal 27017, parser.nodes[0][1]
64
+ assert_equal '::1', parser.nodes[1][0]
65
+ assert_equal 27018, parser.nodes[1][1]
66
+ end
67
67
 
68
68
  def test_multiple_uris
69
69
  parser = Mongo::URIParser.new('mongodb://a.example.com:27018,b.example.com')
@@ -310,4 +310,21 @@ end
310
310
  Mongo::URIParser.new("mongodb://user@localhost/some_db?authMechanism=PLAIN")
311
311
  end
312
312
  end
313
+
314
+ def test_gssapi
315
+ uri = "mongodb://foo%2Fbar%40example.net@localhost?authMechanism=GSSAPI;"
316
+ parser = Mongo::URIParser.new(uri)
317
+ assert_equal 'GSSAPI', parser.auths.first[:mechanism]
318
+ assert_equal 'foo/bar@example.net', parser.auths.first[:username]
319
+
320
+
321
+ uri = "mongodb://foo%2Fbar%40example.net@localhost?authMechanism=GSSAPI;" +
322
+ "gssapiServiceName=mongodb;canonicalizeHostName=true"
323
+ parser = Mongo::URIParser.new(uri)
324
+ assert_equal 'GSSAPI', parser.auths.first[:mechanism]
325
+ assert_equal 'foo/bar@example.net', parser.auths.first[:username]
326
+ assert_equal 'mongodb', parser.auths.first[:extra][:gssapi_service_name]
327
+ assert_equal true, parser.auths.first[:extra][:canonicalize_host_name]
328
+ end
329
+
313
330
  end
@@ -233,6 +233,11 @@ class Test::Unit::TestCase
233
233
  end
234
234
  end
235
235
 
236
+ def with_auth(client, &block)
237
+ cmd_line_args = client['admin'].command({ :getCmdLineOpts => 1 })['parsed']
238
+ yield if cmd_line_args.include?('auth')
239
+ end
240
+
236
241
  def with_default_journaling(client, &block)
237
242
  cmd_line_args = client['admin'].command({ :getCmdLineOpts => 1 })['parsed']
238
243
  unless client.server_version < "2.0" || cmd_line_args.include?('nojournal')
@@ -298,6 +303,9 @@ class Test::Unit::TestCase
298
303
  with_write_operations(client, &block)
299
304
  end
300
305
 
306
+ def batch_commands?(wire_version)
307
+ wire_version >= Mongo::MongoClient::BATCH_COMMANDS
308
+ end
301
309
  end
302
310
 
303
311
  # Before and after hooks for the entire test run
@@ -15,17 +15,21 @@
15
15
  require 'test_helper'
16
16
  require 'shared/authentication/basic_auth_shared'
17
17
  require 'shared/authentication/sasl_plain_shared'
18
+ require 'shared/authentication/bulk_api_auth_shared'
19
+ require 'shared/authentication/gssapi_shared'
18
20
 
19
21
  class ReplicaSetAuthenticationTest < Test::Unit::TestCase
20
22
  include Mongo
21
23
  include BasicAuthTests
22
24
  include SASLPlainTests
25
+ include BulkAPIAuthTests
26
+ include GSSAPITests
23
27
 
24
28
  def setup
25
29
  ensure_cluster(:rs)
26
30
  @client = MongoReplicaSetClient.new(@rs.repl_set_seeds)
31
+ @version = @client.server_version
27
32
  @db = @client[TEST_DB]
28
33
  @host_info = @rs.repl_set_seeds.join(',')
29
- init_auth
30
34
  end
31
35
  end
@@ -329,12 +329,13 @@ class ReplicaSetClientTest < Test::Unit::TestCase
329
329
  def test_find_and_modify_with_secondary_read_preference
330
330
  @client = MongoReplicaSetClient.new @rs.repl_set_seeds
331
331
  collection = @client[TEST_DB].collection('test', :read => :secondary)
332
- collection << { :a => 1, :processed => false}
332
+ id = BSON::ObjectId.new
333
+ collection << { :a => id, :processed => false }
333
334
 
334
335
  collection.find_and_modify(
335
- :query => {},
336
- :update => {"$set" => {:processed => true}}
336
+ :query => { 'a' => id },
337
+ :update => { "$set" => { :processed => true }}
337
338
  )
338
- assert_equal collection.find_one({}, :fields => {:_id => 0}, :read => :primary), {'a' => 1, 'processed' => true}
339
+ assert_equal true, collection.find_one({ 'a' => id }, :read => :primary)['processed']
339
340
  end
340
341
  end
@@ -135,5 +135,11 @@ class MaxValuesTest < Test::Unit::TestCase
135
135
  assert_true @client.use_write_command?({:w => 1})
136
136
  assert_false @client.use_write_command?({:w => 0})
137
137
  end
138
+
139
+ def test_max_write_batch_size
140
+ assert_equal Mongo::MongoClient::DEFAULT_MAX_WRITE_BATCH_SIZE, @client.max_write_batch_size
141
+ @client.local_manager.primary_pool.node.stubs(:max_write_batch_size).returns(999)
142
+ assert_equal 999, @client.max_write_batch_size
143
+ end
138
144
  end
139
145
 
@@ -14,7 +14,7 @@
14
14
 
15
15
  module BasicAuthTests
16
16
 
17
- def init_auth
17
+ def init_auth_basic
18
18
  # enable authentication by creating and logging in as admin user
19
19
  @admin = @client['admin']
20
20
  @admin.add_user('admin', 'password', nil, :roles => ['readAnyDatabase',
@@ -28,7 +28,7 @@ module BasicAuthTests
28
28
  @db.add_user('admin', 'cleanup', nil, :roles => [])
29
29
  end
30
30
 
31
- def teardown
31
+ def teardown_basic
32
32
  remove_all_users(@db, 'admin', 'cleanup')
33
33
  remove_all_users(@admin, 'admin', 'password') if has_auth?(@admin.name)
34
34
  end
@@ -48,15 +48,21 @@ module BasicAuthTests
48
48
  end
49
49
 
50
50
  def test_add_remove_user
51
+ init_auth_basic
52
+
51
53
  # add user
52
54
  silently { @db.add_user('bob','user') }
53
55
  assert @db.authenticate('bob', 'user')
54
56
 
55
57
  # remove user
56
58
  assert @db.remove_user('bob')
59
+
60
+ teardown_basic
57
61
  end
58
62
 
59
63
  def test_update_user
64
+ init_auth_basic
65
+
60
66
  # add user
61
67
  silently { @db.add_user('bob', 'user') }
62
68
  assert @db.authenticate('bob', 'user')
@@ -68,9 +74,13 @@ module BasicAuthTests
68
74
  @db.authenticate('bob', 'user')
69
75
  end
70
76
  assert @db.authenticate('bob', 'updated')
77
+
78
+ teardown_basic
71
79
  end
72
80
 
73
81
  def test_remove_non_existent_user
82
+ init_auth_basic
83
+
74
84
  if @client.server_version < '2.5'
75
85
  assert_equal false, @db.remove_user('joe')
76
86
  else
@@ -78,37 +88,49 @@ module BasicAuthTests
78
88
  assert @db.remove_user('joe')
79
89
  end
80
90
  end
91
+ teardown_basic
81
92
  end
82
93
 
83
94
  def test_authenticate
95
+ init_auth_basic
84
96
  silently { @db.add_user('peggy', 'user') }
85
97
  assert @db.authenticate('peggy', 'user')
86
98
  @db.remove_user('peggy')
99
+ teardown_basic
87
100
  end
88
101
 
89
102
  def test_authenticate_non_existent_user
103
+ init_auth_basic
90
104
  assert_raise Mongo::AuthenticationError do
91
105
  @db.authenticate('frank', 'thetank')
92
106
  end
107
+ teardown_basic
93
108
  end
94
109
 
95
110
  def test_logout
111
+ init_auth_basic
96
112
  silently { @db.add_user('peggy', 'user') }
97
113
  assert @db.authenticate('peggy', 'user')
98
114
  assert @db.logout
115
+ teardown_basic
99
116
  end
100
117
 
101
118
  def test_authenticate_with_special_characters
119
+ init_auth_basic
102
120
  silently { assert @db.add_user('foo:bar','@foo') }
103
121
  assert @db.authenticate('foo:bar','@foo')
122
+ teardown_basic
104
123
  end
105
124
 
106
125
  def test_authenticate_read_only
126
+ init_auth_basic
107
127
  silently { @db.add_user('randy', 'readonly', true) }
108
128
  assert @db.authenticate('randy', 'readonly')
129
+ teardown_basic
109
130
  end
110
131
 
111
132
  def test_authenticate_with_connection_uri
133
+ init_auth_basic
112
134
  silently { @db.add_user('eunice', 'uritest') }
113
135
 
114
136
  uri = "mongodb://eunice:uritest@#{@host_info}/#{@db.name}"
@@ -122,9 +144,11 @@ module BasicAuthTests
122
144
  assert_equal @db.name, auth[:db_name]
123
145
  assert_equal 'eunice', auth[:username]
124
146
  assert_equal 'uritest', auth[:password]
147
+ teardown_basic
125
148
  end
126
149
 
127
150
  def test_socket_auths
151
+ init_auth_basic
128
152
  # setup
129
153
  db_a = @client[TEST_DB + '_a']
130
154
  silently { db_a.add_user('user_a', 'password') }
@@ -156,47 +180,70 @@ module BasicAuthTests
156
180
  remove_all_users(db_a, 'user_a', 'password')
157
181
  remove_all_users(db_b, 'user_b', 'password')
158
182
  remove_all_users(db_c, 'user_c', 'password')
183
+ teardown_basic
184
+ end
185
+
186
+ def test_default_roles_non_admin
187
+ return unless @client.server_version >= '2.5.3'
188
+ init_auth_basic
189
+ silently { @db.add_user('user', 'pass') }
190
+ silently { @db.authenticate('user', 'pass') }
191
+ info = @db.command(:usersInfo => 'user')['users'].first
192
+ assert_equal 'dbOwner', info['roles'].first['role']
193
+
194
+ # read-only
195
+ silently { @db.add_user('ro-user', 'pass', true) }
196
+ @db.logout
197
+ @db.authenticate('ro-user', 'pass')
198
+ info = @db.command(:usersInfo => 'ro-user')['users'].first
199
+ assert_equal 'read', info['roles'].first['role']
200
+ @db.logout
201
+ teardown_basic
159
202
  end
160
203
 
161
204
  def test_delegated_authentication
162
205
  return unless @client.server_version >= '2.4' && @client.server_version < '2.5'
206
+ with_auth(@client) do
207
+ init_auth_basic
208
+ # create user in test databases
209
+ accounts = @client[TEST_DB + '_accounts']
210
+ silently do
211
+ accounts.add_user('debbie', 'delegate')
212
+ @db.add_user('debbie', nil, nil, :roles => ['read'], :userSource => accounts.name)
213
+ end
214
+ @admin.logout
163
215
 
164
- # create user in test databases
165
- accounts = @client[TEST_DB + '_accounts']
166
- silently do
167
- accounts.add_user('debbie', 'delegate')
168
- @db.add_user('debbie', nil, nil, :roles => ['read'], :userSource => accounts.name)
169
- end
170
- @admin.logout
216
+ # validate that direct authentication is not allowed
217
+ assert_raise Mongo::AuthenticationError do
218
+ @db.authenticate('debbie', 'delegate')
219
+ end
171
220
 
172
- # validate that direct authentication is not allowed
173
- assert_raise Mongo::AuthenticationError do
174
- @db.authenticate('debbie', 'delegate')
175
- end
221
+ # validate delegated authentication
222
+ assert accounts.authenticate('debbie', 'delegate')
223
+ assert @db.collection_names
224
+ accounts.logout
225
+ assert_raise Mongo::OperationFailure do
226
+ @db.collection_names
227
+ end
176
228
 
177
- # validate delegated authentication
178
- assert accounts.authenticate('debbie', 'delegate')
179
- assert @db.collection_names
180
- accounts.logout
181
- assert_raise Mongo::OperationFailure do
182
- @db.collection_names
183
- end
229
+ # validate auth using source database
230
+ @db.authenticate('debbie', 'delegate', nil, accounts.name)
231
+ assert @db.collection_names
232
+ accounts.logout
233
+ assert_raise Mongo::OperationFailure do
234
+ @db.collection_names
235
+ end
184
236
 
185
- # validate auth using source database
186
- @db.authenticate('debbie', 'delegate', nil, accounts.name)
187
- assert @db.collection_names
188
- accounts.logout
189
- assert_raise Mongo::OperationFailure do
190
- @db.collection_names
237
+ # clean-up
238
+ @admin.authenticate('admin', 'password')
239
+ remove_all_users(accounts, 'debbie', 'delegate')
240
+ teardown_basic
191
241
  end
192
-
193
- # clean-up
194
- @admin.authenticate('admin', 'password')
195
- remove_all_users(accounts, 'debbie', 'delegate')
196
242
  end
197
243
 
198
244
  def test_non_admin_default_roles
199
245
  return if @client.server_version < '2.5'
246
+ init_auth_basic
200
247
 
201
248
  # add read-only user and verify that role is 'read'
202
249
  @db.add_user('randy', 'password', nil, :roles => ['read'])
@@ -210,6 +257,30 @@ module BasicAuthTests
210
257
  @db.authenticate('emily', 'password')
211
258
  users = @db.command(:usersInfo => 'emily')['users']
212
259
  assert_equal 'dbOwner', users.first['roles'].first['role']
260
+ teardown_basic
261
+ end
262
+
263
+ def test_update_user_to_read_only
264
+ with_auth(@client) do
265
+ init_auth_basic
266
+ silently { @db.add_user('emily', 'password') }
267
+ @admin.logout
268
+ @db.authenticate('emily', 'password')
269
+ @db['test'].insert({})
270
+ @db.logout
271
+
272
+ @admin.authenticate('admin', 'password')
273
+ silently { @db.add_user('emily', 'password', true) }
274
+ @admin.logout
275
+
276
+ silently { @db.authenticate('emily', 'password') }
277
+ assert_raise Mongo::OperationFailure do
278
+ @db['test'].insert({})
279
+ end
280
+ @db.logout
281
+ @admin.authenticate('admin', 'password')
282
+ teardown_basic
283
+ end
213
284
  end
214
285
 
215
286
  end