mongo 1.9.2 → 1.10.0.rc0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/LICENSE +1 -1
  5. data/README.md +94 -334
  6. data/Rakefile +6 -4
  7. data/VERSION +1 -1
  8. data/bin/mongo_console +13 -6
  9. data/lib/mongo.rb +22 -27
  10. data/lib/mongo/bulk_write_collection_view.rb +352 -0
  11. data/lib/mongo/collection.rb +128 -188
  12. data/lib/mongo/collection_writer.rb +348 -0
  13. data/lib/mongo/connection.rb +19 -0
  14. data/lib/mongo/{util → connection}/node.rb +15 -1
  15. data/lib/mongo/{util → connection}/pool.rb +34 -19
  16. data/lib/mongo/{util → connection}/pool_manager.rb +8 -2
  17. data/lib/mongo/{util → connection}/sharding_pool_manager.rb +1 -1
  18. data/lib/mongo/connection/socket.rb +18 -0
  19. data/lib/mongo/{util → connection/socket}/socket_util.rb +5 -2
  20. data/lib/mongo/{util → connection/socket}/ssl_socket.rb +3 -4
  21. data/lib/mongo/{util → connection/socket}/tcp_socket.rb +25 -15
  22. data/lib/mongo/{util → connection/socket}/unix_socket.rb +6 -4
  23. data/lib/mongo/cursor.rb +113 -47
  24. data/lib/mongo/db.rb +203 -131
  25. data/lib/mongo/{exceptions.rb → exception.rb} +7 -1
  26. data/lib/mongo/functional.rb +19 -0
  27. data/lib/mongo/functional/authentication.rb +303 -0
  28. data/lib/mongo/{util → functional}/logging.rb +1 -1
  29. data/lib/mongo/{util → functional}/read_preference.rb +49 -1
  30. data/lib/mongo/{util → functional}/uri_parser.rb +81 -69
  31. data/lib/mongo/{util → functional}/write_concern.rb +2 -1
  32. data/{test/unit/pool_test.rb → lib/mongo/gridfs.rb} +5 -10
  33. data/lib/mongo/gridfs/grid.rb +1 -3
  34. data/lib/mongo/gridfs/grid_ext.rb +1 -1
  35. data/lib/mongo/gridfs/grid_file_system.rb +1 -1
  36. data/lib/mongo/gridfs/grid_io.rb +1 -1
  37. data/lib/mongo/legacy.rb +63 -8
  38. data/lib/mongo/mongo_client.rb +128 -154
  39. data/lib/mongo/mongo_replica_set_client.rb +17 -11
  40. data/lib/mongo/mongo_sharded_client.rb +2 -1
  41. data/lib/mongo/networking.rb +19 -10
  42. data/lib/mongo/utils.rb +19 -0
  43. data/lib/mongo/{util → utils}/conversions.rb +1 -1
  44. data/lib/mongo/{util → utils}/core_ext.rb +1 -1
  45. data/lib/mongo/{util → utils}/server_version.rb +1 -1
  46. data/lib/mongo/{util → utils}/support.rb +10 -57
  47. data/lib/mongo/{util → utils}/thread_local_variable_manager.rb +1 -1
  48. data/test/functional/authentication_test.rb +8 -21
  49. data/test/functional/bulk_write_collection_view_test.rb +782 -0
  50. data/test/functional/{connection_test.rb → client_test.rb} +153 -78
  51. data/test/functional/collection_test.rb +343 -97
  52. data/test/functional/collection_writer_test.rb +83 -0
  53. data/test/functional/conversions_test.rb +1 -3
  54. data/test/functional/cursor_fail_test.rb +3 -3
  55. data/test/functional/cursor_message_test.rb +3 -3
  56. data/test/functional/cursor_test.rb +38 -3
  57. data/test/functional/db_api_test.rb +5 -5
  58. data/test/functional/db_connection_test.rb +2 -2
  59. data/test/functional/db_test.rb +35 -11
  60. data/test/functional/grid_file_system_test.rb +2 -2
  61. data/test/functional/grid_io_test.rb +2 -2
  62. data/test/functional/grid_test.rb +2 -2
  63. data/test/functional/pool_test.rb +2 -3
  64. data/test/functional/safe_test.rb +5 -5
  65. data/test/functional/ssl_test.rb +22 -102
  66. data/test/functional/support_test.rb +1 -1
  67. data/test/functional/timeout_test.rb +6 -22
  68. data/test/functional/uri_test.rb +113 -12
  69. data/test/functional/write_concern_test.rb +6 -6
  70. data/test/helpers/general.rb +50 -0
  71. data/test/helpers/test_unit.rb +309 -0
  72. data/test/replica_set/authentication_test.rb +8 -23
  73. data/test/replica_set/basic_test.rb +41 -14
  74. data/test/replica_set/client_test.rb +179 -117
  75. data/test/replica_set/complex_connect_test.rb +6 -7
  76. data/test/replica_set/connection_test.rb +46 -38
  77. data/test/replica_set/count_test.rb +2 -2
  78. data/test/replica_set/cursor_test.rb +8 -8
  79. data/test/replica_set/insert_test.rb +64 -2
  80. data/test/replica_set/max_values_test.rb +59 -10
  81. data/test/replica_set/pinning_test.rb +2 -2
  82. data/test/replica_set/query_test.rb +2 -2
  83. data/test/replica_set/read_preference_test.rb +6 -6
  84. data/test/replica_set/refresh_test.rb +7 -7
  85. data/test/replica_set/replication_ack_test.rb +5 -5
  86. data/test/replica_set/ssl_test.rb +24 -106
  87. data/test/sharded_cluster/basic_test.rb +43 -15
  88. data/test/shared/authentication/basic_auth_shared.rb +215 -0
  89. data/test/shared/authentication/sasl_plain_shared.rb +96 -0
  90. data/test/shared/ssl_shared.rb +173 -0
  91. data/test/test_helper.rb +31 -199
  92. data/test/threading/basic_test.rb +29 -3
  93. data/test/tools/mongo_config.rb +45 -20
  94. data/test/tools/mongo_config_test.rb +1 -1
  95. data/test/unit/client_test.rb +136 -57
  96. data/test/unit/collection_test.rb +31 -55
  97. data/test/unit/connection_test.rb +135 -72
  98. data/test/unit/cursor_test.rb +2 -2
  99. data/test/unit/db_test.rb +19 -15
  100. data/test/unit/grid_test.rb +2 -2
  101. data/test/unit/mongo_sharded_client_test.rb +17 -15
  102. data/test/unit/node_test.rb +2 -2
  103. data/test/unit/pool_manager_test.rb +7 -5
  104. data/test/unit/read_pref_test.rb +82 -2
  105. data/test/unit/read_test.rb +14 -14
  106. data/test/unit/safe_test.rb +9 -9
  107. data/test/unit/sharding_pool_manager_test.rb +11 -5
  108. data/test/unit/write_concern_test.rb +9 -9
  109. metadata +71 -56
  110. metadata.gz.sig +0 -0
  111. data/test/functional/threading_test.rb +0 -109
  112. data/test/shared/authentication.rb +0 -121
  113. data/test/unit/util_test.rb +0 -69
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2013 10gen Inc.
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -14,10 +14,8 @@
14
14
 
15
15
  require 'test_helper'
16
16
  require 'logger'
17
- require 'stringio'
18
- require 'thread'
19
17
 
20
- class TestConnection < Test::Unit::TestCase
18
+ class ClientTest < Test::Unit::TestCase
21
19
 
22
20
  include Mongo
23
21
  include BSON
@@ -52,6 +50,30 @@ class TestConnection < Test::Unit::TestCase
52
50
  assert ping['ok']
53
51
  end
54
52
 
53
+ def test_ipv6
54
+ with_ipv6_enabled(@client) do
55
+ assert client = MongoClient.new('[::1]')
56
+ end
57
+ end
58
+
59
+ def test_ipv6_uri_no_opts
60
+ with_ipv6_enabled(@client) do
61
+ uri = 'mongodb://[::1]:27017'
62
+ with_preserved_env_uri(uri) do
63
+ assert MongoClient.new
64
+ end
65
+ end
66
+ end
67
+
68
+ def test_ipv6_uri_opts
69
+ with_ipv6_enabled(@client) do
70
+ uri = 'mongodb://[::1]:27017/?slaveOk=true'
71
+ with_preserved_env_uri(uri) do
72
+ assert MongoClient.new
73
+ end
74
+ end
75
+ end
76
+
55
77
  def test_connection_uri
56
78
  con = MongoClient.from_uri("mongodb://#{host_port}")
57
79
  assert_equal mongo_host, con.primary_pool.host
@@ -65,66 +87,49 @@ class TestConnection < Test::Unit::TestCase
65
87
  end
66
88
 
67
89
  def test_env_mongodb_uri
68
- begin
69
- old_mongodb_uri = ENV['MONGODB_URI']
70
- ENV['MONGODB_URI'] = "mongodb://#{host_port}"
90
+ uri = "mongodb://#{host_port}"
91
+ with_preserved_env_uri(uri) do
71
92
  con = MongoClient.new
72
93
  assert_equal mongo_host, con.primary_pool.host
73
94
  assert_equal mongo_port, con.primary_pool.port
74
- ensure
75
- ENV['MONGODB_URI'] = old_mongodb_uri
76
95
  end
77
96
  end
78
97
 
79
98
  def test_from_uri_implicit_mongodb_uri
80
- begin
81
- old_mongodb_uri = ENV['MONGODB_URI']
82
- ENV['MONGODB_URI'] = "mongodb://#{host_port}"
99
+ uri = "mongodb://#{host_port}"
100
+ with_preserved_env_uri(uri) do
83
101
  con = MongoClient.from_uri
84
102
  assert_equal mongo_host, con.primary_pool.host
85
103
  assert_equal mongo_port, con.primary_pool.port
86
- ensure
87
- ENV['MONGODB_URI'] = old_mongodb_uri
88
104
  end
89
105
  end
90
106
 
91
107
  def test_db_from_uri_exists_no_options
92
- begin
93
- db_name = "_database"
94
-
95
- old_mongodb_uri = ENV['MONGODB_URI']
96
- ENV['MONGODB_URI'] = "mongodb://#{host_port}/#{db_name}"
108
+ db_name = "_database"
109
+ uri = "mongodb://#{host_port}/#{db_name}"
110
+ with_preserved_env_uri(uri) do
97
111
  con = MongoClient.from_uri
98
112
  db = con.db
99
113
  assert_equal db.name, db_name
100
- ensure
101
- ENV['MONGODB_URI'] = old_mongodb_uri
102
114
  end
103
115
  end
104
116
 
105
117
  def test_db_from_uri_exists_options
106
- begin
107
- db_name = "_database"
108
-
109
- old_mongodb_uri = ENV['MONGODB_URI']
110
- ENV['MONGODB_URI'] = "mongodb://#{host_port}/#{db_name}?"
118
+ db_name = "_database"
119
+ uri = "mongodb://#{host_port}/#{db_name}?"
120
+ with_preserved_env_uri(uri) do
111
121
  con = MongoClient.from_uri
112
122
  db = con.db
113
123
  assert_equal db.name, db_name
114
- ensure
115
- ENV['MONGODB_URI'] = old_mongodb_uri
116
124
  end
117
125
  end
118
126
 
119
127
  def test_db_from_uri_exists_no_db_name
120
- begin
121
- old_mongodb_uri = ENV['MONGODB_URI']
122
- ENV['MONGODB_URI'] = "mongodb://#{host_port}/"
128
+ uri = "mongodb://#{host_port}/"
129
+ with_preserved_env_uri(uri) do
123
130
  con = MongoClient.from_uri
124
131
  db = con.db
125
132
  assert_equal db.name, MongoClient::DEFAULT_DB_NAME
126
- ensure
127
- ENV['MONGODB_URI'] = old_mongodb_uri
128
133
  end
129
134
  end
130
135
 
@@ -163,59 +168,47 @@ class TestConnection < Test::Unit::TestCase
163
168
  end
164
169
 
165
170
  def test_database_info
166
- @client.drop_database(MONGO_TEST_DB)
167
- @client.db(MONGO_TEST_DB).collection('info-test').insert('a' => 1)
171
+ @client.drop_database(TEST_DB)
172
+ @client.db(TEST_DB).collection('info-test').insert('a' => 1)
168
173
 
169
174
  info = @client.database_info
170
175
  assert_not_nil info
171
176
  assert_kind_of Hash, info
172
- assert_not_nil info[MONGO_TEST_DB]
173
- assert info[MONGO_TEST_DB] > 0
177
+ assert_not_nil info[TEST_DB]
178
+ assert info[TEST_DB] > 0
174
179
 
175
- @client.drop_database(MONGO_TEST_DB)
180
+ @client.drop_database(TEST_DB)
176
181
  end
177
182
 
178
183
  def test_copy_database
179
- @client.db('old').collection('copy-test').insert('a' => 1)
180
- @client.copy_database('old', 'new', host_port)
181
- old_object = @client.db('old').collection('copy-test').find.next_document
182
- new_object = @client.db('new').collection('copy-test').find.next_document
183
- assert_equal old_object, new_object
184
- @client.drop_database('old')
185
- @client.drop_database('new')
186
- end
187
-
188
- def test_copy_database_with_auth
189
- @client.db('old').collection('copy-test').insert('a' => 1)
190
- @client.db('old').add_user('bob', 'secret')
191
-
192
- assert_raise Mongo::OperationFailure do
193
- @client.copy_database('old', 'new', host_port, 'bob', 'badpassword')
194
- end
184
+ old_name = TEST_DB + '_old'
185
+ new_name = TEST_DB + '_new'
195
186
 
196
- result = @client.copy_database('old', 'new', host_port, 'bob', 'secret')
197
- assert Mongo::Support.ok?(result)
187
+ @client.drop_database(new_name)
188
+ @client.db(old_name).collection('copy-test').insert('a' => 1)
189
+ @client.copy_database(old_name, new_name, host_port)
198
190
 
199
- @client.drop_database('old')
200
- @client.drop_database('new')
191
+ old_object = @client.db(old_name).collection('copy-test').find.next_document
192
+ new_object = @client.db(new_name).collection('copy-test').find.next_document
193
+ assert_equal old_object, new_object
201
194
  end
202
195
 
203
196
  def test_database_names
204
- @client.drop_database(MONGO_TEST_DB)
205
- @client.db(MONGO_TEST_DB).collection('info-test').insert('a' => 1)
197
+ @client.drop_database(TEST_DB)
198
+ @client.db(TEST_DB).collection('info-test').insert('a' => 1)
206
199
 
207
200
  names = @client.database_names
208
201
  assert_not_nil names
209
202
  assert_kind_of Array, names
210
203
  assert names.length >= 1
211
- assert names.include?(MONGO_TEST_DB)
204
+ assert names.include?(TEST_DB)
212
205
  end
213
206
 
214
207
  def test_logging
215
208
  output = StringIO.new
216
209
  logger = Logger.new(output)
217
210
  logger.level = Logger::DEBUG
218
- standard_connection(:logger => logger).db(MONGO_TEST_DB)
211
+ standard_connection(:logger => logger).db(TEST_DB)
219
212
  assert output.string.include?("admin['$cmd'].find")
220
213
  end
221
214
 
@@ -223,7 +216,7 @@ class TestConnection < Test::Unit::TestCase
223
216
  output = StringIO.new
224
217
  logger = Logger.new(output)
225
218
  logger.level = Logger::DEBUG
226
- standard_connection(:logger => logger).db(MONGO_TEST_DB)
219
+ standard_connection(:logger => logger).db(TEST_DB)
227
220
  assert_match(/\(\d+.\d{1}ms\)/, output.string)
228
221
  assert output.string.include?("admin['$cmd'].find")
229
222
  end
@@ -240,15 +233,15 @@ class TestConnection < Test::Unit::TestCase
240
233
  end
241
234
 
242
235
  def test_drop_database
243
- db = @client.db('ruby-mongo-will-be-deleted')
236
+ db = @client.db(TEST_DB + '_drop_test')
244
237
  coll = db.collection('temp')
245
238
  coll.remove
246
239
  coll.insert(:name => 'temp')
247
240
  assert_equal 1, coll.count()
248
- assert @client.database_names.include?('ruby-mongo-will-be-deleted')
241
+ assert @client.database_names.include?(TEST_DB + '_drop_test')
249
242
 
250
- @client.drop_database('ruby-mongo-will-be-deleted')
251
- assert !@client.database_names.include?('ruby-mongo-will-be-deleted')
243
+ @client.drop_database(TEST_DB + '_drop_test')
244
+ assert !@client.database_names.include?(TEST_DB + '_drop_test')
252
245
  end
253
246
 
254
247
  def test_nodes
@@ -337,6 +330,66 @@ class TestConnection < Test::Unit::TestCase
337
330
  assert_equal Mongo::DEFAULT_MAX_BSON_SIZE * Mongo::MESSAGE_SIZE_FACTOR, conn.max_message_size
338
331
  end
339
332
 
333
+ def test_max_wire_version_and_min_wire_version_values
334
+ conn = standard_connection(:connect => false)
335
+
336
+ admin_db = Object.new
337
+ admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1, 'maxWireVersion' => 1, 'minWireVersion' => 1})
338
+ conn.expects(:[]).with('admin').returns(admin_db)
339
+ conn.connect
340
+
341
+ assert_equal 1, conn.max_wire_version
342
+ assert_equal 1, conn.min_wire_version
343
+ end
344
+
345
+ def test_max_wire_version_and_min_wire_version_values_with_no_reported_values
346
+ conn = standard_connection(:connect => false)
347
+
348
+ admin_db = Object.new
349
+ admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1})
350
+ conn.expects(:[]).with('admin').returns(admin_db)
351
+ conn.connect
352
+
353
+ assert_equal 0, conn.max_wire_version
354
+ assert_equal 0, conn.min_wire_version
355
+ end
356
+
357
+ def test_wire_version_feature
358
+ conn = standard_connection(:connect => false)
359
+ conn.stubs(:min_wire_version).returns(0)
360
+ conn.stubs(:max_wire_version).returns(1)
361
+ assert_true conn.wire_version_feature?(0)
362
+ assert_true conn.wire_version_feature?(1)
363
+ assert_false conn.wire_version_feature?(2)
364
+ assert_false conn.wire_version_feature?(-1)
365
+ end
366
+
367
+ def test_wire_version_not_in_range
368
+ [
369
+ [Mongo::MongoClient::MAX_WIRE_VERSION+1, Mongo::MongoClient::MAX_WIRE_VERSION+1],
370
+ [Mongo::MongoClient::MIN_WIRE_VERSION-1, Mongo::MongoClient::MIN_WIRE_VERSION-1]
371
+ ].each do |min_wire_version, max_wire_version|
372
+ conn = standard_connection(:connect => false)
373
+ admin_db = Object.new
374
+ admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1, 'maxWireVersion' => max_wire_version, 'minWireVersion' => min_wire_version})
375
+ conn.expects(:[]).with('admin').returns(admin_db)
376
+ assert_raises Mongo::ConnectionFailure do
377
+ conn.connect
378
+ end
379
+ end
380
+ end
381
+
382
+ def test_use_write_command
383
+ with_write_commands(@client) do
384
+ assert_true @client.use_write_command?({:w => 1})
385
+ assert_false @client.use_write_command?({:w => 0})
386
+ end
387
+ with_write_operations(@client) do
388
+ assert_false @client.use_write_command?({:w => 1})
389
+ assert_false @client.use_write_command?({:w => 0})
390
+ end
391
+ end
392
+
340
393
  def test_connection_activity
341
394
  conn = standard_connection
342
395
  assert conn.active?
@@ -361,22 +414,42 @@ class TestConnection < Test::Unit::TestCase
361
414
  context "Saved authentications" do
362
415
  setup do
363
416
  @client = standard_connection
364
- @auth = {:db_name => 'test', :username => 'bob', :password => 'secret', :source => nil}
365
- @client.add_auth(@auth[:db_name], @auth[:username], @auth[:password], @auth[:source])
417
+
418
+ @auth = {
419
+ :db_name => TEST_DB,
420
+ :username => 'bob',
421
+ :password => 'secret',
422
+ :source => TEST_DB,
423
+ :mechanism => 'MONGODB-CR'
424
+ }
425
+
426
+ @client.auths << @auth
366
427
  end
367
428
 
368
429
  teardown do
369
430
  @client.clear_auths
370
431
  end
371
432
 
372
- should "save the authentication" do
373
- assert_equal @auth, @client.auths[0]
433
+ should "save and validate the authentication" do
434
+ assert_equal Authentication.validate_credentials(@auth), @client.auths.first
374
435
  end
375
436
 
376
437
  should "not allow multiple authentications for the same db" do
377
- auth = {:db_name => 'test', :username => 'mickey', :password => 'm0u53', :source => nil}
438
+ auth = {
439
+ :db_name => TEST_DB,
440
+ :username => 'mickey',
441
+ :password => 'm0u53',
442
+ :source => nil,
443
+ :mechanism => nil
444
+ }
445
+
378
446
  assert_raise Mongo::MongoArgumentError do
379
- @client.add_auth(auth[:db_name], auth[:username], auth[:password], auth[:source])
447
+ @client.add_auth(
448
+ auth[:db_name],
449
+ auth[:username],
450
+ auth[:password],
451
+ auth[:source],
452
+ auth[:mechanism])
380
453
  end
381
454
  end
382
455
 
@@ -384,7 +457,7 @@ class TestConnection < Test::Unit::TestCase
384
457
  @client.remove_auth('non-existent database')
385
458
  assert_equal 1, @client.auths.length
386
459
 
387
- @client.remove_auth('test')
460
+ @client.remove_auth(TEST_DB)
388
461
  assert_equal 0, @client.auths.length
389
462
  end
390
463
 
@@ -398,11 +471,12 @@ class TestConnection < Test::Unit::TestCase
398
471
  context "checking out writers" do
399
472
  setup do
400
473
  @con = standard_connection(:pool_size => 10, :pool_timeout => 10)
401
- @coll = @con[MONGO_TEST_DB]['test-connection-exceptions']
474
+ @coll = @con[TEST_DB]['test-connection-exceptions']
402
475
  end
403
476
 
404
477
  should "close the connection on send_message for major exceptions" do
405
- @con.expects(:checkout_writer).raises(SystemStackError)
478
+ @con.stubs(:checkout_writer).raises(SystemStackError)
479
+ @con.stubs(:checkout_reader).raises(SystemStackError)
406
480
  @con.expects(:close)
407
481
  begin
408
482
  @coll.insert({:foo => "bar"})
@@ -411,7 +485,8 @@ class TestConnection < Test::Unit::TestCase
411
485
  end
412
486
 
413
487
  should "close the connection on send_message_with_gle for major exceptions" do
414
- @con.expects(:checkout_writer).raises(SystemStackError)
488
+ @con.stubs(:checkout_writer).raises(SystemStackError)
489
+ @con.stubs(:checkout_reader).raises(SystemStackError)
415
490
  @con.expects(:close)
416
491
  begin
417
492
  @coll.insert({:foo => "bar"}, :w => 1)
@@ -433,7 +508,7 @@ class TestConnection < Test::Unit::TestCase
433
508
  context "Connection exceptions" do
434
509
  setup do
435
510
  @con = standard_connection(:pool_size => 10, :pool_timeout => 10)
436
- @coll = @con[MONGO_TEST_DB]['test-connection-exceptions']
511
+ @coll = @con[TEST_DB]['test-connection-exceptions']
437
512
  end
438
513
 
439
514
  should "release connection if an exception is raised on send_message" do
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2013 10gen Inc.
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -15,16 +15,145 @@
15
15
  require 'rbconfig'
16
16
  require 'test_helper'
17
17
 
18
- class TestCollection < Test::Unit::TestCase
18
+ class CollectionTest < Test::Unit::TestCase
19
19
  @@client ||= standard_connection(:op_timeout => 10)
20
- @@db = @@client.db(MONGO_TEST_DB)
20
+ @@db = @@client.db(TEST_DB)
21
21
  @@test = @@db.collection("test")
22
22
  @@version = @@client.server_version
23
23
 
24
+ LIMITED_MAX_BSON_SIZE = 1024
25
+ LIMITED_MAX_MESSAGE_SIZE = 3 * LIMITED_MAX_BSON_SIZE
26
+ LIMITED_TEST_HEADROOM = 50
27
+ LIMITED_VALID_VALUE_SIZE = LIMITED_MAX_BSON_SIZE - LIMITED_TEST_HEADROOM
28
+ LIMITED_INVALID_VALUE_SIZE = LIMITED_MAX_BSON_SIZE + Mongo::MongoClient::COMMAND_HEADROOM + 1
29
+
24
30
  def setup
25
31
  @@test.remove
26
32
  end
27
33
 
34
+ @@wv0 = Mongo::MongoClient::RELEASE_2_4_AND_BEFORE
35
+ @@wv2 = Mongo::MongoClient::BATCH_COMMANDS
36
+ @@a_h = Mongo::MongoClient::APPEND_HEADROOM
37
+ @@s_h = Mongo::MongoClient::SERIALIZE_HEADROOM
38
+
39
+ MAX_SIZE_EXCEPTION_TEST = [
40
+ #[@@wv0, @@client.max_bson_size, nil, /xyzzy/], # succeeds standalone, fails whole suite
41
+ ]
42
+ MAX_SIZE_EXCEPTION_CRUBY_TEST = [
43
+ [@@wv0, @@client.max_bson_size + 1, BSON::InvalidDocument, /Document.* too large/]
44
+ ]
45
+ MAX_SIZE_EXCEPTION_JRUBY_TEST = [
46
+ [@@wv0, @@client.max_bson_size + 1, Mongo::OperationFailure, /object to insert too large/]
47
+ ]
48
+ MAX_SIZE_EXCEPTION_COMMANDS_TEST = [
49
+ #[@@wv2, @@client.max_bson_size, nil, /xyzzy/], # succeeds standalone, fails whole suite
50
+ [@@wv2, @@client.max_bson_size + 1, Mongo::OperationFailure, /object to insert too large/],
51
+ [@@wv2, @@client.max_bson_size + @@s_h, Mongo::OperationFailure, /object to insert too large/],
52
+ [@@wv2, @@client.max_bson_size + @@a_h, BSON::InvalidDocument, /Document.* too large/]
53
+ ]
54
+
55
+ @@max_size_exception_test = MAX_SIZE_EXCEPTION_TEST
56
+ @@max_size_exception_test += MAX_SIZE_EXCEPTION_CRUBY_TEST unless RUBY_PLATFORM == 'java'
57
+ #@@max_size_exception_test += MAX_SIZE_EXCEPTION_JRUBY_TEST if RUBY_PLATFORM == 'java'
58
+ @@max_size_exception_test += MAX_SIZE_EXCEPTION_COMMANDS_TEST if @@version >= "2.5.2"
59
+
60
+ def generate_sized_doc(size)
61
+ doc = {"_id" => BSON::ObjectId.new, "x" => "y"}
62
+ serialize_doc = BSON::BSON_CODER.serialize(doc, false, false, size)
63
+ doc = {"_id" => BSON::ObjectId.new, "x" => "y" * (1 + size - serialize_doc.size)}
64
+ assert_equal size, BSON::BSON_CODER.serialize(doc, false, false, size).size
65
+ doc
66
+ end
67
+
68
+ def with_max_wire_version(client, wire_version) # does not support replica sets
69
+ if client.wire_version_feature?(wire_version)
70
+ client.class.class_eval(%Q{
71
+ alias :old_max_wire_version :max_wire_version
72
+ def max_wire_version
73
+ #{wire_version}
74
+ end
75
+ })
76
+ yield wire_version
77
+ client.class.class_eval(%Q{
78
+ alias :max_wire_version :old_max_wire_version
79
+ })
80
+ end
81
+ end
82
+
83
+ def test_insert_batch_max_sizes
84
+ @@max_size_exception_test.each do |wire_version, size, exc, regexp|
85
+ with_max_wire_version(@@client, wire_version) do
86
+ @@test.remove
87
+ doc = generate_sized_doc(size)
88
+ begin
89
+ @@test.insert([doc.dup])
90
+ assert_equal nil, exc
91
+ rescue => e
92
+ assert_equal exc, e.class, "wire_version:#{wire_version}, size:#{size}, exc:#{exc} e:#{e.message.inspect} @@version:#{@@version}"
93
+ assert_match regexp, e.message
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ if @@version >= '2.5.1'
100
+ def test_aggregation_cursor
101
+ [10, 1000].each do |size|
102
+ @@test.drop
103
+ size.times {|i| @@test.insert({ :_id => i }) }
104
+ expected_sum = size.times.reduce(:+)
105
+
106
+ cursor = @@test.aggregate(
107
+ [{ :$project => {:_id => '$_id'}} ],
108
+ :cursor => {}
109
+ )
110
+
111
+ assert_equal Mongo::Cursor, cursor.class
112
+
113
+ cursor_sum = cursor.reduce(0) do |sum, doc|
114
+ sum += doc['_id']
115
+ end
116
+
117
+ assert_equal expected_sum, cursor_sum
118
+ end
119
+ @@test.drop
120
+ end
121
+
122
+ def test_aggregation_cursor_invalid_ops
123
+ cursor = @@test.aggregate([], :cursor => {})
124
+ assert_raise(Mongo::InvalidOperation) { cursor.rewind! }
125
+ assert_raise(Mongo::InvalidOperation) { cursor.explain }
126
+ assert_raise(Mongo::InvalidOperation) { cursor.count }
127
+ end
128
+ end
129
+
130
+ def test_aggregation_invalid_read_pref
131
+ assert_raise Mongo::MongoArgumentError do
132
+ @@test.aggregate([], :read => :invalid_read_pref)
133
+ end
134
+ end
135
+
136
+ if @@version >= '2.5.3'
137
+ def test_aggregation_allow_disk_usage
138
+ @@db.expects(:command).with do |selector, opts|
139
+ opts[:allowDiskUsage] == true
140
+ end.returns({ 'ok' => 1 })
141
+ @@test.aggregate([], :allowDiskUsage => true)
142
+ end
143
+
144
+ def test_aggregation_supports_explain
145
+ @@db.expects(:command).with do |selector, opts|
146
+ opts[:explain] == true
147
+ end.returns({ 'ok' => 1 })
148
+ @@test.aggregate([], :explain => true)
149
+ end
150
+
151
+ def test_aggregation_explain_returns_raw_result
152
+ response = @@test.aggregate([], :explain => true)
153
+ assert response['stages']
154
+ end
155
+ end
156
+
28
157
  def test_capped_method
29
158
  @@db.create_collection('normal')
30
159
  assert !@@db['normal'].capped?
@@ -43,7 +172,7 @@ class TestCollection < Test::Unit::TestCase
43
172
 
44
173
  # Create a db with a pk_factory.
45
174
  @db = MongoClient.new(ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
46
- ENV['MONGO_RUBY_DRIVER_PORT'] || MongoClient::DEFAULT_PORT).db(MONGO_TEST_DB, :pk => Object.new)
175
+ ENV['MONGO_RUBY_DRIVER_PORT'] || MongoClient::DEFAULT_PORT).db(TEST_DB, :pk => Object.new)
47
176
  @coll = @db.collection('coll-with-pk')
48
177
  assert @coll.pk_factory.is_a?(Object)
49
178
 
@@ -51,20 +180,19 @@ class TestCollection < Test::Unit::TestCase
51
180
  assert @coll.pk_factory.is_a?(Object)
52
181
  end
53
182
 
54
- class TestPK
183
+ class PKTest
55
184
  def self.create_pk
56
185
  end
57
186
  end
58
187
 
59
188
  def test_pk_factory_on_collection
60
189
  silently do
61
- @coll = Collection.new('foo', @@db, TestPK)
62
- assert_equal TestPK, @coll.pk_factory
190
+ @coll = Collection.new('foo', @@db, PKTest)
191
+ assert_equal PKTest, @coll.pk_factory
63
192
  end
64
193
 
65
-
66
- @coll2 = Collection.new('foo', @@db, :pk => TestPK)
67
- assert_equal TestPK, @coll2.pk_factory
194
+ @coll2 = Collection.new('foo', @@db, :pk => PKTest)
195
+ assert_equal PKTest, @coll2.pk_factory
68
196
  end
69
197
 
70
198
  def test_valid_names
@@ -158,13 +286,17 @@ class TestCollection < Test::Unit::TestCase
158
286
 
159
287
  def test_safe_insert
160
288
  @@test.create_index("hello", :unique => true)
161
- a = {"hello" => "world"}
162
- @@test.insert(a)
163
- @@test.insert(a, :w => 0)
164
- assert(@@db.get_last_error['err'].include?("11000"))
165
-
166
- assert_raise OperationFailure do
289
+ begin
290
+ a = {"hello" => "world"}
167
291
  @@test.insert(a)
292
+ @@test.insert(a, :w => 0)
293
+ assert(@@db.get_last_error['err'].include?("11000"))
294
+
295
+ assert_raise OperationFailure do
296
+ @@test.insert(a)
297
+ end
298
+ ensure
299
+ @@test.drop_indexes
168
300
  end
169
301
  end
170
302
 
@@ -182,29 +314,32 @@ class TestCollection < Test::Unit::TestCase
182
314
  def test_bulk_insert_with_continue_on_error
183
315
  if @@version >= "2.0"
184
316
  @@test.create_index([["foo", 1]], :unique => true)
185
- docs = []
186
- docs << {:foo => 1}
187
- docs << {:foo => 1}
188
- docs << {:foo => 2}
189
- docs << {:foo => 3}
190
- assert_raise OperationFailure do
191
- @@test.insert(docs)
192
- end
193
- assert_equal 1, @@test.count
194
- @@test.remove
317
+ begin
318
+ docs = []
319
+ docs << {:foo => 1}
320
+ docs << {:foo => 1}
321
+ docs << {:foo => 2}
322
+ docs << {:foo => 3}
323
+ assert_raise OperationFailure do
324
+ @@test.insert(docs)
325
+ end
326
+ assert_equal 1, @@test.count
327
+ @@test.remove
195
328
 
196
- docs = []
197
- docs << {:foo => 1}
198
- docs << {:foo => 1}
199
- docs << {:foo => 2}
200
- docs << {:foo => 3}
201
- assert_raise OperationFailure do
202
- @@test.insert(docs, :continue_on_error => true)
203
- end
204
- assert_equal 3, @@test.count
329
+ docs = []
330
+ docs << {:foo => 1}
331
+ docs << {:foo => 1}
332
+ docs << {:foo => 2}
333
+ docs << {:foo => 3}
334
+ assert_raise OperationFailure do
335
+ @@test.insert(docs, :continue_on_error => true)
336
+ end
337
+ assert_equal 3, @@test.count
205
338
 
206
- @@test.remove
207
- @@test.drop_index("foo_1")
339
+ @@test.remove
340
+ ensure
341
+ @@test.drop_index("foo_1")
342
+ end
208
343
  end
209
344
  end
210
345
 
@@ -229,7 +364,7 @@ class TestCollection < Test::Unit::TestCase
229
364
  assert_raise BSON::InvalidKeyName do
230
365
  @@test.insert(docs, :collect_on_error => false)
231
366
  end
232
- assert_equal 0, @@test.count
367
+ assert_equal 2, @@test.count
233
368
 
234
369
  doc_ids, error_docs = @@test.insert(docs, :collect_on_error => true)
235
370
  assert_equal 2, @@test.count
@@ -250,7 +385,7 @@ class TestCollection < Test::Unit::TestCase
250
385
  assert_raise BSON::InvalidStringEncoding do
251
386
  @@test.insert(docs, :collect_on_error => false)
252
387
  end
253
- assert_equal 0, @@test.count
388
+ assert_equal 2, @@test.count
254
389
 
255
390
  doc_ids, error_docs = @@test.insert(docs, :collect_on_error => true)
256
391
  assert_equal 2, @@test.count
@@ -284,20 +419,20 @@ class TestCollection < Test::Unit::TestCase
284
419
  admin_db.expects(:command).returns({
285
420
  'ok' => 1,
286
421
  'ismaster' => 1,
287
- 'maxBsonObjectSize' => 1024,
288
- 'maxMessageSizeBytes' => 3 * 1024
422
+ 'maxBsonObjectSize' => LIMITED_MAX_BSON_SIZE,
423
+ 'maxMessageSizeBytes' => LIMITED_MAX_MESSAGE_SIZE
289
424
  })
290
425
  conn.expects(:[]).with('admin').returns(admin_db)
291
426
  conn.connect
292
- return conn.db(MONGO_TEST_DB)["test"]
427
+ return conn.db(TEST_DB)["test"]
293
428
  end
294
429
 
295
430
  def test_non_operation_failure_halts_insertion_with_continue_on_error
296
431
  coll = limited_collection
297
- coll.stubs(:send_insert_message).raises(OperationTimeout).times(1)
432
+ coll.db.connection.stubs(:send_message_with_gle).raises(OperationTimeout).times(1)
298
433
  docs = []
299
434
  10.times do
300
- docs << {'foo' => 'a' * 950}
435
+ docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
301
436
  end
302
437
  assert_raise OperationTimeout do
303
438
  coll.insert(docs, :continue_on_error => true)
@@ -307,7 +442,7 @@ class TestCollection < Test::Unit::TestCase
307
442
  def test_chunking_batch_insert
308
443
  docs = []
309
444
  10.times do
310
- docs << {'foo' => 'a' * 950}
445
+ docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
311
446
  end
312
447
  limited_collection.insert(docs)
313
448
  assert_equal 10, limited_collection.count
@@ -316,13 +451,13 @@ class TestCollection < Test::Unit::TestCase
316
451
  def test_chunking_batch_insert_without_collect_on_error
317
452
  docs = []
318
453
  4.times do
319
- docs << {'foo' => 'a' * 950}
454
+ docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
320
455
  end
321
456
  invalid_docs = []
322
457
  invalid_docs << {'$invalid-key' => 1} # non utf8 encoding
323
458
  docs += invalid_docs
324
459
  4.times do
325
- docs << {'foo' => 'a' * 950}
460
+ docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
326
461
  end
327
462
  assert_raise BSON::InvalidKeyName do
328
463
  limited_collection.insert(docs, :collect_on_error => false)
@@ -334,13 +469,13 @@ class TestCollection < Test::Unit::TestCase
334
469
  if RUBY_PLATFORM == 'java' then return end
335
470
  docs = []
336
471
  4.times do
337
- docs << {'foo' => 'a' * 950}
472
+ docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
338
473
  end
339
474
  invalid_docs = []
340
475
  invalid_docs << {'$invalid-key' => 1} # non utf8 encoding
341
476
  docs += invalid_docs
342
477
  4.times do
343
- docs << {'foo' => 'a' * 950}
478
+ docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
344
479
  end
345
480
  doc_ids, error_docs = limited_collection.insert(docs, :collect_on_error => true)
346
481
  assert_equal 8, doc_ids.count
@@ -351,28 +486,28 @@ class TestCollection < Test::Unit::TestCase
351
486
  def test_chunking_batch_insert_with_continue_on_error
352
487
  docs = []
353
488
  4.times do
354
- docs << {'foo' => 'a' * 950}
489
+ docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
355
490
  end
356
491
  docs << {'_id' => 'b', 'foo' => 'a'}
357
492
  docs << {'_id' => 'b', 'foo' => 'c'}
358
493
  4.times do
359
- docs << {'foo' => 'a' * 950}
494
+ docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
360
495
  end
361
496
  assert_raise OperationFailure do
362
497
  limited_collection.insert(docs, :continue_on_error => true)
363
498
  end
364
- assert_equal 9, limited_collection.count
499
+ assert limited_collection.count >= 6, "write commands need headroom for doc wrapping overhead - count:#{limited_collection.count}"
365
500
  end
366
501
 
367
502
  def test_chunking_batch_insert_without_continue_on_error
368
503
  docs = []
369
504
  4.times do
370
- docs << {'foo' => 'a' * 950}
505
+ docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
371
506
  end
372
507
  docs << {'_id' => 'b', 'foo' => 'a'}
373
508
  docs << {'_id' => 'b', 'foo' => 'c'}
374
509
  4.times do
375
- docs << {'foo' => 'a' * 950}
510
+ docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
376
511
  end
377
512
  assert_raise OperationFailure do
378
513
  limited_collection.insert(docs, :continue_on_error => false)
@@ -383,74 +518,74 @@ class TestCollection < Test::Unit::TestCase
383
518
  def test_maximum_insert_size
384
519
  docs = []
385
520
  3.times do
386
- docs << {'foo' => 'a' * 950}
521
+ docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
387
522
  end
388
523
  assert_equal limited_collection.insert(docs).length, 3
389
524
  end
390
525
 
391
526
  def test_maximum_document_size
392
527
  assert_raise InvalidDocument do
393
- limited_collection.insert({'foo' => 'a' * 1024})
528
+ limited_collection.insert({'foo' => 'a' * LIMITED_MAX_BSON_SIZE})
394
529
  end
395
530
  end
396
531
 
397
532
  def test_maximum_save_size
398
- assert limited_collection.save({'foo' => 'a' * 950})
533
+ assert limited_collection.save({'foo' => 'a' * LIMITED_VALID_VALUE_SIZE})
399
534
  assert_raise InvalidDocument do
400
- limited_collection.save({'foo' => 'a' * 1024})
535
+ limited_collection.save({'foo' => 'a' * LIMITED_MAX_BSON_SIZE})
401
536
  end
402
537
  end
403
538
 
404
539
  def test_maximum_remove_size
405
- assert limited_collection.remove({'foo' => 'a' * 950})
540
+ assert limited_collection.remove({'foo' => 'a' * LIMITED_VALID_VALUE_SIZE})
406
541
  assert_raise InvalidDocument do
407
- limited_collection.remove({'foo' => 'a' * 1024})
542
+ limited_collection.remove({'foo' => 'a' * LIMITED_MAX_BSON_SIZE})
408
543
  end
409
544
  end
410
545
 
411
546
  def test_maximum_update_size
412
547
  assert_raise InvalidDocument do
413
548
  limited_collection.update(
414
- {'foo' => 'a' * 1024},
415
- {'foo' => 'a' * 950}
549
+ {'foo' => 'a' * LIMITED_MAX_BSON_SIZE},
550
+ {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
416
551
  )
417
552
  end
418
553
 
419
554
  assert_raise InvalidDocument do
420
555
  limited_collection.update(
421
- {'foo' => 'a' * 950},
422
- {'foo' => 'a' * 1024}
556
+ {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE},
557
+ {'foo' => 'a' * LIMITED_MAX_BSON_SIZE}
423
558
  )
424
559
  end
425
560
 
426
561
  assert_raise InvalidDocument do
427
562
  limited_collection.update(
428
- {'foo' => 'a' * 1024},
429
- {'foo' => 'a' * 1024}
563
+ {'foo' => 'a' * LIMITED_MAX_BSON_SIZE},
564
+ {'foo' => 'a' * LIMITED_MAX_BSON_SIZE}
430
565
  )
431
566
  end
432
567
 
433
568
  assert limited_collection.update(
434
- {'foo' => 'a' * 950},
435
- {'foo' => 'a' * 950}
569
+ {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE},
570
+ {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
436
571
  )
437
572
  end
438
573
 
439
574
  def test_maximum_query_size
440
- assert limited_collection.find({'foo' => 'a' * 950}).to_a
575
+ assert limited_collection.find({'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}).to_a
441
576
  assert limited_collection.find(
442
- {'foo' => 'a' * 950},
443
- {:fields => {'foo' => 'a' * 950}}
577
+ {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE},
578
+ {:fields => {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}}
444
579
  ).to_a
445
580
 
446
581
  assert_raise InvalidDocument do
447
- limited_collection.find({'foo' => 'a' * 1024}).to_a
582
+ limited_collection.find({'foo' => 'a' * LIMITED_INVALID_VALUE_SIZE}).to_a
448
583
  end
449
584
 
450
585
  assert_raise InvalidDocument do
451
586
  limited_collection.find(
452
- {'foo' => 'a' * 950},
453
- {:fields => {'foo' => 'a' * 1024}}
587
+ {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE},
588
+ {:fields => {'foo' => 'a' * LIMITED_MAX_BSON_SIZE}}
454
589
  ).to_a
455
590
  end
456
591
  end
@@ -470,8 +605,8 @@ class TestCollection < Test::Unit::TestCase
470
605
  # end
471
606
  #end
472
607
 
473
- if @@version >= "2.0.0"
474
- def test_safe_mode_with_journal_commit_option
608
+ def test_safe_mode_with_journal_commit_option
609
+ with_default_journaling(@@client) do
475
610
  @@test.insert({:foo => 1}, :j => true)
476
611
  @@test.update({:foo => 1}, {:foo => 2}, :j => true)
477
612
  @@test.remove({:foo => 2}, :j => true)
@@ -490,13 +625,15 @@ class TestCollection < Test::Unit::TestCase
490
625
  assert_equal 1, @@test.find_one(:_id => id2)["x"]
491
626
  end
492
627
 
493
- def test_update_check_keys
494
- @@test.save("x" => 1)
495
- @@test.update({"x" => 1}, {"$set" => {"a.b" => 2}})
496
- assert_equal 2, @@test.find_one("x" => 1)["a"]["b"]
628
+ if @@version < "2.5.3"
629
+ def test_update_check_keys
630
+ @@test.save("x" => 1)
631
+ @@test.update({"x" => 1}, {"$set" => {"a.b" => 2}})
632
+ assert_equal 2, @@test.find_one("x" => 1)["a"]["b"]
497
633
 
498
- assert_raise_error BSON::InvalidKeyName do
499
- @@test.update({"x" => 1}, {"a.b" => 3})
634
+ assert_raise_error BSON::InvalidKeyName do
635
+ @@test.update({"x" => 1}, {"a.b" => 3})
636
+ end
500
637
  end
501
638
  end
502
639
 
@@ -568,7 +705,7 @@ class TestCollection < Test::Unit::TestCase
568
705
 
569
706
  def test_mocked_safe_remove
570
707
  @client = standard_connection
571
- @db = @client[MONGO_TEST_DB]
708
+ @db = @client[TEST_DB]
572
709
  @test = @db['test-safe-remove']
573
710
  @test.save({:a => 20})
574
711
  @client.stubs(:receive).returns([[{'ok' => 0, 'err' => 'failed'}], 1, 0])
@@ -581,7 +718,7 @@ class TestCollection < Test::Unit::TestCase
581
718
 
582
719
  def test_safe_remove
583
720
  @client = standard_connection
584
- @db = @client[MONGO_TEST_DB]
721
+ @db = @client[TEST_DB]
585
722
  @test = @db['test-safe-remove']
586
723
  @test.remove
587
724
  @test.save({:a => 50})
@@ -593,6 +730,14 @@ class TestCollection < Test::Unit::TestCase
593
730
  assert_equal true, @@test.remove({}, :w => 0)
594
731
  end
595
732
 
733
+ def test_remove_with_limit
734
+ @@test.insert([{:n => 1},{:n => 2},{:n => 3}])
735
+ @@test.remove({}, :limit => 1)
736
+ assert_equal 2, @@test.count
737
+ @@test.remove({}, :limit => 0)
738
+ assert_equal 0, @@test.count
739
+ end
740
+
596
741
  def test_count
597
742
  @@test.drop
598
743
 
@@ -692,6 +837,22 @@ class TestCollection < Test::Unit::TestCase
692
837
  end
693
838
  end
694
839
 
840
+ def test_find_one_with_max_time_ms
841
+ with_forced_timeout(@@client) do
842
+ assert_raise ExecutionTimeout do
843
+ @@test.find_one({}, { :max_time_ms => 100 })
844
+ end
845
+ end
846
+ end
847
+
848
+ def test_find_one_with_compile_regex_option
849
+ regex = /.*/
850
+ @@test.insert('r' => /.*/)
851
+ assert_kind_of Regexp, @@test.find_one({})['r']
852
+ assert_kind_of Regexp, @@test.find_one({}, :compile_regex => true)['r']
853
+ assert_equal BSON::Regex, @@test.find_one({}, :compile_regex => false)['r'].class
854
+ end
855
+
695
856
  def test_insert_adds_id
696
857
  doc = {"hello" => "world"}
697
858
  @@test.insert(doc)
@@ -856,6 +1017,57 @@ class TestCollection < Test::Unit::TestCase
856
1017
  results = @@test.aggregate([{"$unwind"=> "$tags"}])
857
1018
  assert_equal desired_results, results
858
1019
  end
1020
+
1021
+ def test_aggregate_with_compile_regex_option
1022
+ # see SERVER-6470
1023
+ return unless @@version >= '2.3.2'
1024
+ @@test.insert({ 'r' => /.*/ })
1025
+ result1 = @@test.aggregate([])
1026
+ assert_kind_of Regexp, result1.first['r']
1027
+
1028
+ result2 = @@test.aggregate([], :compile_regex => false)
1029
+ assert_kind_of BSON::Regex, result2.first['r']
1030
+
1031
+ return unless @@version >= '2.5.1'
1032
+ result = @@test.aggregate([], :compile_regex => false, :cursor => {})
1033
+ assert_kind_of BSON::Regex, result.first['r']
1034
+ end
1035
+ end
1036
+
1037
+ if @@version >= "2.5.2"
1038
+ def test_out_aggregate
1039
+ out_collection = 'test_out'
1040
+ @@db.drop_collection(out_collection)
1041
+ setup_aggregate_data
1042
+ docs = @@test.find.to_a
1043
+ pipeline = [{:$out => out_collection}]
1044
+ @@test.aggregate(pipeline)
1045
+ assert_equal docs, @@db.collection(out_collection).find.to_a
1046
+ end
1047
+
1048
+ def test_out_aggregate_nonprimary_sym_warns
1049
+ ReadPreference::expects(:warn).with(regexp_matches(/rerouted to primary/))
1050
+ pipeline = [{:$out => 'test_out'}]
1051
+ @@test.aggregate(pipeline, :read => :secondary)
1052
+ end
1053
+
1054
+ def test_out_aggregate_nonprimary_string_warns
1055
+ ReadPreference::expects(:warn).with(regexp_matches(/rerouted to primary/))
1056
+ pipeline = [{'$out' => 'test_out'}]
1057
+ @@test.aggregate(pipeline, :read => :secondary)
1058
+ end
1059
+
1060
+ def test_out_aggregate_string_returns_raw_response
1061
+ pipeline = [{'$out' => 'test_out'}]
1062
+ response = @@test.aggregate(pipeline)
1063
+ assert response.respond_to?(:keys)
1064
+ end
1065
+
1066
+ def test_out_aggregate_sym_returns_raw_response
1067
+ pipeline = [{:$out => 'test_out'}]
1068
+ response = @@test.aggregate(pipeline)
1069
+ assert response.respond_to?(:keys)
1070
+ end
859
1071
  end
860
1072
 
861
1073
  if @@version > "1.1.1"
@@ -865,7 +1077,7 @@ class TestCollection < Test::Unit::TestCase
865
1077
 
866
1078
  m = "function() { emit(this.user_id, 1); }"
867
1079
  r = "function(k,vals) { return 1; }"
868
- res = @@test.map_reduce(m, r, :out => 'foo');
1080
+ res = @@test.map_reduce(m, r, :out => 'foo')
869
1081
  assert res.find_one({"_id" => 1})
870
1082
  assert res.find_one({"_id" => 2})
871
1083
  end
@@ -876,7 +1088,7 @@ class TestCollection < Test::Unit::TestCase
876
1088
 
877
1089
  m = Code.new("function() { emit(this.user_id, 1); }")
878
1090
  r = Code.new("function(k,vals) { return 1; }")
879
- res = @@test.map_reduce(m, r, :out => 'foo');
1091
+ res = @@test.map_reduce(m, r, :out => 'foo')
880
1092
  assert res.find_one({"_id" => 1})
881
1093
  assert res.find_one({"_id" => 2})
882
1094
  end
@@ -889,7 +1101,7 @@ class TestCollection < Test::Unit::TestCase
889
1101
 
890
1102
  m = Code.new("function() { emit(this.user_id, 1); }")
891
1103
  r = Code.new("function(k,vals) { return 1; }")
892
- res = @@test.map_reduce(m, r, :query => {"user_id" => {"$gt" => 1}}, :out => 'foo');
1104
+ res = @@test.map_reduce(m, r, :query => {"user_id" => {"$gt" => 1}}, :out => 'foo')
893
1105
  assert_equal 2, res.count
894
1106
  assert res.find_one({"_id" => 2})
895
1107
  assert res.find_one({"_id" => 3})
@@ -914,6 +1126,13 @@ class TestCollection < Test::Unit::TestCase
914
1126
  assert res["timeMillis"]
915
1127
  end
916
1128
 
1129
+ def test_map_reduce_nonprimary_output_collection_reroutes
1130
+ output_collection = "test-map-coll"
1131
+ m = Code.new("function() { emit(this.user_id, 1); }")
1132
+ r = Code.new("function(k,vals) { return 1; }")
1133
+ Mongo::ReadPreference.expects(:warn).with(regexp_matches(/rerouted to primary/))
1134
+ res = @@test.map_reduce(m, r, :raw => true, :out => output_collection, :read => :secondary)
1135
+ end
917
1136
 
918
1137
  if @@version >= "1.8.0"
919
1138
  def test_map_reduce_with_collection_merge
@@ -951,7 +1170,7 @@ class TestCollection < Test::Unit::TestCase
951
1170
  r = Code.new("function(k,vals) { return 1; }")
952
1171
  oh = BSON::OrderedHash.new
953
1172
  oh[:replace] = 'foo'
954
- oh[:db] = MONGO_TEST_DB
1173
+ oh[:db] = TEST_DB
955
1174
  res = @@test.map_reduce(m, r, :out => (oh))
956
1175
  assert res["result"]
957
1176
  assert res["counts"]
@@ -961,6 +1180,23 @@ class TestCollection < Test::Unit::TestCase
961
1180
  end
962
1181
  end
963
1182
 
1183
+ if @@version >= '2.5.5'
1184
+ def test_parallel_scan
1185
+ 8000.times { |i| @@test.insert({ :_id => i }) }
1186
+
1187
+ n_docs = {}
1188
+ threads = []
1189
+ cursors = @@test.parallel_scan(3)
1190
+ cursors.each_with_index do |cursor, i|
1191
+ threads << Thread.new do
1192
+ n_docs[i] = cursor.to_a.size
1193
+ end
1194
+ end
1195
+ threads.each(&:join)
1196
+ assert_equal @@test.count, n_docs.values.inject(0) { |sum, n| sum + n }
1197
+ end
1198
+ end
1199
+
964
1200
  if @@version > "1.3.0"
965
1201
  def test_find_and_modify
966
1202
  @@test << { :a => 1, :processed => false }
@@ -1005,7 +1241,8 @@ class TestCollection < Test::Unit::TestCase
1005
1241
  @@test << {:n => 1}
1006
1242
  @@test.create_index("n")
1007
1243
 
1008
- assert_equal "#{MONGO_TEST_DB}.test", @@test.stats['ns']
1244
+ assert_equal "#{TEST_DB}.test", @@test.stats['ns']
1245
+ @@test.drop
1009
1246
  end
1010
1247
  end
1011
1248
 
@@ -1184,6 +1421,7 @@ end
1184
1421
  @@test.ensure_index([['a', 1]])
1185
1422
  assert @@test.index_information.keys.include?("a_1")
1186
1423
  @@test.drop_index("a_1")
1424
+ @@test.drop_indexes
1187
1425
  end
1188
1426
 
1189
1427
  def test_ensure_index_timeout
@@ -1201,6 +1439,7 @@ end
1201
1439
  sleep(1)
1202
1440
  # This won't be, so generate_indexes will be called twice
1203
1441
  coll.ensure_index([['a', 1]])
1442
+ coll.drop
1204
1443
  end
1205
1444
 
1206
1445
  if @@version > '2.0.0'
@@ -1213,12 +1452,18 @@ end
1213
1452
  end
1214
1453
 
1215
1454
  def test_max_scan
1216
- 1000.times do |n|
1217
- @@test.save({:a => n})
1455
+ @@test.drop
1456
+ n = 100
1457
+ n.times do |i|
1458
+ @@test.save({:_id => i, :x => i % 10})
1218
1459
  end
1219
- assert @@test.find({:a => 999}).next
1220
- assert !@@test.find({:a => 999}, :max_scan => 500).next
1221
- @@test.remove
1460
+ assert_equal(n, @@test.find.to_a.size)
1461
+ assert_equal(50, @@test.find({}, :max_scan => 50).to_a.size)
1462
+ assert_equal(10, @@test.find({:x => 2}).to_a.size)
1463
+ assert_equal(5, @@test.find({:x => 2}, :max_scan => 50).to_a.size)
1464
+ @@test.ensure_index([[:x, 1]])
1465
+ assert_equal(10, @@test.find({:x => 2}, :max_scan => n).to_a.size)
1466
+ @@test.drop
1222
1467
  end
1223
1468
  end
1224
1469
 
@@ -1400,6 +1645,7 @@ end
1400
1645
  should "create a geoHaystack index" do
1401
1646
  @geo.save({ "_id" => 100, "pos" => { "long" => 126.9, "lat" => 35.2 }, "type" => "restaurant"})
1402
1647
  @geo.create_index([['pos', Mongo::GEOHAYSTACK], ['type', Mongo::ASCENDING]], :bucket_size => 1)
1648
+ assert @geo.index_information['pos_geoHaystack_type_1']
1403
1649
  end
1404
1650
 
1405
1651
  should "create a geo 2dsphere index" do
@@ -1472,8 +1718,8 @@ end
1472
1718
  end
1473
1719
 
1474
1720
  should "generate indexes in the proper order" do
1475
- @collection.expects(:insert_documents) do |sel, coll, safe|
1476
- assert_equal 'b_1_a_1', sel[:name]
1721
+ @collection.expects(:send_write) do |type, selector, documents, check_keys, opts, collection_name|
1722
+ assert_equal 'b_1_a_1', selector[:name]
1477
1723
  end
1478
1724
  @collection.create_index([['b', 1], ['a', 1]])
1479
1725
  end
@@ -1501,7 +1747,7 @@ end
1501
1747
  context "Capped collections" do
1502
1748
  setup do
1503
1749
  @@db.drop_collection('log')
1504
- @capped = @@db.create_collection('log', :capped => true, :size => 1024)
1750
+ @capped = @@db.create_collection('log', :capped => true, :size => LIMITED_MAX_BSON_SIZE)
1505
1751
 
1506
1752
  10.times { |n| @capped.insert({:n => n}) }
1507
1753
  end