mongo 1.8.4 → 1.8.5

Sign up to get free protection for your applications and to get access to all the features.
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