mongo 1.2.4 → 1.3.0.rc0
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.
- data/README.md +13 -25
- data/Rakefile +9 -1
- data/docs/HISTORY.md +19 -0
- data/docs/RELEASES.md +33 -0
- data/docs/REPLICA_SETS.md +4 -3
- data/lib/mongo.rb +20 -2
- data/lib/mongo/collection.rb +15 -2
- data/lib/mongo/connection.rb +75 -14
- data/lib/mongo/cursor.rb +12 -4
- data/lib/mongo/db.rb +3 -3
- data/lib/mongo/exceptions.rb +3 -0
- data/lib/mongo/gridfs/grid_io.rb +88 -7
- data/lib/mongo/repl_set_connection.rb +29 -11
- data/lib/mongo/util/pool.rb +15 -6
- data/lib/mongo/util/timeout.rb +42 -0
- data/lib/mongo/util/uri_parser.rb +5 -1
- data/test/auxillary/fork_test.rb +30 -0
- data/test/bson/bson_test.rb +68 -27
- data/test/bson/byte_buffer_test.rb +11 -0
- data/test/bson/object_id_test.rb +14 -1
- data/test/bson/ordered_hash_test.rb +7 -0
- data/test/bson/timestamp_test.rb +24 -0
- data/test/collection_test.rb +41 -24
- data/test/connection_test.rb +33 -2
- data/test/conversions_test.rb +10 -11
- data/test/cursor_fail_test.rb +1 -1
- data/test/cursor_message_test.rb +1 -1
- data/test/cursor_test.rb +33 -4
- data/test/db_api_test.rb +13 -2
- data/test/db_test.rb +3 -3
- data/test/grid_file_system_test.rb +0 -1
- data/test/grid_io_test.rb +72 -1
- data/test/grid_test.rb +16 -16
- data/test/replica_sets/connect_test.rb +8 -0
- data/test/replica_sets/query_test.rb +10 -0
- data/test/support/hash_with_indifferent_access.rb +0 -13
- data/test/support_test.rb +0 -1
- data/test/test_helper.rb +27 -8
- data/test/timeout_test.rb +14 -0
- data/test/unit/collection_test.rb +1 -1
- data/test/unit/connection_test.rb +0 -13
- data/test/unit/cursor_test.rb +16 -6
- data/test/unit/db_test.rb +9 -11
- data/test/unit/repl_set_connection_test.rb +0 -13
- data/test/unit/safe_test.rb +1 -1
- metadata +15 -23
data/lib/mongo/db.rb
CHANGED
@@ -69,7 +69,7 @@ module Mongo
|
|
69
69
|
# the factory should not inject a new key).
|
70
70
|
#
|
71
71
|
# @option opts [Boolean, Hash] :safe (false) Set the default safe-mode options
|
72
|
-
#
|
72
|
+
# propagated to Collection objects instantiated off of this DB. If no
|
73
73
|
# value is provided, the default value set on this instance's Connection object will be used. This
|
74
74
|
# default can be overridden upon instantiation of any collection by explicity setting a :safe value
|
75
75
|
# on initialization
|
@@ -272,7 +272,7 @@ module Mongo
|
|
272
272
|
if strict?
|
273
273
|
raise MongoDBError, "Collection #{name} already exists. Currently in strict mode."
|
274
274
|
else
|
275
|
-
return Collection.new(name, self)
|
275
|
+
return Collection.new(name, self, opts)
|
276
276
|
end
|
277
277
|
end
|
278
278
|
|
@@ -287,7 +287,7 @@ module Mongo
|
|
287
287
|
# Get a collection by name.
|
288
288
|
#
|
289
289
|
# @param [String] name the collection name.
|
290
|
-
# @param [Hash] opts any valid options that can
|
290
|
+
# @param [Hash] opts any valid options that can be passed to Collection#new.
|
291
291
|
#
|
292
292
|
# @raise [MongoDBError] if collection does not already exist and we're in +strict+ mode.
|
293
293
|
#
|
data/lib/mongo/exceptions.rb
CHANGED
@@ -57,6 +57,9 @@ module Mongo
|
|
57
57
|
# Raised when a database operation fails.
|
58
58
|
class OperationFailure < MongoDBError; end
|
59
59
|
|
60
|
+
# Raised when a socket read operation times out.
|
61
|
+
class OperationTimeout < ::Timeout::Error; end
|
62
|
+
|
60
63
|
# Raised when a client attempts to perform an invalid operation.
|
61
64
|
class InvalidOperation < MongoDBError; end
|
62
65
|
|
data/lib/mongo/gridfs/grid_io.rb
CHANGED
@@ -17,10 +17,6 @@
|
|
17
17
|
# ++
|
18
18
|
|
19
19
|
require 'digest/md5'
|
20
|
-
begin
|
21
|
-
require 'mime/types'
|
22
|
-
rescue LoadError
|
23
|
-
end
|
24
20
|
|
25
21
|
module Mongo
|
26
22
|
|
@@ -172,6 +168,91 @@ module Mongo
|
|
172
168
|
def tell
|
173
169
|
@file_position
|
174
170
|
end
|
171
|
+
alias :pos :tell
|
172
|
+
|
173
|
+
# Rewind the file. This is equivalent to seeking to the zeroth position.
|
174
|
+
#
|
175
|
+
# @return [Integer] the position of the file after rewinding (always zero).
|
176
|
+
def rewind
|
177
|
+
raise GridError, "file not opened for read" unless @mode[0] == ?r
|
178
|
+
seek(0)
|
179
|
+
end
|
180
|
+
|
181
|
+
# Return a boolean indicating whether the position pointer is
|
182
|
+
# at the end of the file.
|
183
|
+
#
|
184
|
+
# @return [Boolean]
|
185
|
+
def eof
|
186
|
+
raise GridError, "file not opened for read #{@mode}" unless @mode[0] == ?r
|
187
|
+
@file_position >= @file_length
|
188
|
+
end
|
189
|
+
alias :eof? :eof
|
190
|
+
|
191
|
+
# Return the next line from a GridFS file. This probably
|
192
|
+
# makes sense only if you're storing plain text. This method
|
193
|
+
# has a somewhat tricky API, which it inherits from Ruby's
|
194
|
+
# StringIO#gets.
|
195
|
+
#
|
196
|
+
# @param [String, Integer] separator or length. If a separator,
|
197
|
+
# read up to the separator. If a length, read the +length+ number
|
198
|
+
# of bytes. If nil, read the entire file.
|
199
|
+
# @param [Integer] length If a separator is provided, then
|
200
|
+
# read until either finding the separator or
|
201
|
+
# passing over the +length+ number of bytes.
|
202
|
+
#
|
203
|
+
# @return [String]
|
204
|
+
def gets(separator="\n", length=nil)
|
205
|
+
if separator.nil?
|
206
|
+
read_all
|
207
|
+
elsif separator.is_a?(Integer)
|
208
|
+
read_length(separator)
|
209
|
+
elsif separator.length > 1
|
210
|
+
result = ''
|
211
|
+
len = 0
|
212
|
+
match_idx = 0
|
213
|
+
match_num = separator.length - 1
|
214
|
+
to_match = separator[match_idx].chr
|
215
|
+
if length
|
216
|
+
matcher = lambda {|idx, num| idx < num && len < length }
|
217
|
+
else
|
218
|
+
matcher = lambda {|idx, num| idx < num}
|
219
|
+
end
|
220
|
+
while matcher.call(match_idx, match_num) && char = getc
|
221
|
+
result << char
|
222
|
+
len += 1
|
223
|
+
if char == to_match
|
224
|
+
while match_idx < match_num do
|
225
|
+
match_idx += 1
|
226
|
+
to_match = separator[match_idx].chr
|
227
|
+
char = getc
|
228
|
+
result << char
|
229
|
+
if char != to_match
|
230
|
+
match_idx = 0
|
231
|
+
to_match = separator[match_idx].chr
|
232
|
+
break
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
result
|
238
|
+
else
|
239
|
+
result = ''
|
240
|
+
len = 0
|
241
|
+
while char = getc
|
242
|
+
result << char
|
243
|
+
len += 1
|
244
|
+
break if char == separator || (length ? len >= length : false)
|
245
|
+
end
|
246
|
+
result
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
# Return the next byte from the GridFS file.
|
251
|
+
#
|
252
|
+
# @return [String]
|
253
|
+
def getc
|
254
|
+
read_length(1)
|
255
|
+
end
|
175
256
|
|
176
257
|
# Creates or updates the document from the files collection that
|
177
258
|
# stores the chunks' metadata. The file becomes available only after
|
@@ -260,7 +341,7 @@ module Mongo
|
|
260
341
|
if length.nil?
|
261
342
|
to_read = remaining
|
262
343
|
else
|
263
|
-
to_read
|
344
|
+
to_read = length > remaining ? remaining : length
|
264
345
|
end
|
265
346
|
return nil unless remaining > 0
|
266
347
|
|
@@ -335,8 +416,8 @@ module Mongo
|
|
335
416
|
@files_id = opts.delete(:_id) || BSON::ObjectId.new
|
336
417
|
@content_type = opts.delete(:content_type) || (defined? MIME) && get_content_type || DEFAULT_CONTENT_TYPE
|
337
418
|
@chunk_size = opts.delete(:chunk_size) || DEFAULT_CHUNK_SIZE
|
338
|
-
@metadata = opts.delete(:metadata)
|
339
|
-
@aliases = opts.delete(:aliases)
|
419
|
+
@metadata = opts.delete(:metadata)
|
420
|
+
@aliases = opts.delete(:aliases)
|
340
421
|
@file_length = 0
|
341
422
|
opts.each {|k, v| self[k] = v}
|
342
423
|
check_existing_file if @safe
|
@@ -29,8 +29,8 @@ module Mongo
|
|
29
29
|
# Connection#arbiters. This is useful if your application needs to connect manually to nodes other
|
30
30
|
# than the primary.
|
31
31
|
#
|
32
|
-
# @param [Array] args A list of host-port pairs
|
33
|
-
# the examples below for exactly how to use the constructor.
|
32
|
+
# @param [Array] args A list of host-port pairs to be used as seed nodes followed by a
|
33
|
+
# hash containing any options. See the examples below for exactly how to use the constructor.
|
34
34
|
#
|
35
35
|
# @option options [String] :rs_name (nil) The name of the replica set to connect to. You
|
36
36
|
# can use this option to verify that you're connecting to the right replica set.
|
@@ -47,7 +47,9 @@ module Mongo
|
|
47
47
|
# this is the number of seconds to wait for a new connection to be released before throwing an exception.
|
48
48
|
# Note: this setting is relevant only for multi-threaded applications.
|
49
49
|
#
|
50
|
-
# @example Connect to a replica set and provide two seed nodes
|
50
|
+
# @example Connect to a replica set and provide two seed nodes. Note that the number of seed nodes does
|
51
|
+
# not have to be equal to the number of replica set members. The purpose of seed nodes is to permit
|
52
|
+
# the driver to find at least one replica set member even if a member is down.
|
51
53
|
# ReplSetConnection.new(['localhost', 30000], ['localhost', 30001])
|
52
54
|
#
|
53
55
|
# @example Connect to a replica set providing two seed nodes and ensuring a connection to the replica set named 'prod':
|
@@ -99,7 +101,7 @@ module Mongo
|
|
99
101
|
#
|
100
102
|
# @raise [ConnectionFailure] if unable to connect to any host or port.
|
101
103
|
def connect
|
102
|
-
|
104
|
+
close
|
103
105
|
@nodes_to_try = @nodes.clone
|
104
106
|
|
105
107
|
while connecting?
|
@@ -133,6 +135,20 @@ module Mongo
|
|
133
135
|
@nodes_to_try.length > 0
|
134
136
|
end
|
135
137
|
|
138
|
+
# The replica set primary's host name.
|
139
|
+
#
|
140
|
+
# @return [String]
|
141
|
+
def host
|
142
|
+
super
|
143
|
+
end
|
144
|
+
|
145
|
+
# The replica set primary's port.
|
146
|
+
#
|
147
|
+
# @return [Integer]
|
148
|
+
def port
|
149
|
+
super
|
150
|
+
end
|
151
|
+
|
136
152
|
# Determine whether we're reading from a primary node. If false,
|
137
153
|
# this connection connects to a secondary node and @read_secondaries is true.
|
138
154
|
#
|
@@ -149,13 +165,6 @@ module Mongo
|
|
149
165
|
@secondary_pools.each do |pool|
|
150
166
|
pool.close
|
151
167
|
end
|
152
|
-
end
|
153
|
-
|
154
|
-
# If a ConnectionFailure is raised, this method will be called
|
155
|
-
# to close the connection and reset connection values.
|
156
|
-
# TODO: what's the point of this method?
|
157
|
-
def reset_connection
|
158
|
-
super
|
159
168
|
@secondaries = []
|
160
169
|
@secondary_pools = []
|
161
170
|
@arbiters = []
|
@@ -163,6 +172,15 @@ module Mongo
|
|
163
172
|
@nodes_to_try = []
|
164
173
|
end
|
165
174
|
|
175
|
+
# If a ConnectionFailure is raised, this method will be called
|
176
|
+
# to close the connection and reset connection values.
|
177
|
+
# @deprecated
|
178
|
+
def reset_connection
|
179
|
+
close
|
180
|
+
warn "ReplSetConnection#reset_connection is now deprecated. " +
|
181
|
+
"Use ReplSetConnection#close instead."
|
182
|
+
end
|
183
|
+
|
166
184
|
# Is it okay to connect to a slave?
|
167
185
|
#
|
168
186
|
# @return [Boolean]
|
data/lib/mongo/util/pool.rb
CHANGED
@@ -41,6 +41,7 @@ module Mongo
|
|
41
41
|
@socket_ops = Hash.new { |h, k| h[k] = [] }
|
42
42
|
|
43
43
|
@sockets = []
|
44
|
+
@pids = {}
|
44
45
|
@checked_out = []
|
45
46
|
end
|
46
47
|
|
@@ -54,6 +55,7 @@ module Mongo
|
|
54
55
|
end
|
55
56
|
@host = @port = nil
|
56
57
|
@sockets.clear
|
58
|
+
@pids.clear
|
57
59
|
@checked_out.clear
|
58
60
|
end
|
59
61
|
|
@@ -83,6 +85,7 @@ module Mongo
|
|
83
85
|
@connection.apply_saved_authentication(:socket => socket)
|
84
86
|
|
85
87
|
@sockets << socket
|
88
|
+
@pids[socket] = Process.pid
|
86
89
|
@checked_out << socket
|
87
90
|
socket
|
88
91
|
end
|
@@ -115,12 +118,22 @@ module Mongo
|
|
115
118
|
|
116
119
|
# Checks out the first available socket from the pool.
|
117
120
|
#
|
121
|
+
# If the pid has changed, remove the socket and check out
|
122
|
+
# new one.
|
123
|
+
#
|
118
124
|
# This method is called exclusively from #checkout;
|
119
125
|
# therefore, it runs within a mutex.
|
120
126
|
def checkout_existing_socket
|
121
127
|
socket = (@sockets - @checked_out).first
|
122
|
-
@
|
123
|
-
|
128
|
+
if @pids[socket] != Process.pid
|
129
|
+
@pids[socket] = nil
|
130
|
+
@sockets.delete(socket)
|
131
|
+
socket.close
|
132
|
+
checkout_new_socket
|
133
|
+
else
|
134
|
+
@checked_out << socket
|
135
|
+
socket
|
136
|
+
end
|
124
137
|
end
|
125
138
|
|
126
139
|
# Check out an existing socket or create a new socket if the maximum
|
@@ -155,10 +168,6 @@ module Mongo
|
|
155
168
|
return socket
|
156
169
|
else
|
157
170
|
# Otherwise, wait
|
158
|
-
if @logger
|
159
|
-
@logger.warn "MONGODB Waiting for available connection; " +
|
160
|
-
"#{@checked_out.size} of #{@size} connections checked out."
|
161
|
-
end
|
162
171
|
@queue.wait(@connection_mutex)
|
163
172
|
end
|
164
173
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# --
|
4
|
+
# Copyright (C) 2008-2011 10gen Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
# ++
|
18
|
+
module Mongo #:nodoc:
|
19
|
+
module TimeoutWrapper
|
20
|
+
extend self
|
21
|
+
|
22
|
+
def timeout_lib=(lib)
|
23
|
+
@@timeout_lib = lib
|
24
|
+
end
|
25
|
+
|
26
|
+
def timeout_lib
|
27
|
+
@@timeout_lib
|
28
|
+
end
|
29
|
+
|
30
|
+
def timeout(delay, &block)
|
31
|
+
if timeout_lib
|
32
|
+
begin
|
33
|
+
timeout_lib.timeout(delay, &block)
|
34
|
+
rescue ::Timeout::Error
|
35
|
+
raise Mongo::OperationTimeout
|
36
|
+
end
|
37
|
+
else
|
38
|
+
yield
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -20,7 +20,7 @@ module Mongo
|
|
20
20
|
class URIParser
|
21
21
|
|
22
22
|
DEFAULT_PORT = 27017
|
23
|
-
MONGODB_URI_MATCHER = /(([
|
23
|
+
MONGODB_URI_MATCHER = /(([-.\w]+):([^@]+)@)?([-.\w]+)(:([\w]+))?(\/([-\w]+))?/
|
24
24
|
MONGODB_URI_SPEC = "mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/database]"
|
25
25
|
SPEC_ATTRS = [:nodes, :auths]
|
26
26
|
OPT_ATTRS = [:connect, :replicaset, :slaveok, :safe, :w, :wtimeout, :fsync]
|
@@ -142,7 +142,11 @@ module Mongo
|
|
142
142
|
# This method uses the lambdas defined in OPT_VALID and OPT_CONV to validate
|
143
143
|
# and convert the given options.
|
144
144
|
def parse_options(opts)
|
145
|
+
# initialize instance variables for available options
|
146
|
+
OPT_VALID.keys.each { |k| instance_variable_set("@#{k}", nil) }
|
147
|
+
|
145
148
|
return unless opts
|
149
|
+
|
146
150
|
separator = opts.include?('&') ? '&' : ';'
|
147
151
|
opts.split(separator).each do |attr|
|
148
152
|
key, value = attr.split('=')
|
@@ -0,0 +1,30 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
require 'mongo'
|
3
|
+
require 'test/unit'
|
4
|
+
require './test/test_helper'
|
5
|
+
|
6
|
+
class ForkTest < Test::Unit::TestCase
|
7
|
+
include Mongo
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@conn = standard_connection
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_fork
|
14
|
+
# Now insert some data
|
15
|
+
10.times do |n|
|
16
|
+
@conn[MONGO_TEST_DB]['nums'].insert({:a => n})
|
17
|
+
end
|
18
|
+
|
19
|
+
# Now fork. You'll almost always see an exception here.
|
20
|
+
if !Kernel.fork
|
21
|
+
10.times do
|
22
|
+
assert @conn[MONGO_TEST_DB]['nums'].find_one
|
23
|
+
end
|
24
|
+
else
|
25
|
+
10.times do
|
26
|
+
assert @conn[MONGO_TEST_DB]['nums'].find_one
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/test/bson/bson_test.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
# encoding:utf-8
|
2
2
|
require './test/test_helper'
|
3
|
-
|
3
|
+
|
4
|
+
if RUBY_VERSION < '1.9'
|
5
|
+
require 'complex'
|
6
|
+
require 'rational'
|
7
|
+
end
|
4
8
|
require 'bigdecimal'
|
5
|
-
require 'rational'
|
6
9
|
|
7
10
|
begin
|
11
|
+
require 'tzinfo'
|
8
12
|
require 'active_support/core_ext'
|
9
13
|
Time.zone = "Pacific Time (US & Canada)"
|
10
14
|
Zone = Time.zone.now
|
@@ -116,15 +120,23 @@ class BSONTest < Test::Unit::TestCase
|
|
116
120
|
end
|
117
121
|
else
|
118
122
|
def test_non_utf8_string
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
+
assert_raise BSON::InvalidStringEncoding do
|
124
|
+
BSON::BSON_CODER.serialize({'str' => 'aé'.encode('iso-8859-1')})
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_invalid_utf8_string
|
129
|
+
str = "123\xD9"
|
130
|
+
assert !str.valid_encoding?
|
131
|
+
assert_raise BSON::InvalidStringEncoding do
|
132
|
+
BSON::BSON_CODER.serialize({'str' => str})
|
133
|
+
end
|
123
134
|
end
|
124
135
|
|
125
136
|
def test_non_utf8_key
|
126
|
-
|
127
|
-
|
137
|
+
assert_raise BSON::InvalidStringEncoding do
|
138
|
+
BSON::BSON_CODER.serialize({'aé'.encode('iso-8859-1') => 'hello'})
|
139
|
+
end
|
128
140
|
end
|
129
141
|
|
130
142
|
# Based on a test from sqlite3-ruby
|
@@ -134,14 +146,14 @@ class BSONTest < Test::Unit::TestCase
|
|
134
146
|
str = "壁に耳あり、障子に目あり"
|
135
147
|
bson = BSON::BSON_CODER.serialize("x" => str)
|
136
148
|
|
137
|
-
Encoding.default_internal = 'EUC-JP'
|
149
|
+
silently { Encoding.default_internal = 'EUC-JP' }
|
138
150
|
out = BSON::BSON_CODER.deserialize(bson)["x"]
|
139
151
|
|
140
152
|
assert_equal Encoding.default_internal, out.encoding
|
141
153
|
assert_equal str.encode('EUC-JP'), out
|
142
154
|
assert_equal str, out.encode(str.encoding)
|
143
155
|
ensure
|
144
|
-
Encoding.default_internal = before_enc
|
156
|
+
silently { Encoding.default_internal = before_enc }
|
145
157
|
end
|
146
158
|
end
|
147
159
|
|
@@ -161,12 +173,12 @@ class BSONTest < Test::Unit::TestCase
|
|
161
173
|
assert_doc_pass(doc)
|
162
174
|
end
|
163
175
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
176
|
+
def test_double
|
177
|
+
doc = {'doc' => 41.25}
|
178
|
+
assert_doc_pass(doc)
|
179
|
+
end
|
168
180
|
|
169
|
-
|
181
|
+
def test_int
|
170
182
|
doc = {'doc' => 42}
|
171
183
|
assert_doc_pass(doc)
|
172
184
|
|
@@ -246,8 +258,14 @@ class BSONTest < Test::Unit::TestCase
|
|
246
258
|
assert_in_delta doc['date'], doc2['date'], 0.001
|
247
259
|
end
|
248
260
|
|
261
|
+
def test_date_in_array
|
262
|
+
doc = {'date' => [Time.now.utc]}
|
263
|
+
bson = @encoder.serialize(doc)
|
264
|
+
doc2 = @encoder.deserialize(bson)
|
265
|
+
end
|
266
|
+
|
249
267
|
def test_date_returns_as_utc
|
250
|
-
doc = {'date' => Time.now}
|
268
|
+
doc = {'date' => Time.now.utc}
|
251
269
|
bson = @encoder.serialize(doc)
|
252
270
|
doc2 = @encoder.deserialize(bson)
|
253
271
|
assert doc2['date'].utc?
|
@@ -277,7 +295,7 @@ class BSONTest < Test::Unit::TestCase
|
|
277
295
|
ensure
|
278
296
|
if !invalid_date.is_a? Time
|
279
297
|
assert_equal InvalidDocument, e.class
|
280
|
-
assert_match
|
298
|
+
assert_match(/UTC Time/, e.message)
|
281
299
|
end
|
282
300
|
end
|
283
301
|
end
|
@@ -311,6 +329,20 @@ class BSONTest < Test::Unit::TestCase
|
|
311
329
|
bin = Binary.new
|
312
330
|
'binstring'.each_byte { |b| bin.put(b) }
|
313
331
|
|
332
|
+
doc = {'bin' => bin}
|
333
|
+
bson = @encoder.serialize(doc)
|
334
|
+
doc2 = @encoder.deserialize(bson)
|
335
|
+
bin2 = doc2['bin']
|
336
|
+
assert_kind_of Binary, bin2
|
337
|
+
assert_equal 'binstring', bin2.to_s
|
338
|
+
assert_equal Binary::SUBTYPE_SIMPLE, bin2.subtype
|
339
|
+
end
|
340
|
+
|
341
|
+
def test_binary_with_deprecated_subtype
|
342
|
+
bin = Binary.new
|
343
|
+
'binstring'.each_byte { |b| bin.put(b) }
|
344
|
+
bin.subtype = Binary::SUBTYPE_BYTES
|
345
|
+
|
314
346
|
doc = {'bin' => bin}
|
315
347
|
bson = @encoder.serialize(doc)
|
316
348
|
doc2 = @encoder.deserialize(bson)
|
@@ -328,7 +360,7 @@ class BSONTest < Test::Unit::TestCase
|
|
328
360
|
bin2 = doc2['bin']
|
329
361
|
assert_kind_of Binary, bin2
|
330
362
|
assert_equal 'somebinarystring', bin2.to_s
|
331
|
-
assert_equal Binary::
|
363
|
+
assert_equal Binary::SUBTYPE_SIMPLE, bin2.subtype
|
332
364
|
end
|
333
365
|
|
334
366
|
def test_binary_type
|
@@ -368,7 +400,7 @@ class BSONTest < Test::Unit::TestCase
|
|
368
400
|
bin2 = doc2['bin']
|
369
401
|
assert_kind_of Binary, bin2
|
370
402
|
assert_equal [1, 2, 3, 4, 5], bin2.to_a
|
371
|
-
assert_equal Binary::
|
403
|
+
assert_equal Binary::SUBTYPE_SIMPLE, bin2.subtype
|
372
404
|
end
|
373
405
|
|
374
406
|
def test_put_id_first
|
@@ -393,15 +425,24 @@ class BSONTest < Test::Unit::TestCase
|
|
393
425
|
if !(RUBY_PLATFORM =~ /java/)
|
394
426
|
def test_timestamp
|
395
427
|
val = {"test" => [4, 20]}
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
428
|
+
result = @encoder.deserialize([0x13, 0x00, 0x00, 0x00,
|
429
|
+
0x11, 0x74, 0x65, 0x73,
|
430
|
+
0x74, 0x00, 0x04, 0x00,
|
431
|
+
0x00, 0x00, 0x14, 0x00,
|
432
|
+
0x00, 0x00, 0x00])
|
401
433
|
|
434
|
+
assert_equal 4, result["test"][0]
|
435
|
+
assert_equal 20, result["test"][1]
|
402
436
|
end
|
403
437
|
end
|
404
438
|
|
439
|
+
def test_timestamp_type
|
440
|
+
ts = Timestamp.new(5000, 100)
|
441
|
+
doc = {:ts => ts}
|
442
|
+
bson = @encoder.serialize(doc)
|
443
|
+
assert_equal ts, @encoder.deserialize(bson)["ts"]
|
444
|
+
end
|
445
|
+
|
405
446
|
def test_overflow
|
406
447
|
doc = {"x" => 2**75}
|
407
448
|
assert_raise RangeError do
|
@@ -439,7 +480,7 @@ class BSONTest < Test::Unit::TestCase
|
|
439
480
|
rescue => e
|
440
481
|
ensure
|
441
482
|
assert_equal InvalidDocument, e.class
|
442
|
-
assert_match
|
483
|
+
assert_match(/Cannot serialize/, e.message)
|
443
484
|
end
|
444
485
|
end
|
445
486
|
end
|
@@ -573,7 +614,7 @@ class BSONTest < Test::Unit::TestCase
|
|
573
614
|
@encoder.serialize({"he\0llo" => "world"}, true)
|
574
615
|
end
|
575
616
|
|
576
|
-
|
617
|
+
assert_raise BSON::InvalidKeyName do
|
577
618
|
@encoder.serialize({"$hello" => "world"}, true)
|
578
619
|
end
|
579
620
|
|
@@ -581,7 +622,7 @@ class BSONTest < Test::Unit::TestCase
|
|
581
622
|
@encoder.serialize({"hello" => {"$hello" => "world"}}, true)
|
582
623
|
end
|
583
624
|
|
584
|
-
|
625
|
+
assert_raise BSON::InvalidKeyName do
|
585
626
|
@encoder.serialize({".hello" => "world"}, true)
|
586
627
|
end
|
587
628
|
|