mongo 1.3.0 → 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 (185) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/{LICENSE.txt → LICENSE} +1 -1
  4. data/README.md +122 -271
  5. data/Rakefile +25 -209
  6. data/VERSION +1 -0
  7. data/bin/mongo_console +31 -9
  8. data/lib/mongo/bulk_write_collection_view.rb +387 -0
  9. data/lib/mongo/collection.rb +576 -269
  10. data/lib/mongo/collection_writer.rb +364 -0
  11. data/lib/mongo/connection/node.rb +249 -0
  12. data/lib/mongo/connection/pool.rb +340 -0
  13. data/lib/mongo/connection/pool_manager.rb +320 -0
  14. data/lib/mongo/connection/sharding_pool_manager.rb +67 -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 +7 -875
  21. data/lib/mongo/cursor.rb +403 -117
  22. data/lib/mongo/db.rb +444 -243
  23. data/lib/mongo/exception.rb +145 -0
  24. data/lib/mongo/functional/authentication.rb +455 -0
  25. data/lib/mongo/functional/logging.rb +85 -0
  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/functional/write_concern.rb +66 -0
  30. data/lib/mongo/functional.rb +20 -0
  31. data/lib/mongo/gridfs/grid.rb +30 -24
  32. data/lib/mongo/gridfs/grid_ext.rb +6 -10
  33. data/lib/mongo/gridfs/grid_file_system.rb +38 -20
  34. data/lib/mongo/gridfs/grid_io.rb +84 -75
  35. data/lib/mongo/gridfs.rb +18 -0
  36. data/lib/mongo/legacy.rb +140 -0
  37. data/lib/mongo/mongo_client.rb +697 -0
  38. data/lib/mongo/mongo_replica_set_client.rb +535 -0
  39. data/lib/mongo/mongo_sharded_client.rb +159 -0
  40. data/lib/mongo/networking.rb +372 -0
  41. data/lib/mongo/{util → utils}/conversions.rb +29 -8
  42. data/lib/mongo/{util → utils}/core_ext.rb +28 -18
  43. data/lib/mongo/{util → utils}/server_version.rb +4 -6
  44. data/lib/mongo/{util → utils}/support.rb +29 -31
  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 +51 -50
  48. data/mongo.gemspec +29 -32
  49. data/test/functional/authentication_test.rb +39 -0
  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 +2175 -0
  54. data/test/functional/collection_writer_test.rb +83 -0
  55. data/test/{conversions_test.rb → functional/conversions_test.rb} +47 -3
  56. data/test/functional/cursor_fail_test.rb +57 -0
  57. data/test/functional/cursor_message_test.rb +56 -0
  58. data/test/functional/cursor_test.rb +683 -0
  59. data/test/functional/db_api_test.rb +835 -0
  60. data/test/functional/db_connection_test.rb +25 -0
  61. data/test/functional/db_test.rb +348 -0
  62. data/test/functional/grid_file_system_test.rb +285 -0
  63. data/test/{grid_io_test.rb → functional/grid_io_test.rb} +72 -11
  64. data/test/{grid_test.rb → functional/grid_test.rb} +88 -15
  65. data/test/functional/pool_test.rb +136 -0
  66. data/test/functional/safe_test.rb +98 -0
  67. data/test/functional/ssl_test.rb +29 -0
  68. data/test/functional/support_test.rb +62 -0
  69. data/test/functional/timeout_test.rb +60 -0
  70. data/test/functional/uri_test.rb +446 -0
  71. data/test/functional/write_concern_test.rb +118 -0
  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 +37 -0
  75. data/test/replica_set/basic_test.rb +189 -0
  76. data/test/replica_set/client_test.rb +393 -0
  77. data/test/replica_set/connection_test.rb +138 -0
  78. data/test/replica_set/count_test.rb +66 -0
  79. data/test/replica_set/cursor_test.rb +220 -0
  80. data/test/replica_set/insert_test.rb +157 -0
  81. data/test/replica_set/max_values_test.rb +151 -0
  82. data/test/replica_set/pinning_test.rb +105 -0
  83. data/test/replica_set/query_test.rb +73 -0
  84. data/test/replica_set/read_preference_test.rb +219 -0
  85. data/test/replica_set/refresh_test.rb +211 -0
  86. data/test/replica_set/replication_ack_test.rb +95 -0
  87. data/test/replica_set/ssl_test.rb +32 -0
  88. data/test/sharded_cluster/basic_test.rb +203 -0
  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 +53 -94
  96. data/test/threading/basic_test.rb +120 -0
  97. data/test/tools/mongo_config.rb +708 -0
  98. data/test/tools/mongo_config_test.rb +160 -0
  99. data/test/unit/client_test.rb +381 -0
  100. data/test/unit/collection_test.rb +89 -53
  101. data/test/unit/connection_test.rb +282 -32
  102. data/test/unit/cursor_test.rb +206 -8
  103. data/test/unit/db_test.rb +55 -13
  104. data/test/unit/grid_test.rb +43 -16
  105. data/test/unit/mongo_sharded_client_test.rb +48 -0
  106. data/test/unit/node_test.rb +93 -0
  107. data/test/unit/pool_manager_test.rb +111 -0
  108. data/test/unit/read_pref_test.rb +406 -0
  109. data/test/unit/read_test.rb +159 -0
  110. data/test/unit/safe_test.rb +69 -36
  111. data/test/unit/sharding_pool_manager_test.rb +84 -0
  112. data/test/unit/write_concern_test.rb +175 -0
  113. data.tar.gz.sig +3 -0
  114. metadata +227 -216
  115. metadata.gz.sig +0 -0
  116. data/docs/CREDITS.md +0 -123
  117. data/docs/FAQ.md +0 -116
  118. data/docs/GridFS.md +0 -158
  119. data/docs/HISTORY.md +0 -244
  120. data/docs/RELEASES.md +0 -33
  121. data/docs/REPLICA_SETS.md +0 -72
  122. data/docs/TUTORIAL.md +0 -247
  123. data/docs/WRITE_CONCERN.md +0 -28
  124. data/lib/mongo/exceptions.rb +0 -71
  125. data/lib/mongo/gridfs/grid_io_fix.rb +0 -38
  126. data/lib/mongo/repl_set_connection.rb +0 -342
  127. data/lib/mongo/test.rb +0 -20
  128. data/lib/mongo/util/pool.rb +0 -177
  129. data/lib/mongo/util/uri_parser.rb +0 -185
  130. data/test/async/collection_test.rb +0 -224
  131. data/test/async/connection_test.rb +0 -24
  132. data/test/async/cursor_test.rb +0 -162
  133. data/test/async/worker_pool_test.rb +0 -99
  134. data/test/auxillary/1.4_features.rb +0 -166
  135. data/test/auxillary/authentication_test.rb +0 -68
  136. data/test/auxillary/autoreconnect_test.rb +0 -41
  137. data/test/auxillary/fork_test.rb +0 -30
  138. data/test/auxillary/repl_set_auth_test.rb +0 -58
  139. data/test/auxillary/slave_connection_test.rb +0 -36
  140. data/test/auxillary/threaded_authentication_test.rb +0 -101
  141. data/test/bson/binary_test.rb +0 -15
  142. data/test/bson/bson_test.rb +0 -649
  143. data/test/bson/byte_buffer_test.rb +0 -208
  144. data/test/bson/hash_with_indifferent_access_test.rb +0 -38
  145. data/test/bson/json_test.rb +0 -17
  146. data/test/bson/object_id_test.rb +0 -154
  147. data/test/bson/ordered_hash_test.rb +0 -204
  148. data/test/bson/timestamp_test.rb +0 -24
  149. data/test/collection_test.rb +0 -910
  150. data/test/connection_test.rb +0 -309
  151. data/test/cursor_fail_test.rb +0 -75
  152. data/test/cursor_message_test.rb +0 -43
  153. data/test/cursor_test.rb +0 -483
  154. data/test/db_api_test.rb +0 -726
  155. data/test/db_connection_test.rb +0 -15
  156. data/test/db_test.rb +0 -287
  157. data/test/grid_file_system_test.rb +0 -243
  158. data/test/load/resque/load.rb +0 -21
  159. data/test/load/resque/processor.rb +0 -26
  160. data/test/load/thin/load.rb +0 -24
  161. data/test/load/unicorn/load.rb +0 -23
  162. data/test/load/unicorn/unicorn.rb +0 -29
  163. data/test/replica_sets/connect_test.rb +0 -94
  164. data/test/replica_sets/connection_string_test.rb +0 -32
  165. data/test/replica_sets/count_test.rb +0 -35
  166. data/test/replica_sets/insert_test.rb +0 -53
  167. data/test/replica_sets/pooled_insert_test.rb +0 -55
  168. data/test/replica_sets/query_secondaries.rb +0 -96
  169. data/test/replica_sets/query_test.rb +0 -51
  170. data/test/replica_sets/replication_ack_test.rb +0 -66
  171. data/test/replica_sets/rs_test_helper.rb +0 -27
  172. data/test/safe_test.rb +0 -68
  173. data/test/support/hash_with_indifferent_access.rb +0 -186
  174. data/test/support/keys.rb +0 -45
  175. data/test/support_test.rb +0 -18
  176. data/test/threading/threading_with_large_pool_test.rb +0 -90
  177. data/test/threading_test.rb +0 -87
  178. data/test/tools/auth_repl_set_manager.rb +0 -14
  179. data/test/tools/load.rb +0 -58
  180. data/test/tools/repl_set_manager.rb +0 -266
  181. data/test/tools/sharding_manager.rb +0 -202
  182. data/test/tools/test.rb +0 -4
  183. data/test/unit/pool_test.rb +0 -9
  184. data/test/unit/repl_set_connection_test.rb +0 -59
  185. data/test/uri_test.rb +0 -91
@@ -0,0 +1,683 @@
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'test_helper'
16
+ require 'logger'
17
+
18
+ class CursorTest < Test::Unit::TestCase
19
+ include Mongo
20
+ include Mongo::Constants
21
+
22
+ def setup
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"
30
+ end
31
+
32
+ def test_alive
33
+ batch = []
34
+ 5000.times do |n|
35
+ batch << {:a => n}
36
+ end
37
+
38
+ @coll.insert(batch)
39
+ cursor = @coll.find
40
+ assert !cursor.alive?
41
+ cursor.next
42
+ assert cursor.alive?
43
+ cursor.close
44
+ assert !cursor.alive?
45
+ @coll.remove
46
+ end
47
+
48
+ def test_add_and_remove_options
49
+ c = @coll.find
50
+ assert_equal 0, c.options & OP_QUERY_EXHAUST
51
+ c.add_option(OP_QUERY_EXHAUST)
52
+ assert_equal OP_QUERY_EXHAUST, c.options & OP_QUERY_EXHAUST
53
+ c.remove_option(OP_QUERY_EXHAUST)
54
+ assert_equal 0, c.options & OP_QUERY_EXHAUST
55
+
56
+ c.next
57
+ assert_raise Mongo::InvalidOperation do
58
+ c.add_option(OP_QUERY_EXHAUST)
59
+ end
60
+
61
+ assert_raise Mongo::InvalidOperation do
62
+ c.add_option(OP_QUERY_EXHAUST)
63
+ end
64
+ end
65
+
66
+ def test_exhaust
67
+ if @version >= "2.0"
68
+ @coll.remove
69
+ data = "1" * 10_000
70
+ 5000.times do |n|
71
+ @coll.insert({:n => n, :data => data})
72
+ end
73
+
74
+ c = Cursor.new(@coll)
75
+ c.add_option(OP_QUERY_EXHAUST)
76
+ assert_equal @coll.count, c.to_a.size
77
+ assert c.closed?
78
+
79
+ c = Cursor.new(@coll)
80
+ c.add_option(OP_QUERY_EXHAUST)
81
+ 4999.times do
82
+ c.next
83
+ end
84
+ assert c.has_next?
85
+ assert c.next
86
+ assert !c.has_next?
87
+ assert c.closed?
88
+
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)
153
+ end
154
+ end
155
+
156
+ def test_inspect
157
+ selector = {:a => 1}
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
161
+ end
162
+
163
+ def test_explain
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
176
+ end
177
+
178
+ def test_each_with_no_block
179
+ assert_kind_of(Enumerator, @coll.find().each) if defined? Enumerator
180
+ end
181
+
182
+ def test_count
183
+ @coll.remove
184
+
185
+ assert_equal 0, @coll.find().count()
186
+
187
+ 10.times do |i|
188
+ @coll.save("x" => i)
189
+ end
190
+
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()
195
+
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)
199
+
200
+ assert_equal 1, @coll.find({"x" => 1}).count()
201
+ assert_equal 5, @coll.find({"x" => {"$lt" => 5}}).count()
202
+
203
+ a = @coll.find()
204
+ b = a.count()
205
+ a.each do |doc|
206
+ break
207
+ end
208
+ assert_equal b, a.count()
209
+
210
+ assert_equal 0, @db['acollectionthatdoesn'].count()
211
+ end
212
+
213
+ def test_sort
214
+ @coll.remove
215
+ 5.times{|x| @coll.insert({"age" => x}) }
216
+
217
+ assert_kind_of Cursor, @coll.find().sort(:age, 1)
218
+
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"]
222
+
223
+ assert_kind_of Cursor, @coll.find().sort([[:age, -1], [:b, 1]])
224
+
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"]
227
+
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"]
230
+
231
+ cursor = @coll.find()
232
+ cursor.next_document
233
+ assert_raise InvalidOperation do
234
+ cursor.sort(["age"])
235
+ end
236
+
237
+ assert_raise InvalidSortValueError do
238
+ @coll.find().sort(:age, 25).next_document
239
+ end
240
+
241
+ assert_raise InvalidSortValueError do
242
+ @coll.find().sort(25).next_document
243
+ end
244
+ end
245
+
246
+ def test_sort_date
247
+ @coll.remove
248
+ 5.times{|x| @coll.insert({"created_at" => Time.utc(2000 + x)}) }
249
+
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
252
+
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
255
+
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
258
+ end
259
+
260
+ def test_sort_min_max_keys
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})
266
+
267
+ results = @coll.find.sort([:n, :asc]).to_a
268
+
269
+ assert_equal MinKey.new, results[0]['n']
270
+ assert_equal(-1000000, results[1]['n'])
271
+ assert_equal 1000000, results[2]['n']
272
+ assert_equal MaxKey.new, results[3]['n']
273
+ end
274
+
275
+ def test_id_range_queries
276
+ @coll.remove
277
+
278
+ t1 = Time.now
279
+ t1_id = ObjectId.from_time(t1)
280
+ @coll.save({:t => 't1'})
281
+ @coll.save({:t => 't1'})
282
+ @coll.save({:t => 't1'})
283
+ sleep(1)
284
+ t2 = Time.now
285
+ t2_id = ObjectId.from_time(t2)
286
+ @coll.save({:t => 't2'})
287
+ @coll.save({:t => 't2'})
288
+ @coll.save({:t => 't2'})
289
+
290
+ assert_equal 3, @coll.find({'_id' => {'$gt' => t1_id, '$lt' => t2_id}}).count
291
+ @coll.find({'_id' => {'$gt' => t2_id}}).each do |doc|
292
+ assert_equal 't2', doc['t']
293
+ end
294
+ end
295
+
296
+ def test_limit
297
+ @coll.remove
298
+
299
+ 10.times do |i|
300
+ @coll.save("x" => i)
301
+ end
302
+ assert_equal 10, @coll.find().count()
303
+
304
+ results = @coll.find().limit(5).to_a
305
+ assert_equal 5, results.length
306
+ end
307
+
308
+ def test_timeout_options
309
+ cursor = Cursor.new(@coll)
310
+ assert_equal true, cursor.timeout
311
+
312
+ cursor = @coll.find
313
+ assert_equal true, cursor.timeout
314
+
315
+ cursor = @coll.find({}, :timeout => nil)
316
+ assert_equal true, cursor.timeout
317
+
318
+ cursor = Cursor.new(@coll, :timeout => false)
319
+ assert_equal false, cursor.timeout
320
+
321
+ @coll.find({}, :timeout => false) do |c|
322
+ assert_equal false, c.timeout
323
+ end
324
+ end
325
+
326
+ def test_timeout
327
+ opts = Cursor.new(@coll).options
328
+ assert_equal 0, opts & Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT
329
+
330
+ opts = Cursor.new(@coll, :timeout => false).options
331
+ assert_equal Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT,
332
+ opts & Mongo::Constants::OP_QUERY_NO_CURSOR_TIMEOUT
333
+ end
334
+
335
+ def test_limit_exceptions
336
+ cursor = @coll.find()
337
+ cursor.next_document
338
+ assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do
339
+ cursor.limit(1)
340
+ end
341
+
342
+ cursor = @coll.find()
343
+ cursor.close
344
+ assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do
345
+ cursor.limit(1)
346
+ end
347
+ end
348
+
349
+ def test_skip
350
+ @coll.remove
351
+
352
+ 10.times do |i|
353
+ @coll.save("x" => i)
354
+ end
355
+ assert_equal 10, @coll.find().count()
356
+
357
+ all_results = @coll.find().to_a
358
+ skip_results = @coll.find().skip(2).to_a
359
+ assert_equal 10, all_results.length
360
+ assert_equal 8, skip_results.length
361
+
362
+ assert_equal all_results.slice(2...10), skip_results
363
+ end
364
+
365
+ def test_skip_exceptions
366
+ cursor = @coll.find()
367
+ cursor.next_document
368
+ assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do
369
+ cursor.skip(1)
370
+ end
371
+
372
+ cursor = @coll.find()
373
+ cursor.close
374
+ assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do
375
+ cursor.skip(1)
376
+ end
377
+ end
378
+
379
+ def test_limit_skip_chaining
380
+ @coll.remove
381
+ 10.times do |i|
382
+ @coll.save("x" => i)
383
+ end
384
+
385
+ all_results = @coll.find().to_a
386
+ limited_skip_results = @coll.find().limit(5).skip(3).to_a
387
+
388
+ assert_equal all_results.slice(3...8), limited_skip_results
389
+ end
390
+
391
+ def test_close_no_query_sent
392
+ begin
393
+ cursor = @coll.find('a' => 1)
394
+ cursor.close
395
+ assert cursor.closed?
396
+ rescue => ex
397
+ fail ex.to_s
398
+ end
399
+ end
400
+
401
+ def test_refill_via_get_more
402
+ assert_equal 1, @coll.count
403
+ 1000.times { |i|
404
+ assert_equal 1 + i, @coll.count
405
+ @coll.insert('a' => i)
406
+ }
407
+
408
+ assert_equal 1001, @coll.count
409
+ count = 0
410
+ @coll.find.each { |obj|
411
+ count += obj['a']
412
+ }
413
+ assert_equal 1001, @coll.count
414
+
415
+ # do the same thing again for debugging
416
+ assert_equal 1001, @coll.count
417
+ count2 = 0
418
+ @coll.find.each { |obj|
419
+ count2 += obj['a']
420
+ }
421
+ assert_equal 1001, @coll.count
422
+
423
+ assert_equal count, count2
424
+ assert_equal 499501, count
425
+ end
426
+
427
+ def test_refill_via_get_more_alt_coll
428
+ coll = @db.collection('test-alt-coll')
429
+ coll.remove
430
+ coll.insert('a' => 1) # collection not created until it's used
431
+ assert_equal 1, coll.count
432
+
433
+ 1000.times { |i|
434
+ assert_equal 1 + i, coll.count
435
+ coll.insert('a' => i)
436
+ }
437
+
438
+ assert_equal 1001, coll.count
439
+ count = 0
440
+ coll.find.each { |obj|
441
+ count += obj['a']
442
+ }
443
+ assert_equal 1001, coll.count
444
+
445
+ # do the same thing again for debugging
446
+ assert_equal 1001, coll.count
447
+ count2 = 0
448
+ coll.find.each { |obj|
449
+ count2 += obj['a']
450
+ }
451
+ assert_equal 1001, coll.count
452
+
453
+ assert_equal count, count2
454
+ assert_equal 499501, count
455
+ end
456
+
457
+ def test_close_after_query_sent
458
+ begin
459
+ cursor = @coll.find('a' => 1)
460
+ cursor.next_document
461
+ cursor.close
462
+ assert cursor.closed?
463
+ rescue => ex
464
+ fail ex.to_s
465
+ end
466
+ end
467
+
468
+ def test_kill_cursors
469
+ @coll.drop
470
+
471
+ client_cursors = cursor_count(@db)
472
+
473
+ 10000.times do |i|
474
+ @coll.insert("i" => i)
475
+ end
476
+
477
+ assert_equal(client_cursors, cursor_count(@db))
478
+
479
+ 10.times do |i|
480
+ @coll.find_one()
481
+ end
482
+
483
+ assert_equal(client_cursors, cursor_count(@db))
484
+
485
+ 10.times do |i|
486
+ a = @coll.find()
487
+ a.next_document
488
+ a.close()
489
+ end
490
+
491
+ assert_equal(client_cursors, cursor_count(@db))
492
+
493
+ a = @coll.find()
494
+ a.next_document
495
+
496
+ assert_not_equal(client_cursors, cursor_count(@db))
497
+
498
+ a.close()
499
+
500
+ assert_equal(client_cursors, cursor_count(@db))
501
+
502
+ a = @coll.find({}, :limit => 10).next_document
503
+
504
+ assert_equal(client_cursors, cursor_count(@db))
505
+
506
+ @coll.find() do |cursor|
507
+ cursor.next_document
508
+ end
509
+
510
+ assert_equal(client_cursors, cursor_count(@db))
511
+
512
+ @coll.find() { |cursor|
513
+ cursor.next_document
514
+ }
515
+
516
+ assert_equal(client_cursors, cursor_count(@db))
517
+ end
518
+
519
+ def test_count_with_fields
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
550
+
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
556
+ else
557
+ assert_equal 1, @coll.find({ :i => 1 }, :named_hint => 'bad_hint').count
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
581
+ end
582
+
583
+ def test_has_next
584
+ @coll.remove
585
+ 200.times do |n|
586
+ @coll.save("x" => n)
587
+ end
588
+
589
+ cursor = @coll.find
590
+ n = 0
591
+ while cursor.has_next?
592
+ assert cursor.next
593
+ n += 1
594
+ end
595
+
596
+ assert_equal n, 200
597
+ assert_equal false, cursor.has_next?
598
+ end
599
+
600
+ def test_cursor_invalid
601
+ @coll.remove
602
+ 10000.times do |n|
603
+ @coll.insert({:a => n})
604
+ end
605
+
606
+ cursor = @coll.find({})
607
+
608
+ assert_raise_error Mongo::OperationFailure, "CURSOR_NOT_FOUND" do
609
+ 9999.times do
610
+ cursor.next_document
611
+ cursor.instance_variable_set(:@cursor_id, 1234567890)
612
+ end
613
+ end
614
+ end
615
+
616
+ def test_enumberables
617
+ @coll.remove
618
+ 100.times do |n|
619
+ @coll.insert({:a => n})
620
+ end
621
+
622
+ assert_equal 100, @coll.find.to_a.length
623
+ assert_equal 100, @coll.find.to_set.length
624
+
625
+ cursor = @coll.find
626
+ 50.times { |n| cursor.next_document }
627
+ assert_equal 50, cursor.to_a.length
628
+ end
629
+
630
+ def test_rewind
631
+ @coll.remove
632
+ 100.times do |n|
633
+ @coll.insert({:a => n})
634
+ end
635
+
636
+ cursor = @coll.find
637
+ cursor.to_a
638
+ assert_equal [], cursor.map {|doc| doc }
639
+
640
+ cursor.rewind!
641
+ assert_equal 100, cursor.map {|doc| doc }.length
642
+
643
+ cursor.rewind!
644
+ 5.times { cursor.next_document }
645
+ cursor.rewind!
646
+ assert_equal 100, cursor.map {|doc| doc }.length
647
+ end
648
+
649
+ def test_transformer
650
+ transformer = Proc.new { |doc| doc }
651
+ cursor = Cursor.new(@coll, :transformer => transformer)
652
+ assert_equal(transformer, cursor.transformer)
653
+ end
654
+
655
+ def test_instance_transformation_with_next
656
+ klass = Struct.new(:id, :a)
657
+ transformer = Proc.new { |doc| klass.new(doc['_id'], doc['a']) }
658
+ cursor = Cursor.new(@coll, :transformer => transformer)
659
+ instance = cursor.next
660
+
661
+ assert_instance_of(klass, instance)
662
+ assert_instance_of(BSON::ObjectId, instance.id)
663
+ assert_equal(1, instance.a)
664
+ end
665
+
666
+ def test_instance_transformation_with_each
667
+ klass = Struct.new(:id, :a)
668
+ transformer = Proc.new { |doc| klass.new(doc['_id'], doc['a']) }
669
+ cursor = Cursor.new(@coll, :transformer => transformer)
670
+
671
+ cursor.each do |instance|
672
+ assert_instance_of(klass, instance)
673
+ end
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
683
+ end