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
@@ -1,3 +1,17 @@
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
  require 'logger'
3
17
 
@@ -5,15 +19,14 @@ class CursorTest < Test::Unit::TestCase
5
19
  include Mongo
6
20
  include Mongo::Constants
7
21
 
8
- @@connection = standard_connection
9
- @@db = @@connection.db(MONGO_TEST_DB)
10
- @@coll = @@db.collection('test')
11
- @@version = @@connection.server_version
12
-
13
22
  def setup
14
- @@coll.remove
15
- @@coll.insert('a' => 1) # collection not created until it's used
16
- @@coll_full_name = "#{MONGO_TEST_DB}.test"
23
+ @connection = standard_connection
24
+ @db = @connection.db(TEST_DB)
25
+ @coll = @db.collection('test')
26
+ @version = @connection.server_version
27
+ @coll.remove
28
+ @coll.insert('a' => 1) # collection not created until it's used
29
+ @coll_full_name = "#{TEST_DB}.test"
17
30
  end
18
31
 
19
32
  def test_alive
@@ -22,18 +35,18 @@ class CursorTest < Test::Unit::TestCase
22
35
  batch << {:a => n}
23
36
  end
24
37
 
25
- @@coll.insert(batch)
26
- cursor = @@coll.find
38
+ @coll.insert(batch)
39
+ cursor = @coll.find
27
40
  assert !cursor.alive?
28
41
  cursor.next
29
42
  assert cursor.alive?
30
43
  cursor.close
31
44
  assert !cursor.alive?
32
- @@coll.remove
45
+ @coll.remove
33
46
  end
34
47
 
35
48
  def test_add_and_remove_options
36
- c = @@coll.find
49
+ c = @coll.find
37
50
  assert_equal 0, c.options & OP_QUERY_EXHAUST
38
51
  c.add_option(OP_QUERY_EXHAUST)
39
52
  assert_equal OP_QUERY_EXHAUST, c.options & OP_QUERY_EXHAUST
@@ -51,19 +64,19 @@ class CursorTest < Test::Unit::TestCase
51
64
  end
52
65
 
53
66
  def test_exhaust
54
- if @@version >= "2.0"
55
- @@coll.remove
67
+ if @version >= "2.0"
68
+ @coll.remove
56
69
  data = "1" * 10_000
57
70
  5000.times do |n|
58
- @@coll.insert({:n => n, :data => data})
71
+ @coll.insert({:n => n, :data => data})
59
72
  end
60
73
 
61
- c = Cursor.new(@@coll)
74
+ c = Cursor.new(@coll)
62
75
  c.add_option(OP_QUERY_EXHAUST)
63
- assert_equal @@coll.count, c.to_a.size
76
+ assert_equal @coll.count, c.to_a.size
64
77
  assert c.closed?
65
78
 
66
- c = Cursor.new(@@coll)
79
+ c = Cursor.new(@coll)
67
80
  c.add_option(OP_QUERY_EXHAUST)
68
81
  4999.times do
69
82
  c.next
@@ -73,116 +86,185 @@ class CursorTest < Test::Unit::TestCase
73
86
  assert !c.has_next?
74
87
  assert c.closed?
75
88
 
76
- @@coll.remove
89
+ @coll.remove
90
+ end
91
+ end
92
+
93
+ def test_compile_regex_get_more
94
+ return unless defined?(BSON::BSON_RUBY) && BSON::BSON_CODER == BSON::BSON_RUBY
95
+ @coll.remove
96
+ n_docs = 3
97
+ n_docs.times { |n| @coll.insert({ 'n' => /.*/ }) }
98
+ cursor = @coll.find({}, :batch_size => (n_docs-1), :compile_regex => false)
99
+ cursor.expects(:send_get_more)
100
+ cursor.to_a.each do |doc|
101
+ assert_kind_of BSON::Regex, doc['n']
102
+ end
103
+ end
104
+
105
+ def test_max_time_ms_error
106
+ cursor = @coll.find
107
+ cursor.stubs(:send_initial_query).returns(true)
108
+
109
+ cursor.instance_variable_set(:@cache, [{
110
+ '$err' => 'operation exceeded time limit',
111
+ 'code' => 50
112
+ }])
113
+
114
+ assert_raise ExecutionTimeout do
115
+ cursor.to_a
116
+ end
117
+ end
118
+
119
+ def test_max_time_ms
120
+ with_forced_timeout(@connection) do
121
+ assert_raise ExecutionTimeout do
122
+ cursor = @coll.find.max_time_ms(100)
123
+ cursor.to_a
124
+ end
125
+ end
126
+ end
127
+
128
+ def test_exhaust_after_limit_error
129
+ c = Cursor.new(@coll, :limit => 17)
130
+ assert_raise MongoArgumentError do
131
+ c.add_option(OP_QUERY_EXHAUST)
132
+ end
133
+
134
+ assert_raise MongoArgumentError do
135
+ c.add_option(OP_QUERY_EXHAUST + OP_QUERY_SLAVE_OK)
136
+ end
137
+ end
138
+
139
+ def test_limit_after_exhaust_error
140
+ c = Cursor.new(@coll)
141
+ c.add_option(OP_QUERY_EXHAUST)
142
+ assert_raise MongoArgumentError do
143
+ c.limit(17)
144
+ end
145
+ end
146
+
147
+ def test_exhaust_with_mongos
148
+ @connection.expects(:mongos?).returns(:true)
149
+ c = Cursor.new(@coll)
150
+
151
+ assert_raise MongoArgumentError do
152
+ c.add_option(OP_QUERY_EXHAUST)
77
153
  end
78
154
  end
79
155
 
80
156
  def test_inspect
81
157
  selector = {:a => 1}
82
- cursor = @@coll.find(selector)
83
- assert_equal "<Mongo::Cursor:0x#{cursor.object_id.to_s(16)} namespace='#{@@db.name}.#{@@coll.name}' " +
84
- "@selector=#{selector.inspect} @cursor_id=#{cursor.cursor_id}>", cursor.inspect
158
+ cursor = @coll.find(selector)
159
+ assert_equal "<Mongo::Cursor:0x#{cursor.object_id.to_s(16)} namespace='#{@db.name}.#{@coll.name}' " +
160
+ "@selector=#{selector.inspect} @cursor_id=#{cursor.cursor_id}>", cursor.inspect
85
161
  end
86
162
 
87
163
  def test_explain
88
- cursor = @@coll.find('a' => 1)
89
- explaination = cursor.explain
90
- assert_not_nil explaination['cursor']
91
- assert_kind_of Numeric, explaination['n']
92
- assert_kind_of Numeric, explaination['millis']
93
- assert_kind_of Numeric, explaination['nscanned']
164
+ cursor = @coll.find('a' => 1)
165
+ explanation = cursor.explain
166
+ if @version < '2.7'
167
+ assert_not_nil explanation['cursor']
168
+ assert_kind_of Numeric, explanation['n']
169
+ assert_kind_of Numeric, explanation['millis']
170
+ assert_kind_of Numeric, explanation['nscanned']
171
+ else
172
+ cursor = @coll.find('a' => 1)
173
+ assert_not_nil explanation
174
+ assert explanation.keys.include?('executionStats')
175
+ end
94
176
  end
95
177
 
96
178
  def test_each_with_no_block
97
- assert_kind_of(Enumerator, @@coll.find().each) if defined? Enumerator
179
+ assert_kind_of(Enumerator, @coll.find().each) if defined? Enumerator
98
180
  end
99
181
 
100
182
  def test_count
101
- @@coll.remove
183
+ @coll.remove
102
184
 
103
- assert_equal 0, @@coll.find().count()
185
+ assert_equal 0, @coll.find().count()
104
186
 
105
187
  10.times do |i|
106
- @@coll.save("x" => i)
188
+ @coll.save("x" => i)
107
189
  end
108
190
 
109
- assert_equal 10, @@coll.find().count()
110
- assert_kind_of Integer, @@coll.find().count()
111
- assert_equal 10, @@coll.find({}, :limit => 5).count()
112
- assert_equal 10, @@coll.find({}, :skip => 5).count()
191
+ assert_equal 10, @coll.find().count()
192
+ assert_kind_of Integer, @coll.find().count()
193
+ assert_equal 10, @coll.find({}, :limit => 5).count()
194
+ assert_equal 10, @coll.find({}, :skip => 5).count()
113
195
 
114
- assert_equal 5, @@coll.find({}, :limit => 5).count(true)
115
- assert_equal 5, @@coll.find({}, :skip => 5).count(true)
116
- assert_equal 2, @@coll.find({}, :skip => 5, :limit => 2).count(true)
196
+ assert_equal 5, @coll.find({}, :limit => 5).count(true)
197
+ assert_equal 5, @coll.find({}, :skip => 5).count(true)
198
+ assert_equal 2, @coll.find({}, :skip => 5, :limit => 2).count(true)
117
199
 
118
- assert_equal 1, @@coll.find({"x" => 1}).count()
119
- assert_equal 5, @@coll.find({"x" => {"$lt" => 5}}).count()
200
+ assert_equal 1, @coll.find({"x" => 1}).count()
201
+ assert_equal 5, @coll.find({"x" => {"$lt" => 5}}).count()
120
202
 
121
- a = @@coll.find()
203
+ a = @coll.find()
122
204
  b = a.count()
123
205
  a.each do |doc|
124
206
  break
125
207
  end
126
208
  assert_equal b, a.count()
127
209
 
128
- assert_equal 0, @@db['acollectionthatdoesn'].count()
210
+ assert_equal 0, @db['acollectionthatdoesn'].count()
129
211
  end
130
212
 
131
213
  def test_sort
132
- @@coll.remove
133
- 5.times{|x| @@coll.insert({"age" => x}) }
214
+ @coll.remove
215
+ 5.times{|x| @coll.insert({"age" => x}) }
134
216
 
135
- assert_kind_of Cursor, @@coll.find().sort(:age, 1)
217
+ assert_kind_of Cursor, @coll.find().sort(:age, 1)
136
218
 
137
- assert_equal 0, @@coll.find().sort(:age, 1).next_document["age"]
138
- assert_equal 4, @@coll.find().sort(:age, -1).next_document["age"]
139
- assert_equal 0, @@coll.find().sort([["age", :asc]]).next_document["age"]
219
+ assert_equal 0, @coll.find().sort(:age, 1).next_document["age"]
220
+ assert_equal 4, @coll.find().sort(:age, -1).next_document["age"]
221
+ assert_equal 0, @coll.find().sort([["age", :asc]]).next_document["age"]
140
222
 
141
- assert_kind_of Cursor, @@coll.find().sort([[:age, -1], [:b, 1]])
223
+ assert_kind_of Cursor, @coll.find().sort([[:age, -1], [:b, 1]])
142
224
 
143
- assert_equal 4, @@coll.find().sort(:age, 1).sort(:age, -1).next_document["age"]
144
- assert_equal 0, @@coll.find().sort(:age, -1).sort(:age, 1).next_document["age"]
225
+ assert_equal 4, @coll.find().sort(:age, 1).sort(:age, -1).next_document["age"]
226
+ assert_equal 0, @coll.find().sort(:age, -1).sort(:age, 1).next_document["age"]
145
227
 
146
- assert_equal 4, @@coll.find().sort([:age, :asc]).sort(:age, -1).next_document["age"]
147
- assert_equal 0, @@coll.find().sort([:age, :desc]).sort(:age, 1).next_document["age"]
228
+ assert_equal 4, @coll.find().sort([:age, :asc]).sort(:age, -1).next_document["age"]
229
+ assert_equal 0, @coll.find().sort([:age, :desc]).sort(:age, 1).next_document["age"]
148
230
 
149
- cursor = @@coll.find()
231
+ cursor = @coll.find()
150
232
  cursor.next_document
151
233
  assert_raise InvalidOperation do
152
234
  cursor.sort(["age"])
153
235
  end
154
236
 
155
237
  assert_raise InvalidSortValueError do
156
- @@coll.find().sort(:age, 25).next_document
238
+ @coll.find().sort(:age, 25).next_document
157
239
  end
158
240
 
159
241
  assert_raise InvalidSortValueError do
160
- @@coll.find().sort(25).next_document
242
+ @coll.find().sort(25).next_document
161
243
  end
162
244
  end
163
245
 
164
246
  def test_sort_date
165
- @@coll.remove
166
- 5.times{|x| @@coll.insert({"created_at" => Time.utc(2000 + x)}) }
247
+ @coll.remove
248
+ 5.times{|x| @coll.insert({"created_at" => Time.utc(2000 + x)}) }
167
249
 
168
- assert_equal 2000, @@coll.find().sort(:created_at, :asc).next_document["created_at"].year
169
- assert_equal 2004, @@coll.find().sort(:created_at, :desc).next_document["created_at"].year
250
+ assert_equal 2000, @coll.find().sort(:created_at, :asc).next_document["created_at"].year
251
+ assert_equal 2004, @coll.find().sort(:created_at, :desc).next_document["created_at"].year
170
252
 
171
- assert_equal 2000, @@coll.find().sort([:created_at, :asc]).next_document["created_at"].year
172
- assert_equal 2004, @@coll.find().sort([:created_at, :desc]).next_document["created_at"].year
253
+ assert_equal 2000, @coll.find().sort([:created_at, :asc]).next_document["created_at"].year
254
+ assert_equal 2004, @coll.find().sort([:created_at, :desc]).next_document["created_at"].year
173
255
 
174
- assert_equal 2000, @@coll.find().sort([[:created_at, :asc]]).next_document["created_at"].year
175
- assert_equal 2004, @@coll.find().sort([[:created_at, :desc]]).next_document["created_at"].year
256
+ assert_equal 2000, @coll.find().sort([[:created_at, :asc]]).next_document["created_at"].year
257
+ assert_equal 2004, @coll.find().sort([[:created_at, :desc]]).next_document["created_at"].year
176
258
  end
177
259
 
178
260
  def test_sort_min_max_keys
179
- @@coll.remove
180
- @@coll.insert({"n" => 1000000})
181
- @@coll.insert({"n" => -1000000})
182
- @@coll.insert({"n" => MaxKey.new})
183
- @@coll.insert({"n" => MinKey.new})
261
+ @coll.remove
262
+ @coll.insert({"n" => 1000000})
263
+ @coll.insert({"n" => -1000000})
264
+ @coll.insert({"n" => MaxKey.new})
265
+ @coll.insert({"n" => MinKey.new})
184
266
 
185
- results = @@coll.find.sort([:n, :asc]).to_a
267
+ results = @coll.find.sort([:n, :asc]).to_a
186
268
 
187
269
  assert_equal MinKey.new, results[0]['n']
188
270
  assert_equal(-1000000, results[1]['n'])
@@ -191,73 +273,73 @@ class CursorTest < Test::Unit::TestCase
191
273
  end
192
274
 
193
275
  def test_id_range_queries
194
- @@coll.remove
276
+ @coll.remove
195
277
 
196
278
  t1 = Time.now
197
279
  t1_id = ObjectId.from_time(t1)
198
- @@coll.save({:t => 't1'})
199
- @@coll.save({:t => 't1'})
200
- @@coll.save({:t => 't1'})
201
- sleep(2)
280
+ @coll.save({:t => 't1'})
281
+ @coll.save({:t => 't1'})
282
+ @coll.save({:t => 't1'})
283
+ sleep(1)
202
284
  t2 = Time.now
203
285
  t2_id = ObjectId.from_time(t2)
204
- @@coll.save({:t => 't2'})
205
- @@coll.save({:t => 't2'})
206
- @@coll.save({:t => 't2'})
286
+ @coll.save({:t => 't2'})
287
+ @coll.save({:t => 't2'})
288
+ @coll.save({:t => 't2'})
207
289
 
208
- assert_equal 3, @@coll.find({'_id' => {'$gt' => t1_id, '$lt' => t2_id}}).count
209
- @@coll.find({'_id' => {'$gt' => t2_id}}).each do |doc|
290
+ assert_equal 3, @coll.find({'_id' => {'$gt' => t1_id, '$lt' => t2_id}}).count
291
+ @coll.find({'_id' => {'$gt' => t2_id}}).each do |doc|
210
292
  assert_equal 't2', doc['t']
211
293
  end
212
294
  end
213
295
 
214
296
  def test_limit
215
- @@coll.remove
297
+ @coll.remove
216
298
 
217
299
  10.times do |i|
218
- @@coll.save("x" => i)
300
+ @coll.save("x" => i)
219
301
  end
220
- assert_equal 10, @@coll.find().count()
302
+ assert_equal 10, @coll.find().count()
221
303
 
222
- results = @@coll.find().limit(5).to_a
304
+ results = @coll.find().limit(5).to_a
223
305
  assert_equal 5, results.length
224
306
  end
225
307
 
226
308
  def test_timeout_options
227
- cursor = Cursor.new(@@coll)
309
+ cursor = Cursor.new(@coll)
228
310
  assert_equal true, cursor.timeout
229
311
 
230
- cursor = @@coll.find
312
+ cursor = @coll.find
231
313
  assert_equal true, cursor.timeout
232
314
 
233
- cursor = @@coll.find({}, :timeout => nil)
315
+ cursor = @coll.find({}, :timeout => nil)
234
316
  assert_equal true, cursor.timeout
235
317
 
236
- cursor = Cursor.new(@@coll, :timeout => false)
318
+ cursor = Cursor.new(@coll, :timeout => false)
237
319
  assert_equal false, cursor.timeout
238
320
 
239
- @@coll.find({}, :timeout => false) do |c|
321
+ @coll.find({}, :timeout => false) do |c|
240
322
  assert_equal false, c.timeout
241
323
  end
242
324
  end
243
325
 
244
326
  def test_timeout
245
- opts = Cursor.new(@@coll).options
327
+ opts = Cursor.new(@coll).options
246
328
  assert_equal 0, opts & Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT
247
329
 
248
- opts = Cursor.new(@@coll, :timeout => false).options
330
+ opts = Cursor.new(@coll, :timeout => false).options
249
331
  assert_equal Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT,
250
- opts & Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT
332
+ opts & Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT
251
333
  end
252
334
 
253
335
  def test_limit_exceptions
254
- cursor = @@coll.find()
336
+ cursor = @coll.find()
255
337
  cursor.next_document
256
338
  assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do
257
339
  cursor.limit(1)
258
340
  end
259
341
 
260
- cursor = @@coll.find()
342
+ cursor = @coll.find()
261
343
  cursor.close
262
344
  assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do
263
345
  cursor.limit(1)
@@ -265,15 +347,15 @@ class CursorTest < Test::Unit::TestCase
265
347
  end
266
348
 
267
349
  def test_skip
268
- @@coll.remove
350
+ @coll.remove
269
351
 
270
352
  10.times do |i|
271
- @@coll.save("x" => i)
353
+ @coll.save("x" => i)
272
354
  end
273
- assert_equal 10, @@coll.find().count()
355
+ assert_equal 10, @coll.find().count()
274
356
 
275
- all_results = @@coll.find().to_a
276
- skip_results = @@coll.find().skip(2).to_a
357
+ all_results = @coll.find().to_a
358
+ skip_results = @coll.find().skip(2).to_a
277
359
  assert_equal 10, all_results.length
278
360
  assert_equal 8, skip_results.length
279
361
 
@@ -281,13 +363,13 @@ class CursorTest < Test::Unit::TestCase
281
363
  end
282
364
 
283
365
  def test_skip_exceptions
284
- cursor = @@coll.find()
366
+ cursor = @coll.find()
285
367
  cursor.next_document
286
368
  assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do
287
369
  cursor.skip(1)
288
370
  end
289
371
 
290
- cursor = @@coll.find()
372
+ cursor = @coll.find()
291
373
  cursor.close
292
374
  assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do
293
375
  cursor.skip(1)
@@ -295,20 +377,20 @@ class CursorTest < Test::Unit::TestCase
295
377
  end
296
378
 
297
379
  def test_limit_skip_chaining
298
- @@coll.remove
380
+ @coll.remove
299
381
  10.times do |i|
300
- @@coll.save("x" => i)
382
+ @coll.save("x" => i)
301
383
  end
302
384
 
303
- all_results = @@coll.find().to_a
304
- limited_skip_results = @@coll.find().limit(5).skip(3).to_a
385
+ all_results = @coll.find().to_a
386
+ limited_skip_results = @coll.find().limit(5).skip(3).to_a
305
387
 
306
388
  assert_equal all_results.slice(3...8), limited_skip_results
307
389
  end
308
390
 
309
391
  def test_close_no_query_sent
310
392
  begin
311
- cursor = @@coll.find('a' => 1)
393
+ cursor = @coll.find('a' => 1)
312
394
  cursor.close
313
395
  assert cursor.closed?
314
396
  rescue => ex
@@ -317,33 +399,33 @@ class CursorTest < Test::Unit::TestCase
317
399
  end
318
400
 
319
401
  def test_refill_via_get_more
320
- assert_equal 1, @@coll.count
402
+ assert_equal 1, @coll.count
321
403
  1000.times { |i|
322
- assert_equal 1 + i, @@coll.count
323
- @@coll.insert('a' => i)
404
+ assert_equal 1 + i, @coll.count
405
+ @coll.insert('a' => i)
324
406
  }
325
407
 
326
- assert_equal 1001, @@coll.count
408
+ assert_equal 1001, @coll.count
327
409
  count = 0
328
- @@coll.find.each { |obj|
410
+ @coll.find.each { |obj|
329
411
  count += obj['a']
330
412
  }
331
- assert_equal 1001, @@coll.count
413
+ assert_equal 1001, @coll.count
332
414
 
333
415
  # do the same thing again for debugging
334
- assert_equal 1001, @@coll.count
416
+ assert_equal 1001, @coll.count
335
417
  count2 = 0
336
- @@coll.find.each { |obj|
418
+ @coll.find.each { |obj|
337
419
  count2 += obj['a']
338
420
  }
339
- assert_equal 1001, @@coll.count
421
+ assert_equal 1001, @coll.count
340
422
 
341
423
  assert_equal count, count2
342
424
  assert_equal 499501, count
343
425
  end
344
426
 
345
427
  def test_refill_via_get_more_alt_coll
346
- coll = @@db.collection('test-alt-coll')
428
+ coll = @db.collection('test-alt-coll')
347
429
  coll.remove
348
430
  coll.insert('a' => 1) # collection not created until it's used
349
431
  assert_equal 1, coll.count
@@ -374,7 +456,7 @@ class CursorTest < Test::Unit::TestCase
374
456
 
375
457
  def test_close_after_query_sent
376
458
  begin
377
- cursor = @@coll.find('a' => 1)
459
+ cursor = @coll.find('a' => 1)
378
460
  cursor.next_document
379
461
  cursor.close
380
462
  assert cursor.closed?
@@ -384,82 +466,127 @@ class CursorTest < Test::Unit::TestCase
384
466
  end
385
467
 
386
468
  def test_kill_cursors
387
- @@coll.drop
469
+ @coll.drop
388
470
 
389
- client_cursors = @@db.command("cursorInfo" => 1)["clientCursors_size"]
471
+ client_cursors = cursor_count(@db)
390
472
 
391
473
  10000.times do |i|
392
- @@coll.insert("i" => i)
474
+ @coll.insert("i" => i)
393
475
  end
394
476
 
395
- assert_equal(client_cursors,
396
- @@db.command("cursorInfo" => 1)["clientCursors_size"])
477
+ assert_equal(client_cursors, cursor_count(@db))
397
478
 
398
479
  10.times do |i|
399
- @@coll.find_one()
480
+ @coll.find_one()
400
481
  end
401
482
 
402
- assert_equal(client_cursors,
403
- @@db.command("cursorInfo" => 1)["clientCursors_size"])
483
+ assert_equal(client_cursors, cursor_count(@db))
404
484
 
405
485
  10.times do |i|
406
- a = @@coll.find()
486
+ a = @coll.find()
407
487
  a.next_document
408
488
  a.close()
409
489
  end
410
490
 
411
- assert_equal(client_cursors,
412
- @@db.command("cursorInfo" => 1)["clientCursors_size"])
491
+ assert_equal(client_cursors, cursor_count(@db))
413
492
 
414
- a = @@coll.find()
493
+ a = @coll.find()
415
494
  a.next_document
416
495
 
417
- assert_not_equal(client_cursors,
418
- @@db.command("cursorInfo" => 1)["clientCursors_size"])
496
+ assert_not_equal(client_cursors, cursor_count(@db))
419
497
 
420
498
  a.close()
421
499
 
422
- assert_equal(client_cursors,
423
- @@db.command("cursorInfo" => 1)["clientCursors_size"])
500
+ assert_equal(client_cursors, cursor_count(@db))
424
501
 
425
- a = @@coll.find({}, :limit => 10).next_document
502
+ a = @coll.find({}, :limit => 10).next_document
426
503
 
427
- assert_equal(client_cursors,
428
- @@db.command("cursorInfo" => 1)["clientCursors_size"])
504
+ assert_equal(client_cursors, cursor_count(@db))
429
505
 
430
- @@coll.find() do |cursor|
506
+ @coll.find() do |cursor|
431
507
  cursor.next_document
432
508
  end
433
509
 
434
- assert_equal(client_cursors,
435
- @@db.command("cursorInfo" => 1)["clientCursors_size"])
510
+ assert_equal(client_cursors, cursor_count(@db))
436
511
 
437
- @@coll.find() { |cursor|
512
+ @coll.find() { |cursor|
438
513
  cursor.next_document
439
514
  }
440
515
 
441
- assert_equal(client_cursors,
442
- @@db.command("cursorInfo" => 1)["clientCursors_size"])
516
+ assert_equal(client_cursors, cursor_count(@db))
443
517
  end
444
518
 
445
519
  def test_count_with_fields
446
- @@coll.remove
447
- @@coll.save("x" => 1)
520
+ @coll.remove
521
+ @coll.save("x" => 1)
522
+
523
+ if @version < "1.1.3"
524
+ assert_equal(0, @coll.find({}, :fields => ["a"]).count())
525
+ else
526
+ assert_equal(1, @coll.find({}, :fields => ["a"]).count())
527
+ end
528
+ end
529
+
530
+ def test_count_with_hint
531
+ @coll.drop
532
+ @coll.save(:i => 1)
533
+ @coll.save(:i => 2)
534
+ assert_equal 2, @coll.find.count
535
+
536
+ @coll.ensure_index(BSON::OrderedHash[:i, Mongo::ASCENDING])
537
+
538
+ # Check that a named_hint can be specified
539
+ assert_equal 1, @coll.find({ :i => 1 }, :named_hint => '_id_').count
540
+ assert_equal 2, @coll.find({ }, :named_hint => '_id_').count
541
+
542
+ # Verify that the hint is being sent to the server by providing a bad hint
543
+ if @version > '2.6'
544
+ assert_raise Mongo::OperationFailure do
545
+ @coll.find({ :i => 1 }, :hint => 'bad_hint').count
546
+ end
547
+ else
548
+ assert_equal 1, @coll.find({ :i => 1 }, :hint => 'bad_hint').count
549
+ end
448
550
 
449
- if @@version < "1.1.3"
450
- assert_equal(0, @@coll.find({}, :fields => ["a"]).count())
551
+ # Verify that the named_hint is being sent to the server by providing a bad hint
552
+ if @version > '2.6'
553
+ assert_raise Mongo::OperationFailure do
554
+ @coll.find({ :i => 1 }, :named_hint => 'bad_hint').count
555
+ end
451
556
  else
452
- assert_equal(1, @@coll.find({}, :fields => ["a"]).count())
557
+ assert_equal 1, @coll.find({ :i => 1 }, :named_hint => 'bad_hint').count
453
558
  end
559
+
560
+ @coll.ensure_index(BSON::OrderedHash[:x, Mongo::ASCENDING], :sparse => true)
561
+
562
+ # The sparse index won't have any entries.
563
+ # Check that count returns 0 when using the hint.
564
+ expected = @version > '2.6' ? 0 : 1
565
+ assert_equal expected, @coll.find({ :i => 1 }, :hint => { 'x' => 1 }).count
566
+ assert_equal expected, @coll.find({ :i => 1 }, :hint => 'x').count
567
+ assert_equal expected, @coll.find({ :i => 1 }, :named_hint => 'x_1').count
568
+
569
+ # Verify that the hint / named hint set on the collection is used.
570
+ @coll.hint = { 'x' => 1 }
571
+ assert_equal expected, @coll.find(:i => 1).count
572
+
573
+ @coll.hint = 'x'
574
+ assert_equal expected, @coll.find(:i => 1).count
575
+
576
+ @coll.named_hint = 'x_1'
577
+ assert_equal expected, @coll.find(:i => 1).count
578
+
579
+ assert_equal 2, @coll.find({ }, :hint => 'x').count
580
+ assert_equal 2, @coll.find({ }, :named_hint => 'x_1').count
454
581
  end
455
582
 
456
583
  def test_has_next
457
- @@coll.remove
584
+ @coll.remove
458
585
  200.times do |n|
459
- @@coll.save("x" => n)
586
+ @coll.save("x" => n)
460
587
  end
461
588
 
462
- cursor = @@coll.find
589
+ cursor = @coll.find
463
590
  n = 0
464
591
  while cursor.has_next?
465
592
  assert cursor.next
@@ -471,12 +598,12 @@ class CursorTest < Test::Unit::TestCase
471
598
  end
472
599
 
473
600
  def test_cursor_invalid
474
- @@coll.remove
601
+ @coll.remove
475
602
  10000.times do |n|
476
- @@coll.insert({:a => n})
603
+ @coll.insert({:a => n})
477
604
  end
478
605
 
479
- cursor = @@coll.find({})
606
+ cursor = @coll.find({})
480
607
 
481
608
  assert_raise_error Mongo::OperationFailure, "CURSOR_NOT_FOUND" do
482
609
  9999.times do
@@ -487,26 +614,26 @@ class CursorTest < Test::Unit::TestCase
487
614
  end
488
615
 
489
616
  def test_enumberables
490
- @@coll.remove
617
+ @coll.remove
491
618
  100.times do |n|
492
- @@coll.insert({:a => n})
619
+ @coll.insert({:a => n})
493
620
  end
494
621
 
495
- assert_equal 100, @@coll.find.to_a.length
496
- assert_equal 100, @@coll.find.to_set.length
622
+ assert_equal 100, @coll.find.to_a.length
623
+ assert_equal 100, @coll.find.to_set.length
497
624
 
498
- cursor = @@coll.find
625
+ cursor = @coll.find
499
626
  50.times { |n| cursor.next_document }
500
627
  assert_equal 50, cursor.to_a.length
501
628
  end
502
629
 
503
630
  def test_rewind
504
- @@coll.remove
631
+ @coll.remove
505
632
  100.times do |n|
506
- @@coll.insert({:a => n})
633
+ @coll.insert({:a => n})
507
634
  end
508
635
 
509
- cursor = @@coll.find
636
+ cursor = @coll.find
510
637
  cursor.to_a
511
638
  assert_equal [], cursor.map {|doc| doc }
512
639
 
@@ -521,14 +648,14 @@ class CursorTest < Test::Unit::TestCase
521
648
 
522
649
  def test_transformer
523
650
  transformer = Proc.new { |doc| doc }
524
- cursor = Cursor.new(@@coll, :transformer => transformer)
651
+ cursor = Cursor.new(@coll, :transformer => transformer)
525
652
  assert_equal(transformer, cursor.transformer)
526
653
  end
527
654
 
528
655
  def test_instance_transformation_with_next
529
656
  klass = Struct.new(:id, :a)
530
657
  transformer = Proc.new { |doc| klass.new(doc['_id'], doc['a']) }
531
- cursor = Cursor.new(@@coll, :transformer => transformer)
658
+ cursor = Cursor.new(@coll, :transformer => transformer)
532
659
  instance = cursor.next
533
660
 
534
661
  assert_instance_of(klass, instance)
@@ -539,10 +666,18 @@ class CursorTest < Test::Unit::TestCase
539
666
  def test_instance_transformation_with_each
540
667
  klass = Struct.new(:id, :a)
541
668
  transformer = Proc.new { |doc| klass.new(doc['_id'], doc['a']) }
542
- cursor = Cursor.new(@@coll, :transformer => transformer)
669
+ cursor = Cursor.new(@coll, :transformer => transformer)
543
670
 
544
671
  cursor.each do |instance|
545
672
  assert_instance_of(klass, instance)
546
673
  end
547
674
  end
675
+
676
+ def cursor_count(db)
677
+ if @version > '2.6.0'
678
+ db.command("serverStatus" => 1)["metrics"]["cursor"]["open"]["total"]
679
+ else
680
+ db.command("cursorInfo" => 1)["clientCursors_size"]
681
+ end
682
+ end
548
683
  end