mongo 1.8.4 → 1.8.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 (51) hide show
  1. checksums.yaml +6 -14
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/README.md +2 -0
  5. data/VERSION +1 -1
  6. data/lib/mongo.rb +11 -9
  7. data/lib/mongo/collection.rb +26 -19
  8. data/lib/mongo/cursor.rb +7 -2
  9. data/lib/mongo/db.rb +1 -1
  10. data/lib/mongo/mongo_client.rb +1 -1
  11. data/lib/mongo/mongo_replica_set_client.rb +2 -3
  12. data/lib/mongo/mongo_sharded_client.rb +1 -2
  13. data/lib/mongo/util/node.rb +12 -14
  14. data/lib/mongo/util/pool.rb +1 -1
  15. data/lib/mongo/util/pool_manager.rb +13 -15
  16. data/lib/mongo/util/sharding_pool_manager.rb +5 -2
  17. data/lib/mongo/util/support.rb +14 -0
  18. data/mongo.gemspec +7 -3
  19. data/test/functional/authentication_test.rb +21 -0
  20. data/test/functional/collection_test.rb +0 -1
  21. data/test/functional/connection_test.rb +1 -1
  22. data/test/functional/db_test.rb +1 -56
  23. data/test/functional/support_test.rb +30 -0
  24. data/test/replica_set/authentication_test.rb +23 -0
  25. data/test/replica_set/max_values_test.rb +61 -0
  26. data/test/sharded_cluster/basic_test.rb +18 -0
  27. data/test/shared/authentication.rb +49 -0
  28. data/test/tools/mongo_config.rb +21 -26
  29. data/test/unit/node_test.rb +3 -0
  30. data/test/unit/pool_manager_test.rb +3 -1
  31. data/test/unit/read_test.rb +4 -0
  32. data/test/unit/sharding_pool_manager_test.rb +88 -0
  33. metadata +38 -69
  34. metadata.gz.sig +0 -0
  35. data/test/auxillary/1.4_feature_test.rb +0 -165
  36. data/test/auxillary/authentication_test.rb +0 -74
  37. data/test/auxillary/autoreconnect_test.rb +0 -39
  38. data/test/auxillary/fork_test.rb +0 -28
  39. data/test/auxillary/pool_reuse_test.rb +0 -65
  40. data/test/auxillary/repl_set_auth_test.rb +0 -69
  41. data/test/auxillary/slave_connection_test.rb +0 -37
  42. data/test/auxillary/threaded_authentication_test.rb +0 -99
  43. data/test/bson/binary_test.rb +0 -13
  44. data/test/bson/bson_test.rb +0 -762
  45. data/test/bson/byte_buffer_test.rb +0 -215
  46. data/test/bson/hash_with_indifferent_access_test.rb +0 -48
  47. data/test/bson/json_test.rb +0 -16
  48. data/test/bson/object_id_test.rb +0 -153
  49. data/test/bson/ordered_hash_test.rb +0 -247
  50. data/test/bson/timestamp_test.rb +0 -51
  51. data/test/tools/auth_repl_set_manager.rb +0 -14
@@ -1,39 +0,0 @@
1
- require 'test_helper'
2
- require 'mongo'
3
-
4
- # NOTE: This test requires bouncing the server
5
- class AutoreconnectTest < Test::Unit::TestCase
6
- include Mongo
7
-
8
- def setup
9
- @client = MongoClient.new
10
- @db = @client.db('mongo-ruby-test')
11
- @db.drop_collection("test-connect")
12
- @coll = @db.collection("test-connect")
13
- end
14
-
15
- def test_query
16
- @coll.save({:a => 20})
17
- @coll.save({:a => 30})
18
- @coll.save({:a => 40})
19
- results = []
20
- @coll.find.each {|r| results << r}
21
- [20, 30, 40].each do |a|
22
- assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"
23
- end
24
-
25
- puts "Please disconnect and then reconnect the current master."
26
- gets
27
-
28
- begin
29
- @coll.find.to_a
30
- rescue Mongo::ConnectionFailure
31
- end
32
-
33
- results = []
34
- @coll.find.each {|r| results << r}
35
- [20, 30, 40].each do |a|
36
- assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"
37
- end
38
- end
39
- end
@@ -1,28 +0,0 @@
1
- require 'test_helper'
2
- require 'mongo'
3
-
4
- class ForkTest < Test::Unit::TestCase
5
- include Mongo
6
-
7
- def setup
8
- @client = standard_connection
9
- end
10
-
11
- def test_fork
12
- # Now insert some data
13
- 10.times do |n|
14
- @client[MONGO_TEST_DB]['nums'].insert({:a => n})
15
- end
16
-
17
- # Now fork. You'll almost always see an exception here.
18
- if !Kernel.fork
19
- 10.times do
20
- assert @client[MONGO_TEST_DB]['nums'].find_one
21
- end
22
- else
23
- 10.times do
24
- assert @client[MONGO_TEST_DB]['nums'].find_one
25
- end
26
- end
27
- end
28
- end
@@ -1,65 +0,0 @@
1
- require 'test_helper'
2
- require 'mongo'
3
-
4
- class PoolReuseTest < Test::Unit::TestCase
5
- include Mongo
6
-
7
- def count_open_file_handles
8
- @conn["admin"].command(:serverStatus => 1)["connections"]["current"]
9
- end
10
-
11
- def setup
12
- ensure_cluster(:rs, :replicas => 2, :arbiters => 1)
13
- connect
14
- end
15
-
16
- def teardown
17
- @@cluster.stop if @@cluster
18
- @conn.close if @conn
19
- end
20
-
21
- def connect
22
- @conn.close if @conn
23
- @conn = MongoReplicaSetClient.new(["%s:%s" % [@rs.primary.host, @rs.primary.port]])
24
- end
25
-
26
- def test_pool_resources_are_reused
27
- handles_before_refresh = count_open_file_handles
28
- 10.times do
29
- @conn.hard_refresh!
30
- end
31
- assert_equal handles_before_refresh, count_open_file_handles
32
- end
33
-
34
- def test_pool_connectability_after_cycling_members
35
- db = @conn['sample-db']
36
-
37
- assert_equal db.collection_names, []
38
- old_primary = @@cluster.primary
39
- @conn["admin"].command step_down_command rescue nil
40
- old_primary.stop
41
-
42
- rescue_connection_failure do
43
- db.collection_names
44
- end
45
-
46
- # We should be reconnected to the new master now
47
- assert_equal db.collection_names, []
48
-
49
- # Start up the old primary
50
- old_primary.start
51
-
52
- # Stop the new primary
53
- primary = @@cluster.primary
54
- @conn["admin"].command step_down_command rescue nil
55
- primary.stop
56
-
57
- # Wait for primary failover
58
- rescue_connection_failure do
59
- db.collection_names
60
- end
61
-
62
- # Reconnect and verify that we can read again
63
- assert_equal db.collection_names, []
64
- end
65
- end
@@ -1,69 +0,0 @@
1
- require 'test_helper'
2
- require 'mongo'
3
-
4
- class AuthTest < Test::Unit::TestCase
5
- include Mongo
6
-
7
- def setup
8
- @rs = AuthReplSetManager.new(:start_port => 40000)
9
- @rs.start_set
10
- end
11
-
12
- def teardown
13
- #@rs.cleanup_set
14
- end
15
-
16
- def test_repl_set_auth
17
- @client = MongoReplicaSetClient.new(build_seeds(3), :name => @rs.name)
18
-
19
- # Add an admin user
20
- @client['admin'].add_user("me", "secret")
21
-
22
- # Ensure that insert fails
23
- assert_raise_error Mongo::OperationFailure, "unauthorized" do
24
- @client['foo']['stuff'].insert({:a => 2}, {:w => 2})
25
- end
26
-
27
- # Then authenticate
28
- assert @client['admin'].authenticate("me", "secret")
29
-
30
- # Insert should succeed now
31
- assert @client['foo']['stuff'].insert({:a => 2}, {:w => 2})
32
-
33
- # So should a query
34
- assert @client['foo']['stuff'].find_one
35
-
36
- # But not when we logout
37
- @client['admin'].logout
38
-
39
- assert_raise_error Mongo::OperationFailure, "unauthorized" do
40
- @client['foo']['stuff'].find_one
41
- end
42
-
43
- # Same should apply to a random secondary
44
- @slave1 = MongoClient.new(@client.secondary_pools[0].host,
45
- @client.secondary_pools[0].port, :slave_ok => true)
46
-
47
- # Find should fail
48
- assert_raise_error Mongo::OperationFailure, "unauthorized" do
49
- @slave1['foo']['stuff'].find_one
50
- end
51
-
52
- # But not when authenticated
53
- assert @slave1['admin'].authenticate("me", "secret")
54
- assert @slave1['foo']['stuff'].find_one
55
-
56
- # Same should apply when using :secondary_only
57
- @second_only = MongoReplicaSetClient.new(build_seeds(3),
58
- :require_primary => false, :read => :secondary_only)
59
-
60
- # Find should fail
61
- assert_raise_error Mongo::OperationFailure, "unauthorized" do
62
- @second_only['foo']['stuff'].find_one
63
- end
64
-
65
- # But not when authenticated
66
- assert @second_only['admin'].authenticate("me", "secret")
67
- assert @second_only['foo']['stuff'].find_one
68
- end
69
- end
@@ -1,37 +0,0 @@
1
- require 'test_helper'
2
- require 'mongo'
3
-
4
- # NOTE: these tests are run only if we can connect to a single MongoDB in slave mode.
5
- class SlaveConnectionTest < Test::Unit::TestCase
6
- include Mongo
7
-
8
- def self.connect_to_slave
9
- @@host = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
10
- @@port = ENV['MONGO_RUBY_DRIVER_PORT'] || MongoClient::DEFAULT_PORT
11
- conn = MongoClient.new(@@host, @@port, :slave_ok => true)
12
- response = conn['admin'].command(:ismaster => 1)
13
- Mongo::Support.ok?(response) && response['ismaster'] != 1
14
- end
15
-
16
- if self.connect_to_slave
17
- puts "Connected to slave; running slave tests."
18
-
19
- def test_connect_to_slave
20
- assert_raise Mongo::ConnectionFailure do
21
- @db = MongoClient.new(@@host, @@port, :slave_ok => false).db('ruby-mongo-demo')
22
- end
23
- end
24
-
25
- def test_slave_ok_sent_to_queries
26
- @con = MongoClient.new(@@host, @@port, :slave_ok => true)
27
- assert_equal true, @con.slave_ok?
28
- end
29
- else
30
- puts "Not connected to slave; skipping slave connection tests."
31
-
32
- def test_slave_ok_false_on_queries
33
- @client = MongoClient.new(@@host, @@port)
34
- assert !@client.slave_ok?
35
- end
36
- end
37
- end
@@ -1,99 +0,0 @@
1
- require 'test_helper'
2
- require 'mongo'
3
- require 'thread'
4
-
5
- # NOTE: This test requires bouncing the server.
6
- # It also requires that a user exists on the admin database.
7
- class AuthenticationTest < Test::Unit::TestCase
8
- include Mongo
9
-
10
- def setup
11
- @client = standard_connection(:pool_size => 10)
12
- @db1 = @client.db('mongo-ruby-test-auth1')
13
- @db2 = @client.db('mongo-ruby-test-auth2')
14
- @admin = @client.db('admin')
15
- end
16
-
17
- def teardown
18
- @db1.authenticate('user1', 'secret')
19
- @db2.authenticate('user2', 'secret')
20
- @client.drop_database('mongo-ruby-test-auth1')
21
- @client.drop_database('mongo-ruby-test-auth2')
22
- end
23
-
24
- def threaded_exec
25
- threads = []
26
-
27
- 100.times do
28
- threads << Thread.new do
29
- yield
30
- end
31
- end
32
-
33
- 100.times do |n|
34
- threads[n].join
35
- end
36
- end
37
-
38
- def test_authenticate
39
- @admin.authenticate('bob', 'secret')
40
- @db1.add_user('user1', 'secret')
41
- @db2.add_user('user2', 'secret')
42
- @admin.logout
43
-
44
- threaded_exec do
45
- assert_raise Mongo::OperationFailure do
46
- @db1['stuff'].insert({:a => 2})
47
- end
48
- end
49
-
50
- threaded_exec do
51
- assert_raise Mongo::OperationFailure do
52
- @db2['stuff'].insert({:a => 2})
53
- end
54
- end
55
-
56
- @db1.authenticate('user1', 'secret')
57
- @db2.authenticate('user2', 'secret')
58
-
59
- threaded_exec do
60
- assert @db1['stuff'].insert({:a => 2})
61
- end
62
-
63
- threaded_exec do
64
- assert @db2['stuff'].insert({:a => 2})
65
- end
66
-
67
- puts "Please bounce the server."
68
- gets
69
-
70
- # Here we reconnect.
71
- begin
72
- @db1['stuff'].find.to_a
73
- rescue Mongo::ConnectionFailure
74
- end
75
-
76
- threaded_exec do
77
- assert @db1['stuff'].insert({:a => 2})
78
- end
79
-
80
- threaded_exec do
81
- assert @db2['stuff'].insert({:a => 2})
82
- end
83
-
84
- @db1.logout
85
- threaded_exec do
86
- assert_raise Mongo::OperationFailure do
87
- @db1['stuff'].insert({:a => 2})
88
- end
89
- end
90
-
91
- @db2.logout
92
- threaded_exec do
93
- assert_raise Mongo::OperationFailure do
94
- assert @db2['stuff'].insert({:a => 2})
95
- end
96
- end
97
- end
98
-
99
- end
@@ -1,13 +0,0 @@
1
- # encoding:utf-8
2
- require 'test_helper'
3
-
4
- class BinaryTest < Test::Unit::TestCase
5
- def setup
6
- @data = ("THIS IS BINARY " * 50).unpack("c*")
7
- end
8
-
9
- def test_do_not_display_binary_data
10
- binary = BSON::Binary.new(@data)
11
- assert_equal "<BSON::Binary:#{binary.object_id}>", binary.inspect
12
- end
13
- end
@@ -1,762 +0,0 @@
1
- # encoding:utf-8
2
- require 'test_helper'
3
- require 'set'
4
-
5
- if RUBY_VERSION < '1.9'
6
- silently do
7
- require 'complex'
8
- require 'rational'
9
- end
10
- end
11
- require 'bigdecimal'
12
-
13
- begin
14
- require 'date'
15
- require 'tzinfo'
16
- require 'active_support/timezone'
17
- Time.zone = "Pacific Time (US & Canada)"
18
- Zone = Time.zone.now
19
- rescue LoadError
20
- #warn 'Mocking time with zone'
21
- module ActiveSupport
22
- class TimeWithZone
23
- def initialize(utc_time, zone)
24
- end
25
- end
26
- end
27
- Zone = ActiveSupport::TimeWithZone.new(Time.now.utc, 'EST')
28
- end
29
-
30
- begin
31
- require 'active_support/multibyte/chars'
32
- rescue LoadError
33
- warn 'Mocking ActiveSupport::Multibyte::Chars'
34
- module ActiveSupport
35
- module Multibyte
36
- class Chars < String
37
- end
38
- end
39
- end
40
- end
41
-
42
- class BSONTest < Test::Unit::TestCase
43
-
44
- include BSON
45
-
46
- def setup
47
- @encoder = BSON::BSON_CODER
48
- end
49
-
50
- def assert_doc_pass(doc, options={})
51
- bson = @encoder.serialize(doc)
52
- if options[:debug]
53
- puts "DEBUGGING DOC:"
54
- p bson.to_a
55
- puts "DESERIALIZES TO:"
56
- end
57
- assert_equal @encoder.serialize(doc).to_a, bson.to_a
58
- assert_equal doc, @encoder.deserialize(bson)
59
- end
60
-
61
- def test_interface
62
- doc = { 'a' => 1 }
63
- bson = BSON.serialize(doc)
64
- assert_equal doc, BSON.deserialize(bson)
65
- end
66
-
67
- def test_read_bson_document
68
- bson_file_data_h_star = ["21000000075f6964005115883c3d75c94d3aa18b63016100000000000000f03f00"]
69
- strio = StringIO.new(bson_file_data_h_star.pack('H*'))
70
- bson = BSON.read_bson_document(strio)
71
- doc = {"_id"=>BSON::ObjectId('5115883c3d75c94d3aa18b63'), "a"=>1.0}
72
- assert_equal doc, bson
73
- end
74
-
75
- def test_bson_ruby_interface
76
- doc = { 'a' => 1 }
77
- buf = BSON_RUBY.serialize(doc)
78
- bson = BSON::BSON_RUBY.new
79
- bson.instance_variable_set(:@buf, buf)
80
- assert_equal [12, 0, 0, 0, 16, 97, 0, 1, 0, 0, 0, 0], bson.to_a
81
- assert_equal "\f\x00\x00\x00\x10a\x00\x01\x00\x00\x00\x00", bson.to_s
82
- assert_equal [12, 0, 0, 0, 16, 97, 0, 1, 0, 0, 0, 0], bson.unpack
83
- end
84
-
85
- def test_bson_ruby_hex_dump
86
- doc = { 'a' => 1 }
87
- buf = BSON_RUBY.serialize(doc)
88
- bson = BSON_RUBY.new
89
- bson.instance_variable_set(:@buf, buf)
90
- doc_hex_dump = " 0: 0C 00 00 00 10 61 00 01\n 8: 00 00 00 00"
91
- assert_equal doc_hex_dump, bson.hex_dump
92
- end
93
-
94
- def test_bson_ruby_dbref_not_used
95
- buf = BSON::ByteBuffer.new
96
- val = ns = 'namespace'
97
-
98
- # Make a hole for the length
99
- len_pos = buf.position
100
- buf.put_int(0)
101
-
102
- # Save the string
103
- start_pos = buf.position
104
- BSON::BSON_RUBY.serialize_cstr(buf, val)
105
- end_pos = buf.position
106
-
107
- # Put the string size in front
108
- buf.put_int(end_pos - start_pos, len_pos)
109
-
110
- # Go back to where we were
111
- buf.position = end_pos
112
-
113
- oid = ObjectId.new
114
- buf.put_array(oid.to_a)
115
- buf.rewind
116
-
117
- bson = BSON::BSON_RUBY.new
118
- bson.instance_variable_set(:@buf, buf)
119
-
120
- assert_equal DBRef.new(ns, oid).to_s, bson.deserialize_dbref_data(buf).to_s
121
- end
122
-
123
- def test_require_hash
124
- assert_raise_error InvalidDocument, "takes a Hash" do
125
- BSON.serialize('foo')
126
- end
127
-
128
- assert_raise_error InvalidDocument, "takes a Hash" do
129
- BSON.serialize(Object.new)
130
- end
131
-
132
- assert_raise_error InvalidDocument, "takes a Hash" do
133
- BSON.serialize(Set.new)
134
- end
135
- end
136
-
137
- def test_string
138
- doc = {'doc' => 'hello, world'}
139
- assert_doc_pass(doc)
140
- end
141
-
142
- def test_valid_utf8_string
143
- doc = {'doc' => 'aé'}
144
- assert_doc_pass(doc)
145
- end
146
-
147
- def test_valid_active_support_multibyte_chars
148
- unless RUBY_PLATFORM =~ /java/
149
- doc = {'doc' => ActiveSupport::Multibyte::Chars.new('aé')}
150
- assert_doc_pass(doc)
151
-
152
- bson = @encoder.serialize(doc)
153
- doc = @encoder.deserialize(bson)
154
- assert_equal doc['doc'], 'aé'
155
- end
156
- end
157
-
158
- def test_valid_utf8_key
159
- doc = {'aé' => 'hello'}
160
- assert_doc_pass(doc)
161
- end
162
-
163
- def test_limit_max_bson_size
164
- doc = {'name' => 'a' * BSON::DEFAULT_MAX_BSON_SIZE}
165
- assert_raise InvalidDocument do
166
- assert @encoder.serialize(doc)
167
- end
168
- end
169
-
170
- def test_update_max_bson_size
171
- require 'ostruct'
172
- mock_conn = OpenStruct.new
173
- size = 7 * 1024 * 1024
174
- mock_conn.max_bson_size = size
175
- silently do
176
- assert_equal size, BSON_CODER.update_max_bson_size(mock_conn)
177
- assert_equal size, BSON_CODER.max_bson_size
178
- end
179
- end
180
-
181
- def test_round_trip
182
- doc = {'doc' => 123}
183
- @encoder.deserialize(@encoder.serialize(doc))
184
- end
185
-
186
- # In 1.8 we test that other string encodings raise an exception.
187
- # In 1.9 we test that they get auto-converted.
188
- if RUBY_VERSION < '1.9'
189
- unless RUBY_PLATFORM == 'java'
190
- require 'iconv'
191
- def test_non_utf8_string
192
- string = Iconv.conv('iso-8859-1', 'utf-8', 'aé')
193
- doc = {'doc' => string}
194
- assert_raise InvalidStringEncoding do
195
- @encoder.serialize(doc)
196
- end
197
- end
198
-
199
- def test_non_utf8_key
200
- key = Iconv.conv('iso-8859-1', 'utf-8', 'aé')
201
- doc = {key => 'hello'}
202
- assert_raise InvalidStringEncoding do
203
- @encoder.serialize(doc)
204
- end
205
- end
206
- end
207
- else
208
- unless RUBY_PLATFORM == 'java'
209
- def test_non_utf8_string
210
- assert_raise BSON::InvalidStringEncoding do
211
- BSON::BSON_CODER.serialize({'str' => 'aé'.encode('iso-8859-1')})
212
- end
213
- end
214
-
215
- def test_invalid_utf8_string
216
- str = "123\xD9"
217
- assert !str.valid_encoding?
218
- assert_raise BSON::InvalidStringEncoding do
219
- BSON::BSON_CODER.serialize({'str' => str})
220
- end
221
- end
222
-
223
- def test_non_utf8_key
224
- assert_raise BSON::InvalidStringEncoding do
225
- BSON::BSON_CODER.serialize({'aé'.encode('iso-8859-1') => 'hello'})
226
- end
227
- end
228
-
229
- def test_forced_encoding_with_valid_utf8
230
- doc = {'doc' => "\xC3\xB6".force_encoding("ISO-8859-1")}
231
- serialized = @encoder.serialize(doc)
232
- deserialized = @encoder.deserialize(serialized)
233
- assert_equal(doc['doc'], deserialized['doc'].force_encoding("ISO-8859-1"))
234
- end
235
-
236
- # Based on a test from sqlite3-ruby
237
- def test_default_internal_is_honored
238
- before_enc = Encoding.default_internal
239
-
240
- str = "壁に耳あり、障子に目あり"
241
- bson = BSON::BSON_CODER.serialize("x" => str)
242
-
243
- silently { Encoding.default_internal = 'EUC-JP' }
244
- out = BSON::BSON_CODER.deserialize(bson)["x"]
245
-
246
- assert_equal Encoding.default_internal, out.encoding
247
- assert_equal str.encode('EUC-JP'), out
248
- assert_equal str, out.encode(str.encoding)
249
- ensure
250
- silently { Encoding.default_internal = before_enc }
251
- end
252
- end
253
- end
254
-
255
- def test_code
256
- code = Code.new('this.a.b < this.b')
257
- assert_equal 17, code.length
258
- assert_match /<BSON::Code:.*@data="this.a.b < this.b".*>/, code.inspect
259
- doc = {'$where' => code}
260
- assert_doc_pass(doc)
261
- code = 'this.c.d < this.e'.to_bson_code # core_ext.rb
262
- assert_equal BSON::Code, code.class
263
- assert_equal code, code.to_bson_code
264
- end
265
-
266
- def test_code_with_symbol
267
- assert_raise_error ArgumentError, "BSON::Code must be in the form of a String" do
268
- Code.new(:fubar)
269
- end
270
- end
271
-
272
- def test_code_with_scope
273
- doc = {'$where' => Code.new('this.a.b < this.b', {'foo' => 1})}
274
- assert_doc_pass(doc)
275
- end
276
-
277
- def test_double
278
- doc = {'doc' => 41.25}
279
- assert_doc_pass(doc)
280
- end
281
-
282
- def test_int
283
- doc = {'doc' => 42}
284
- assert_doc_pass(doc)
285
-
286
- doc = {"doc" => -5600}
287
- assert_doc_pass(doc)
288
-
289
- doc = {"doc" => 2147483647}
290
- assert_doc_pass(doc)
291
-
292
- doc = {"doc" => -2147483648}
293
- assert_doc_pass(doc)
294
- end
295
-
296
- def test_ordered_hash
297
- doc = BSON::OrderedHash.new
298
- doc["b"] = 1
299
- doc["a"] = 2
300
- doc["c"] = 3
301
- doc["d"] = 4
302
- assert_doc_pass(doc)
303
- end
304
-
305
- def test_object
306
- doc = {'doc' => {'age' => 42, 'name' => 'Spongebob', 'shoe_size' => 9.5}}
307
- assert_doc_pass(doc)
308
- end
309
-
310
- def test_embedded_document_with_nil
311
- doc = {'doc' => {'age' => 42, 'name' => nil, 'shoe_size' => 9.5}}
312
- assert_doc_pass(doc)
313
- end
314
-
315
- def test_embedded_document_with_date
316
- doc = {'doc' => {'age' => 42, 'date' => Time.now.utc, 'shoe_size' => 9.5}}
317
- bson = @encoder.serialize(doc)
318
- doc2 = @encoder.deserialize(bson)
319
- assert doc2['doc']
320
- assert_equal 42, doc2['doc']['age']
321
- assert_equal 9.5, doc2['doc']['shoe_size']
322
- assert_in_delta Time.now, doc2['doc']['date'], 1
323
- end
324
-
325
- def test_oid
326
- doc = {'doc' => ObjectId.new}
327
- assert_doc_pass(doc)
328
- end
329
-
330
- def test_array
331
- doc = {'doc' => [1, 2, 'a', 'b']}
332
- assert_doc_pass(doc)
333
- end
334
-
335
- def test_array_keys
336
- doc = {'doc' => [1, 2, 'a', 'b']}
337
- bson = @encoder.serialize(doc).to_a
338
- assert_equal 48, bson[14]
339
- assert_equal 49, bson[21]
340
- assert_equal 50, bson[28]
341
- assert_equal 51, bson[37]
342
- end
343
-
344
- def test_regex
345
- doc = {'doc' => /foobar/i}
346
- assert_doc_pass(doc)
347
- end
348
-
349
- def test_regex_multiline
350
- doc = {'doc' => /foobar/m}
351
- assert_doc_pass(doc)
352
- end
353
-
354
- def test_boolean
355
- doc = {'doc' => true}
356
- assert_doc_pass(doc)
357
- end
358
-
359
- def test_date
360
- doc = {'date' => Time.now}
361
- bson = @encoder.serialize(doc)
362
- doc2 = @encoder.deserialize(bson)
363
- # Mongo only stores up to the millisecond
364
- assert_in_delta doc['date'], doc2['date'], 0.001
365
- end
366
-
367
- def test_date_in_array
368
- doc = {'date' => [Time.now.utc]}
369
- bson = @encoder.serialize(doc)
370
- doc2 = @encoder.deserialize(bson)
371
- assert doc2
372
- end
373
-
374
- def test_date_returns_as_utc
375
- doc = {'date' => Time.now.utc}
376
- bson = @encoder.serialize(doc)
377
- doc2 = @encoder.deserialize(bson)
378
- assert doc2['date'].utc?
379
- end
380
-
381
- def test_date_before_epoch
382
- if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/ then return true end
383
- begin
384
- doc = {'date' => Time.utc(1600)}
385
- bson = @encoder.serialize(doc)
386
- doc2 = @encoder.deserialize(bson)
387
- # Mongo only stores up to the millisecond
388
- assert_in_delta doc['date'], doc2['date'], 2
389
- rescue ArgumentError
390
- # some versions of Ruby won't let you create pre-epoch Time instances
391
- #
392
- # TODO figure out how that will work if somebady has saved data
393
- # w/ early dates already and is just querying for it.
394
- end
395
- end
396
-
397
- def test_exeption_on_using_unsupported_date_class
398
- [DateTime.now, Date.today, Zone].each do |invalid_date|
399
- doc = {:date => invalid_date}
400
- begin
401
- BSON::BSON_CODER.serialize(doc)
402
- rescue => e
403
- ensure
404
- if !invalid_date.is_a? Time
405
- assert_equal InvalidDocument, e.class
406
- assert_match(/UTC Time/, e.message)
407
- end
408
- end
409
- end
410
- end
411
-
412
- def test_dbref
413
- oid = ObjectId.new
414
- ns = 'namespace'
415
- doc = {}
416
- dbref = DBRef.new(ns, oid)
417
- assert_equal({"$id"=>oid, "$ns"=>ns}, dbref.to_hash)
418
- doc['dbref'] = dbref
419
- bson = @encoder.serialize(doc)
420
- doc2 = @encoder.deserialize(bson)
421
-
422
- # Java doesn't deserialize to DBRefs
423
- if RUBY_PLATFORM =~ /java/ && BSON.extension?
424
- assert_equal 'namespace', doc2['dbref']['$ns']
425
- assert_equal oid, doc2['dbref']['$id']
426
- else
427
- assert_equal 'namespace', doc2['dbref'].namespace
428
- assert_equal oid, doc2['dbref'].object_id
429
- end
430
- end
431
-
432
- def test_symbol
433
- doc = {'sym' => :foo}
434
- bson = @encoder.serialize(doc)
435
- doc2 = @encoder.deserialize(bson)
436
- assert_equal :foo, doc2['sym']
437
- end
438
-
439
- def test_binary
440
- bin = Binary.new
441
- 'binstring'.each_byte { |b| bin.put(b) }
442
-
443
- doc = {'bin' => bin}
444
- bson = @encoder.serialize(doc)
445
- doc2 = @encoder.deserialize(bson)
446
- bin2 = doc2['bin']
447
- assert_kind_of Binary, bin2
448
- assert_equal 'binstring', bin2.to_s
449
- assert_equal Binary::SUBTYPE_SIMPLE, bin2.subtype
450
- end
451
-
452
- def test_binary_with_deprecated_subtype
453
- bin = Binary.new
454
- 'binstring'.each_byte { |b| bin.put(b) }
455
- bin.subtype = Binary::SUBTYPE_BYTES
456
-
457
- doc = {'bin' => bin}
458
- bson = @encoder.serialize(doc)
459
- doc2 = @encoder.deserialize(bson)
460
- bin2 = doc2['bin']
461
- assert_kind_of Binary, bin2
462
- assert_equal 'binstring', bin2.to_s
463
- assert_equal Binary::SUBTYPE_BYTES, bin2.subtype
464
- end
465
-
466
- def test_binary_with_string
467
- b = Binary.new('somebinarystring')
468
- doc = {'bin' => b}
469
- bson = @encoder.serialize(doc)
470
- doc2 = @encoder.deserialize(bson)
471
- bin2 = doc2['bin']
472
- assert_kind_of Binary, bin2
473
- assert_equal 'somebinarystring', bin2.to_s
474
- assert_equal Binary::SUBTYPE_SIMPLE, bin2.subtype
475
- end
476
-
477
- def test_binary_type
478
- bin = Binary.new([1, 2, 3, 4, 5], Binary::SUBTYPE_USER_DEFINED)
479
-
480
- doc = {'bin' => bin}
481
- bson = @encoder.serialize(doc)
482
- doc2 = @encoder.deserialize(bson)
483
- bin2 = doc2['bin']
484
- assert_kind_of Binary, bin2
485
- assert_equal [1, 2, 3, 4, 5], bin2.to_a
486
- assert_equal Binary::SUBTYPE_USER_DEFINED, bin2.subtype
487
- end
488
-
489
- # Java doesn't support binary subtype 0 yet
490
- if !(RUBY_PLATFORM =~ /java/)
491
- def test_binary_subtype_0
492
- bin = Binary.new([1, 2, 3, 4, 5], Binary::SUBTYPE_SIMPLE)
493
-
494
- doc = {'bin' => bin}
495
- bson = @encoder.serialize(doc)
496
- doc2 = @encoder.deserialize(bson)
497
- bin2 = doc2['bin']
498
- assert_kind_of Binary, bin2
499
- assert_equal [1, 2, 3, 4, 5], bin2.to_a
500
- assert_equal Binary::SUBTYPE_SIMPLE, bin2.subtype
501
- end
502
- end
503
-
504
- def test_binary_byte_buffer
505
- bb = Binary.new
506
- 5.times { |i| bb.put(i + 1) }
507
-
508
- doc = {'bin' => bb}
509
- bson = @encoder.serialize(doc)
510
- doc2 = @encoder.deserialize(bson)
511
- bin2 = doc2['bin']
512
- assert_kind_of Binary, bin2
513
- assert_equal [1, 2, 3, 4, 5], bin2.to_a
514
- assert_equal Binary::SUBTYPE_SIMPLE, bin2.subtype
515
- end
516
-
517
- def test_put_id_first
518
- val = BSON::OrderedHash.new
519
- val['not_id'] = 1
520
- val['_id'] = 2
521
- roundtrip = @encoder.deserialize(@encoder.serialize(val, false, true).to_s)
522
- assert_kind_of BSON::OrderedHash, roundtrip
523
- assert_equal '_id', roundtrip.keys.first
524
-
525
- val = {'a' => 'foo', 'b' => 'bar', :_id => 42, 'z' => 'hello'}
526
- roundtrip = @encoder.deserialize(@encoder.serialize(val, false, true).to_s)
527
- assert_kind_of BSON::OrderedHash, roundtrip
528
- assert_equal '_id', roundtrip.keys.first
529
- end
530
-
531
- def test_nil_id
532
- doc = {"_id" => nil}
533
- assert_doc_pass(doc)
534
- end
535
-
536
- if !(RUBY_PLATFORM =~ /java/)
537
- def test_timestamp
538
- # val = {"test" => [4, 20]}
539
- result = @encoder.deserialize([0x13, 0x00, 0x00, 0x00,
540
- 0x11, 0x74, 0x65, 0x73,
541
- 0x74, 0x00, 0x04, 0x00,
542
- 0x00, 0x00, 0x14, 0x00,
543
- 0x00, 0x00, 0x00])
544
-
545
- silently do
546
- assert_equal 4, result["test"][0]
547
- assert_equal 20, result["test"][1]
548
- end
549
- end
550
- end
551
-
552
- def test_timestamp_type
553
- ts = Timestamp.new(5000, 100)
554
- doc = {:ts => ts}
555
- bson = @encoder.serialize(doc)
556
- assert_equal ts, @encoder.deserialize(bson)["ts"]
557
- end
558
-
559
- def test_overflow
560
- doc = {"x" => 2**75}
561
- assert_raise RangeError do
562
- @encoder.serialize(doc)
563
- end
564
-
565
- doc = {"x" => 9223372036854775}
566
- assert_doc_pass(doc)
567
-
568
- doc = {"x" => 9223372036854775807}
569
- assert_doc_pass(doc)
570
-
571
- doc["x"] = doc["x"] + 1
572
- assert_raise RangeError do
573
- @encoder.serialize(doc)
574
- end
575
-
576
- doc = {"x" => -9223372036854775}
577
- assert_doc_pass(doc)
578
-
579
- doc = {"x" => -9223372036854775808}
580
- assert_doc_pass(doc)
581
-
582
- doc["x"] = doc["x"] - 1
583
- assert_raise RangeError do
584
- BSON::BSON_CODER.serialize(doc)
585
- end
586
- end
587
-
588
- def test_invalid_numeric_types
589
- [BigDecimal.new("1.0"), Complex(0, 1), Rational(2, 3)].each do |type|
590
- doc = {"x" => type}
591
- begin
592
- @encoder.serialize(doc)
593
- rescue => e
594
- ensure
595
- assert_equal InvalidDocument, e.class
596
- assert_match(/Cannot serialize/, e.message)
597
- end
598
- end
599
- end
600
-
601
- def test_do_not_change_original_object
602
- val = BSON::OrderedHash.new
603
- val['not_id'] = 1
604
- val['_id'] = 2
605
- assert val.keys.include?('_id')
606
- @encoder.serialize(val)
607
- assert val.keys.include?('_id')
608
-
609
- val = {'a' => 'foo', 'b' => 'bar', :_id => 42, 'z' => 'hello'}
610
- assert val.keys.include?(:_id)
611
- @encoder.serialize(val)
612
- assert val.keys.include?(:_id)
613
- end
614
-
615
- # note we only test for _id here because in the general case we will
616
- # write duplicates for :key and "key". _id is a special case because
617
- # we call has_key? to check for it's existence rather than just iterating
618
- # over it like we do for the rest of the keys. thus, things like
619
- # HashWithIndifferentAccess can cause problems for _id but not for other
620
- # keys. rather than require rails to test with HWIA directly, we do this
621
- # somewhat hacky test.
622
- #
623
- # Note that the driver only eliminates duplicate ids when move_id is true.
624
- def test_no_duplicate_id
625
- dup = {"_id" => "foo", :_id => "foo"}
626
- one = {"_id" => "foo"}
627
-
628
- assert_equal @encoder.serialize(one, false, true).to_a, @encoder.serialize(dup, false, true).to_a
629
- end
630
-
631
- def test_duplicate_keys
632
- #dup = {"_foo" => "foo", :_foo => "foo"}
633
- #one = {"_foo" => "foo"}
634
-
635
- #assert_equal @encoder.serialize(one).to_a, @encoder.serialize(dup).to_a
636
- #warn "Pending test for duplicate keys"
637
- end
638
-
639
- def test_no_duplicate_id_when_moving_id
640
- dup = {"_id" => "foo", :_id => "foo"}
641
- one = {:_id => "foo"}
642
-
643
- assert_equal @encoder.serialize(one, false, true).to_s, @encoder.serialize(dup, false, true).to_s
644
- end
645
-
646
- def test_null_character
647
- doc = {"a" => "\x00"}
648
-
649
- assert_doc_pass(doc)
650
-
651
- assert_raise InvalidDocument do
652
- @encoder.serialize({"\x00" => "a"})
653
- end
654
-
655
- assert_raise InvalidDocument do
656
- @encoder.serialize({"a" => (Regexp.compile "ab\x00c")})
657
- end
658
- end
659
-
660
- def test_max_key
661
- doc = {"a" => MaxKey.new}
662
- assert_doc_pass(doc)
663
- end
664
-
665
- def test_min_key
666
- doc = {"a" => MinKey.new}
667
- assert_doc_pass(doc)
668
- end
669
-
670
- def test_invalid_object
671
- o = Object.new
672
- assert_raise InvalidDocument do
673
- @encoder.serialize({:foo => o})
674
- end
675
-
676
- assert_raise InvalidDocument do
677
- @encoder.serialize({:foo => Date.today})
678
- end
679
- end
680
-
681
- def test_move_id
682
- a = BSON::OrderedHash.new
683
- a['text'] = 'abc'
684
- a['key'] = 'abc'
685
- a['_id'] = 1
686
-
687
-
688
- assert_equal ")\000\000\000\020_id\000\001\000\000\000\002text" +
689
- "\000\004\000\000\000abc\000\002key\000\004\000\000\000abc\000\000",
690
- @encoder.serialize(a, false, true).to_s
691
-
692
- assert_equal ")\000\000\000\002text\000\004\000\000\000abc\000\002key" +
693
- "\000\004\000\000\000abc\000\020_id\000\001\000\000\000\000",
694
- @encoder.serialize(a, false, false).to_s
695
- end
696
-
697
- def test_move_id_with_nested_doc
698
- b = BSON::OrderedHash.new
699
- b['text'] = 'abc'
700
- b['_id'] = 2
701
- c = BSON::OrderedHash.new
702
- c['text'] = 'abc'
703
- c['hash'] = b
704
- c['_id'] = 3
705
- assert_equal ">\000\000\000\020_id\000\003\000\000\000\002text" +
706
- "\000\004\000\000\000abc\000\003hash\000\034\000\000" +
707
- "\000\002text\000\004\000\000\000abc\000\020_id\000\002\000\000\000\000\000",
708
- @encoder.serialize(c, false, true).to_s
709
-
710
- # Java doesn't support this. Isn't actually necessary.
711
- if !(RUBY_PLATFORM =~ /java/)
712
- assert_equal ">\000\000\000\002text\000\004\000\000\000abc\000\003hash" +
713
- "\000\034\000\000\000\002text\000\004\000\000\000abc\000\020_id" +
714
- "\000\002\000\000\000\000\020_id\000\003\000\000\000\000",
715
- @encoder.serialize(c, false, false).to_s
716
- end
717
- end
718
-
719
- def test_invalid_key_names
720
- assert @encoder.serialize({"hello" => "world"}, true)
721
- assert @encoder.serialize({"hello" => {"hello" => "world"}}, true)
722
-
723
- assert @encoder.serialize({"he$llo" => "world"}, true)
724
- assert @encoder.serialize({"hello" => {"hell$o" => "world"}}, true)
725
-
726
- assert_raise BSON::InvalidDocument do
727
- @encoder.serialize({"he\0llo" => "world"}, true)
728
- end
729
-
730
- assert_raise BSON::InvalidKeyName do
731
- @encoder.serialize({"$hello" => "world"}, true)
732
- end
733
-
734
- assert_raise BSON::InvalidKeyName do
735
- @encoder.serialize({"hello" => {"$hello" => "world"}}, true)
736
- end
737
-
738
- assert_raise BSON::InvalidKeyName do
739
- @encoder.serialize({".hello" => "world"}, true)
740
- end
741
-
742
- assert_raise BSON::InvalidKeyName do
743
- @encoder.serialize({"hello" => {".hello" => "world"}}, true)
744
- end
745
-
746
- assert_raise BSON::InvalidKeyName do
747
- @encoder.serialize({"hello." => "world"}, true)
748
- end
749
-
750
- assert_raise BSON::InvalidKeyName do
751
- @encoder.serialize({"hello" => {"hello." => "world"}}, true)
752
- end
753
-
754
- assert_raise BSON::InvalidKeyName do
755
- @encoder.serialize({"hel.lo" => "world"}, true)
756
- end
757
-
758
- assert_raise BSON::InvalidKeyName do
759
- @encoder.serialize({"hello" => {"hel.lo" => "world"}}, true)
760
- end
761
- end
762
- end