mongo 1.3.1 → 1.4.0

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 (75) hide show
  1. data/README.md +9 -6
  2. data/Rakefile +3 -4
  3. data/docs/HISTORY.md +20 -2
  4. data/docs/READ_PREFERENCE.md +39 -0
  5. data/docs/RELEASES.md +1 -1
  6. data/docs/REPLICA_SETS.md +23 -2
  7. data/docs/TAILABLE_CURSORS.md +51 -0
  8. data/docs/TUTORIAL.md +4 -4
  9. data/docs/WRITE_CONCERN.md +5 -2
  10. data/lib/mongo.rb +7 -22
  11. data/lib/mongo/collection.rb +96 -29
  12. data/lib/mongo/connection.rb +107 -62
  13. data/lib/mongo/cursor.rb +136 -57
  14. data/lib/mongo/db.rb +26 -5
  15. data/lib/mongo/exceptions.rb +17 -1
  16. data/lib/mongo/gridfs/grid.rb +1 -1
  17. data/lib/mongo/repl_set_connection.rb +273 -156
  18. data/lib/mongo/util/logging.rb +42 -0
  19. data/lib/mongo/util/node.rb +183 -0
  20. data/lib/mongo/util/pool.rb +76 -13
  21. data/lib/mongo/util/pool_manager.rb +208 -0
  22. data/lib/mongo/util/ssl_socket.rb +38 -0
  23. data/lib/mongo/util/support.rb +9 -1
  24. data/lib/mongo/util/timeout.rb +42 -0
  25. data/lib/mongo/version.rb +3 -0
  26. data/mongo.gemspec +2 -2
  27. data/test/bson/binary_test.rb +1 -1
  28. data/test/bson/bson_string_test.rb +30 -0
  29. data/test/bson/bson_test.rb +6 -3
  30. data/test/bson/byte_buffer_test.rb +1 -1
  31. data/test/bson/hash_with_indifferent_access_test.rb +1 -1
  32. data/test/bson/json_test.rb +1 -1
  33. data/test/bson/object_id_test.rb +2 -18
  34. data/test/bson/ordered_hash_test.rb +38 -3
  35. data/test/bson/test_helper.rb +46 -0
  36. data/test/bson/timestamp_test.rb +32 -10
  37. data/test/collection_test.rb +89 -3
  38. data/test/connection_test.rb +35 -20
  39. data/test/cursor_test.rb +63 -2
  40. data/test/db_test.rb +12 -2
  41. data/test/pool_test.rb +21 -0
  42. data/test/replica_sets/connect_test.rb +26 -13
  43. data/test/replica_sets/connection_string_test.rb +1 -4
  44. data/test/replica_sets/count_test.rb +1 -0
  45. data/test/replica_sets/insert_test.rb +1 -0
  46. data/test/replica_sets/pooled_insert_test.rb +4 -1
  47. data/test/replica_sets/query_secondaries.rb +2 -1
  48. data/test/replica_sets/query_test.rb +2 -1
  49. data/test/replica_sets/read_preference_test.rb +43 -0
  50. data/test/replica_sets/refresh_test.rb +123 -0
  51. data/test/replica_sets/replication_ack_test.rb +9 -4
  52. data/test/replica_sets/rs_test_helper.rb +2 -2
  53. data/test/timeout_test.rb +14 -0
  54. data/test/tools/repl_set_manager.rb +134 -23
  55. data/test/unit/collection_test.rb +6 -8
  56. data/test/unit/connection_test.rb +4 -4
  57. data/test/unit/cursor_test.rb +23 -5
  58. data/test/unit/db_test.rb +2 -0
  59. data/test/unit/grid_test.rb +2 -0
  60. data/test/unit/node_test.rb +73 -0
  61. data/test/unit/pool_manager_test.rb +47 -0
  62. data/test/unit/read_test.rb +101 -0
  63. metadata +214 -138
  64. data/lib/mongo/test.rb +0 -20
  65. data/test/async/collection_test.rb +0 -224
  66. data/test/async/connection_test.rb +0 -24
  67. data/test/async/cursor_test.rb +0 -162
  68. data/test/async/worker_pool_test.rb +0 -99
  69. data/test/load/resque/load.rb +0 -21
  70. data/test/load/resque/processor.rb +0 -26
  71. data/test/load/unicorn/unicorn.rb +0 -29
  72. data/test/tools/load.rb +0 -58
  73. data/test/tools/sharding_manager.rb +0 -202
  74. data/test/tools/test.rb +0 -4
  75. data/test/unit/repl_set_connection_test.rb +0 -59
@@ -0,0 +1,38 @@
1
+ require 'openssl'
2
+
3
+ module Mongo
4
+
5
+ # A basic wrapper over Ruby's SSLSocket that initiates
6
+ # a TCP connection over SSL and then provides an basic interface
7
+ # mirroring Ruby's TCPSocket, vis., TCPSocket#send and TCPSocket#read.
8
+ class SSLSocket
9
+
10
+ def initialize(host, port)
11
+ @socket = ::TCPSocket.new(host, port)
12
+ @ssl = OpenSSL::SSL::SSLSocket.new(@socket)
13
+ @ssl.sync_close = true
14
+ @ssl.connect
15
+ end
16
+
17
+ def setsockopt(key, value, n)
18
+ @socket.setsockopt(key, value, n)
19
+ end
20
+
21
+ # Write to the SSL socket.
22
+ #
23
+ # @param buffer a buffer to send.
24
+ # @param flags socket flags. Because Ruby's SSL
25
+ def send(buffer, flags=0)
26
+ @ssl.syswrite(buffer)
27
+ end
28
+
29
+ def read(length, buffer)
30
+ @ssl.sysread(length, buffer)
31
+ end
32
+
33
+ def close
34
+ @ssl.close
35
+ end
36
+
37
+ end
38
+ end
@@ -44,7 +44,6 @@ module Mongo
44
44
  Digest::MD5.hexdigest("#{username}:mongo:#{plaintext}")
45
45
  end
46
46
 
47
-
48
47
  def validate_db_name(db_name)
49
48
  unless [String, Symbol].include?(db_name.class)
50
49
  raise TypeError, "db_name must be a string or symbol"
@@ -59,6 +58,15 @@ module Mongo
59
58
  db_name
60
59
  end
61
60
 
61
+ def validate_read_preference(value)
62
+ if [:primary, :secondary, nil].include?(value)
63
+ return true
64
+ else
65
+ raise MongoArgumentError, "#{value} is not a valid read preference. " +
66
+ "Please specify either :primary or :secondary."
67
+ end
68
+ end
69
+
62
70
  def format_order_clause(order)
63
71
  case order
64
72
  when String, Symbol then string_as_sort_parameters(order)
@@ -0,0 +1,42 @@
1
+ # encoding: UTF-8
2
+
3
+ # --
4
+ # Copyright (C) 2008-2011 10gen Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ # ++
18
+ module Mongo #:nodoc:
19
+ module TimeoutWrapper
20
+ extend self
21
+
22
+ def timeout_lib=(lib)
23
+ @@timeout_lib = lib
24
+ end
25
+
26
+ def timeout_lib
27
+ @@timeout_lib
28
+ end
29
+
30
+ def timeout(delay, &block)
31
+ if timeout_lib
32
+ begin
33
+ timeout_lib.timeout(delay, &block)
34
+ rescue ::Timeout::Error
35
+ raise Mongo::OperationTimeout
36
+ end
37
+ else
38
+ yield
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,3 @@
1
+ module Mongo
2
+ VERSION = "1.4.0"
3
+ end
@@ -1,4 +1,4 @@
1
- require "./lib/mongo"
1
+ require File.expand_path('../lib/mongo/version', __FILE__)
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'mongo'
@@ -30,5 +30,5 @@ Gem::Specification.new do |s|
30
30
  s.email = 'mongodb-dev@googlegroups.com'
31
31
  s.homepage = 'http://www.mongodb.org'
32
32
 
33
- s.add_dependency(%q<bson>, [">= #{Mongo::VERSION}"])
33
+ s.add_dependency('bson', Mongo::VERSION)
34
34
  end
@@ -1,5 +1,5 @@
1
1
  # encoding:utf-8
2
- require './test/test_helper'
2
+ require './test/bson/test_helper'
3
3
 
4
4
  class BinaryTest < Test::Unit::TestCase
5
5
  context "Inspecting" do
@@ -0,0 +1,30 @@
1
+ # encoding:utf-8
2
+ require './test/bson/test_helper'
3
+ require 'complex'
4
+ require 'bigdecimal'
5
+ require 'rational'
6
+
7
+ class BSONTest < Test::Unit::TestCase
8
+
9
+ include BSON
10
+
11
+ def setup
12
+ @encoder = BSON::BSON_CODER
13
+ end
14
+
15
+ def assert_doc_pass(doc, options={})
16
+ bson = @encoder.serialize(doc)
17
+ if options[:debug]
18
+ puts "DEBUGGING DOC:"
19
+ p bson.to_a
20
+ puts "DESERIALIZES TO:"
21
+ end
22
+ assert_equal @encoder.serialize(doc).to_a, bson.to_a
23
+ assert_equal doc, @encoder.deserialize(bson)
24
+ end
25
+
26
+ def test_string
27
+ assert_doc_pass({:a => "hello"})
28
+ end
29
+
30
+ end
@@ -1,5 +1,6 @@
1
1
  # encoding:utf-8
2
- require './test/test_helper'
2
+ require './test/bson/test_helper'
3
+ require 'set'
3
4
 
4
5
  if RUBY_VERSION < '1.9'
5
6
  require 'complex'
@@ -436,8 +437,10 @@ class BSONTest < Test::Unit::TestCase
436
437
  0x00, 0x00, 0x14, 0x00,
437
438
  0x00, 0x00, 0x00])
438
439
 
439
- assert_equal 4, result["test"][0]
440
- assert_equal 20, result["test"][1]
440
+ silently do
441
+ assert_equal 4, result["test"][0]
442
+ assert_equal 20, result["test"][1]
443
+ end
441
444
  end
442
445
  end
443
446
 
@@ -1,5 +1,5 @@
1
1
  # encoding: binary
2
- require './test/test_helper'
2
+ require './test/bson/test_helper'
3
3
 
4
4
  class ByteBufferTest < Test::Unit::TestCase
5
5
  include BSON
@@ -1,5 +1,5 @@
1
1
  # encoding:utf-8
2
- require './test/test_helper'
2
+ require './test/bson/test_helper'
3
3
  require './test/support/hash_with_indifferent_access'
4
4
 
5
5
  class HashWithIndifferentAccessTest < Test::Unit::TestCase
@@ -1,4 +1,4 @@
1
- require './test/test_helper'
1
+ require './test/bson/test_helper'
2
2
  require 'rubygems'
3
3
  require 'json'
4
4
 
@@ -1,12 +1,9 @@
1
- require './test/test_helper'
1
+ require './test/bson/test_helper'
2
2
  require 'rubygems'
3
3
  require 'json'
4
4
 
5
5
  class ObjectIdTest < Test::Unit::TestCase
6
6
 
7
- include Mongo
8
- include BSON
9
-
10
7
  def setup
11
8
  @o = ObjectId.new
12
9
  end
@@ -65,18 +62,6 @@ class ObjectIdTest < Test::Unit::TestCase
65
62
  assert_equal "BSON::ObjectId('#{@o.to_s}')", @o.inspect
66
63
  end
67
64
 
68
- def test_save_and_restore
69
- db = standard_connection.db(MONGO_TEST_DB)
70
- coll = db.collection('test')
71
-
72
- coll.remove
73
- coll << {'a' => 1, '_id' => @o}
74
-
75
- row = coll.find().collect.first
76
- assert_equal 1, row['a']
77
- assert_equal @o, row['_id']
78
- end
79
-
80
65
  def test_from_string
81
66
  hex_str = @o.to_s
82
67
  o2 = ObjectId.from_string(hex_str)
@@ -134,8 +119,7 @@ class ObjectIdTest < Test::Unit::TestCase
134
119
  time = Time.now.utc
135
120
  id = ObjectId.from_time(time, :unique => true)
136
121
 
137
- mac_id = Digest::MD5.digest(Socket.gethostname)[0, 3].unpack("C3")
138
- assert_equal id.to_a[4, 3], mac_id
122
+ assert_equal id.to_a[4, 3], ObjectId.machine_id.unpack("C3")
139
123
  assert_equal time.to_i, id.generation_time.to_i
140
124
 
141
125
  id2 = ObjectId.new(nil, time)
@@ -1,4 +1,4 @@
1
- require './test/test_helper'
1
+ require './test/bson/test_helper'
2
2
 
3
3
  class OrderedHashTest < Test::Unit::TestCase
4
4
 
@@ -38,6 +38,7 @@ class OrderedHashTest < Test::Unit::TestCase
38
38
  same_doc = BSON::OrderedHash.new
39
39
  same_doc['_id'] = 'ab12'
40
40
  same_doc['name'] = 'test'
41
+
41
42
  list << doc
42
43
  list << same_doc
43
44
 
@@ -45,6 +46,23 @@ class OrderedHashTest < Test::Unit::TestCase
45
46
  assert_equal 1, list.uniq.size
46
47
  end
47
48
 
49
+ if !(RUBY_VERSION =~ /1.8.6/)
50
+ def test_compatibility_with_hash
51
+ list = []
52
+ doc = BSON::OrderedHash.new
53
+ doc['_id'] = 'ab12'
54
+ doc['name'] = 'test'
55
+
56
+ doc2 = {}
57
+ doc2['_id'] = 'ab12'
58
+ doc2['name'] = 'test'
59
+ list << doc
60
+ list << doc2
61
+
62
+ assert_equal 1, list.uniq.size
63
+ end
64
+ end
65
+
48
66
  def test_equality
49
67
  a = BSON::OrderedHash.new
50
68
  a['x'] = 1
@@ -76,6 +94,21 @@ class OrderedHashTest < Test::Unit::TestCase
76
94
  assert_equal @ordered_keys, @oh.keys
77
95
  end
78
96
 
97
+ def test_replace
98
+ h1 = BSON::OrderedHash.new
99
+ h1[:a] = 1
100
+ h1[:b] = 2
101
+
102
+ h2 = BSON::OrderedHash.new
103
+ h2[:c] = 3
104
+ h2[:d] = 4
105
+ h1.replace(h2)
106
+
107
+ assert_equal [:c, :d], h1.keys
108
+ assert_equal [3, 4], h1.values
109
+ assert h1.keys.object_id != h2.keys.object_id
110
+ end
111
+
79
112
  def test_to_a_order_preserved
80
113
  assert_equal @ordered_keys, @oh.to_a.map {|m| m.first}
81
114
  end
@@ -158,8 +191,10 @@ class OrderedHashTest < Test::Unit::TestCase
158
191
  assert_equal [1, 2, 3, 'foo'], noob.values
159
192
  end
160
193
 
161
- def test_inspect_retains_order
162
- assert_equal '{"c"=>1, "a"=>2, "z"=>3}', @oh.inspect
194
+ if RUBY_VERSION < "1.9.2"
195
+ def test_inspect_retains_order
196
+ assert_equal "#<BSON::OrderedHash:0x#{@oh.object_id.to_s(16)} {\"c\"=>1, \"a\"=>2, \"z\"=>3}>", @oh.inspect
197
+ end
163
198
  end
164
199
 
165
200
  def test_clear
@@ -0,0 +1,46 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'lib', 'bson')
2
+ require 'rubygems' if RUBY_VERSION < '1.9.0' && ENV['C_EXT']
3
+ require 'test/unit'
4
+
5
+ def silently
6
+ warn_level = $VERBOSE
7
+ $VERBOSE = nil
8
+ result = yield
9
+ $VERBOSE = warn_level
10
+ result
11
+ end
12
+
13
+ begin
14
+ require 'rubygems' if RUBY_VERSION < "1.9.0" && !ENV['C_EXT']
15
+ silently { require 'shoulda' }
16
+ silently { require 'mocha' }
17
+ rescue LoadError
18
+ puts <<MSG
19
+
20
+ This test suite requires shoulda and mocha.
21
+ You can install them as follows:
22
+ gem install shoulda
23
+ gem install mocha
24
+
25
+ MSG
26
+
27
+ exit
28
+ end
29
+
30
+ require 'bson_ext/cbson' if !(RUBY_PLATFORM =~ /java/) && ENV['C_EXT']
31
+
32
+ class Test::Unit::TestCase
33
+ include BSON
34
+
35
+ def assert_raise_error(klass, message)
36
+ begin
37
+ yield
38
+ rescue => e
39
+ assert_equal klass, e.class
40
+ assert e.message.include?(message), "#{e.message} does not include #{message}."
41
+ else
42
+ flunk "Expected assertion #{klass} but none was raised."
43
+ end
44
+ end
45
+
46
+ end
@@ -1,7 +1,6 @@
1
- require './test/test_helper'
1
+ require './test/bson/test_helper'
2
2
 
3
- class TiumestampTest < Test::Unit::TestCase
4
- include Mongo
3
+ class TimestampTest < Test::Unit::TestCase
5
4
 
6
5
  def test_timestamp_equality
7
6
  t1 = Timestamp.new(5000, 200)
@@ -9,16 +8,39 @@ class TiumestampTest < Test::Unit::TestCase
9
8
  assert_equal t2, t1
10
9
  end
11
10
 
11
+ def test_timestamp_range
12
+ t = 1;
13
+ while(t < 1_000_000_000 ) do
14
+ ts = Timestamp.new(t, 0)
15
+ doc = {:ts => ts}
16
+ bson = BSON::BSON_CODER.serialize(doc)
17
+ assert_equal doc[:ts], BSON::BSON_CODER.deserialize(bson)['ts']
18
+ t = t * 10
19
+ end
20
+ end
21
+
22
+ def test_timestamp_32bit_compatibility
23
+ max_32bit_fixnum = (1 << 30) - 1
24
+ test_val = max_32bit_fixnum + 10
25
+
26
+ ts = Timestamp.new(test_val, test_val)
27
+ doc = {:ts => ts}
28
+ bson = BSON::BSON_CODER.serialize(doc)
29
+ assert_equal doc[:ts], BSON::BSON_CODER.deserialize(bson)['ts']
30
+ end
31
+
12
32
  def test_implements_array_for_backward_compatibility
13
- ts = Timestamp.new(5000, 200)
14
- assert_equal 200, ts[0]
15
- assert_equal 5000, ts[1]
33
+ silently do
34
+ ts = Timestamp.new(5000, 200)
35
+ assert_equal 200, ts[0]
36
+ assert_equal 5000, ts[1]
16
37
 
17
- array = ts.map {|t| t }
18
- assert_equal 2, array.length
38
+ array = ts.map {|t| t }
39
+ assert_equal 2, array.length
19
40
 
20
- assert_equal 200, array[0]
21
- assert_equal 5000, array[1]
41
+ assert_equal 200, array[0]
42
+ assert_equal 5000, array[1]
43
+ end
22
44
  end
23
45
 
24
46
  end
@@ -1,7 +1,7 @@
1
1
  require './test/test_helper'
2
2
 
3
3
  class TestCollection < Test::Unit::TestCase
4
- @@connection ||= standard_connection(:op_timeout => 2)
4
+ @@connection ||= standard_connection(:op_timeout => 10)
5
5
  @@db = @@connection.db(MONGO_TEST_DB)
6
6
  @@test = @@db.collection("test")
7
7
  @@version = @@connection.server_version
@@ -10,6 +10,16 @@ class TestCollection < Test::Unit::TestCase
10
10
  @@test.remove
11
11
  end
12
12
 
13
+ def test_capped_method
14
+ @@db.create_collection('normal')
15
+ assert !@@db['normal'].capped?
16
+ @@db.drop_collection('normal')
17
+
18
+ @@db.create_collection('c', :capped => true, :size => 100_000)
19
+ assert @@db['c'].capped?
20
+ @@db.drop_collection('c')
21
+ end
22
+
13
23
  def test_optional_pk_factory
14
24
  @coll_default_pk = @@db.collection('stuff')
15
25
  assert_equal BSON::ObjectId, @coll_default_pk.pk_factory
@@ -141,6 +151,35 @@ class TestCollection < Test::Unit::TestCase
141
151
  end
142
152
  end
143
153
 
154
+ def test_bulk_insert_with_continue_on_error
155
+ if @@version >= "2.0"
156
+ @@test.create_index([["foo", 1]], :unique => true)
157
+ docs = []
158
+ docs << {:foo => 1}
159
+ docs << {:foo => 1}
160
+ docs << {:foo => 2}
161
+ docs << {:foo => 3}
162
+ assert_raise OperationFailure do
163
+ @@test.insert(docs, :safe => true)
164
+ end
165
+ assert_equal 1, @@test.count
166
+ @@test.remove
167
+
168
+ docs = []
169
+ docs << {:foo => 1}
170
+ docs << {:foo => 1}
171
+ docs << {:foo => 2}
172
+ docs << {:foo => 3}
173
+ assert_raise OperationFailure do
174
+ @@test.insert(docs, :safe => true, :continue_on_error => true)
175
+ end
176
+ assert_equal 3, @@test.count
177
+
178
+ @@test.remove
179
+ @@test.drop_index("foo_1")
180
+ end
181
+ end
182
+
144
183
  def test_maximum_insert_size
145
184
  docs = []
146
185
  16.times do
@@ -275,9 +314,13 @@ class TestCollection < Test::Unit::TestCase
275
314
  @@test.drop
276
315
 
277
316
  assert_equal 0, @@test.count
278
- @@test.save("x" => 1)
279
- @@test.save("x" => 2)
317
+ @@test.save(:x => 1)
318
+ @@test.save(:x => 2)
280
319
  assert_equal 2, @@test.count
320
+
321
+ assert_equal 1, @@test.count(:query => {:x => 1})
322
+ assert_equal 1, @@test.count(:limit => 1)
323
+ assert_equal 0, @@test.count(:skip => 2)
281
324
  end
282
325
 
283
326
  # Note: #size is just an alias for #count.
@@ -762,6 +805,41 @@ class TestCollection < Test::Unit::TestCase
762
805
  assert_equal 1, @collection.size
763
806
  end
764
807
  end
808
+
809
+ context "Drop index " do
810
+ setup do
811
+ @@db.drop_collection('test-collection')
812
+ @collection = @@db.collection('test-collection')
813
+ end
814
+
815
+ should "drop an index" do
816
+ @collection.create_index([['a', Mongo::ASCENDING]])
817
+ assert @collection.index_information['a_1']
818
+ @collection.drop_index([['a', Mongo::ASCENDING]])
819
+ assert_nil @collection.index_information['a_1']
820
+ end
821
+
822
+ should "drop an index which was given a specific name" do
823
+ @collection.create_index([['a', Mongo::DESCENDING]], {:name => 'i_will_not_fear'})
824
+ assert @collection.index_information['i_will_not_fear']
825
+ @collection.drop_index([['a', Mongo::DESCENDING]])
826
+ assert_nil @collection.index_information['i_will_not_fear']
827
+ end
828
+
829
+ should "drops an composite index" do
830
+ @collection.create_index([['a', Mongo::DESCENDING], ['b', Mongo::ASCENDING]])
831
+ assert @collection.index_information['a_-1_b_1']
832
+ @collection.drop_index([['a', Mongo::DESCENDING], ['b', Mongo::ASCENDING]])
833
+ assert_nil @collection.index_information['a_-1_b_1']
834
+ end
835
+
836
+ should "drops an index with symbols" do
837
+ @collection.create_index([['a', Mongo::DESCENDING], [:b, Mongo::ASCENDING]])
838
+ assert @collection.index_information['a_-1_b_1']
839
+ @collection.drop_index([['a', Mongo::DESCENDING], [:b, Mongo::ASCENDING]])
840
+ assert_nil @collection.index_information['a_-1_b_1']
841
+ end
842
+ end
765
843
 
766
844
  context "Creating indexes " do
767
845
  setup do
@@ -809,6 +887,14 @@ class TestCollection < Test::Unit::TestCase
809
887
  assert_equal 1, @collection.find({:a => 1}).count
810
888
  end
811
889
 
890
+ should "drop duplicates with ensure_index and drop_dups key" do
891
+ @collection.insert({:a => 1})
892
+ @collection.insert({:a => 1})
893
+ assert_equal 2, @collection.find({:a => 1}).count
894
+ @collection.ensure_index([['a', Mongo::ASCENDING]], :unique => true, :drop_dups => true)
895
+ assert_equal 1, @collection.find({:a => 1}).count
896
+ end
897
+
812
898
  should "create an index in the background" do
813
899
  if @@version > '1.3.1'
814
900
  @collection.create_index([['b', Mongo::ASCENDING]], :background => true)