jonbell-mongo 1.3.1.2

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 (88) hide show
  1. data/LICENSE.txt +190 -0
  2. data/README.md +333 -0
  3. data/Rakefile +215 -0
  4. data/bin/mongo_console +21 -0
  5. data/docs/CREDITS.md +123 -0
  6. data/docs/FAQ.md +116 -0
  7. data/docs/GridFS.md +158 -0
  8. data/docs/HISTORY.md +263 -0
  9. data/docs/RELEASES.md +33 -0
  10. data/docs/REPLICA_SETS.md +72 -0
  11. data/docs/TUTORIAL.md +247 -0
  12. data/docs/WRITE_CONCERN.md +28 -0
  13. data/lib/mongo.rb +97 -0
  14. data/lib/mongo/collection.rb +895 -0
  15. data/lib/mongo/connection.rb +926 -0
  16. data/lib/mongo/cursor.rb +474 -0
  17. data/lib/mongo/db.rb +617 -0
  18. data/lib/mongo/exceptions.rb +71 -0
  19. data/lib/mongo/gridfs/grid.rb +107 -0
  20. data/lib/mongo/gridfs/grid_ext.rb +57 -0
  21. data/lib/mongo/gridfs/grid_file_system.rb +146 -0
  22. data/lib/mongo/gridfs/grid_io.rb +485 -0
  23. data/lib/mongo/gridfs/grid_io_fix.rb +38 -0
  24. data/lib/mongo/repl_set_connection.rb +356 -0
  25. data/lib/mongo/util/conversions.rb +89 -0
  26. data/lib/mongo/util/core_ext.rb +60 -0
  27. data/lib/mongo/util/pool.rb +177 -0
  28. data/lib/mongo/util/server_version.rb +71 -0
  29. data/lib/mongo/util/support.rb +82 -0
  30. data/lib/mongo/util/uri_parser.rb +185 -0
  31. data/mongo.gemspec +34 -0
  32. data/test/auxillary/1.4_features.rb +166 -0
  33. data/test/auxillary/authentication_test.rb +68 -0
  34. data/test/auxillary/autoreconnect_test.rb +41 -0
  35. data/test/auxillary/fork_test.rb +30 -0
  36. data/test/auxillary/repl_set_auth_test.rb +58 -0
  37. data/test/auxillary/slave_connection_test.rb +36 -0
  38. data/test/auxillary/threaded_authentication_test.rb +101 -0
  39. data/test/bson/binary_test.rb +15 -0
  40. data/test/bson/bson_test.rb +654 -0
  41. data/test/bson/byte_buffer_test.rb +208 -0
  42. data/test/bson/hash_with_indifferent_access_test.rb +38 -0
  43. data/test/bson/json_test.rb +17 -0
  44. data/test/bson/object_id_test.rb +154 -0
  45. data/test/bson/ordered_hash_test.rb +210 -0
  46. data/test/bson/timestamp_test.rb +24 -0
  47. data/test/collection_test.rb +910 -0
  48. data/test/connection_test.rb +324 -0
  49. data/test/conversions_test.rb +119 -0
  50. data/test/cursor_fail_test.rb +75 -0
  51. data/test/cursor_message_test.rb +43 -0
  52. data/test/cursor_test.rb +483 -0
  53. data/test/db_api_test.rb +738 -0
  54. data/test/db_connection_test.rb +15 -0
  55. data/test/db_test.rb +315 -0
  56. data/test/grid_file_system_test.rb +259 -0
  57. data/test/grid_io_test.rb +209 -0
  58. data/test/grid_test.rb +258 -0
  59. data/test/load/thin/load.rb +24 -0
  60. data/test/load/unicorn/load.rb +23 -0
  61. data/test/replica_sets/connect_test.rb +112 -0
  62. data/test/replica_sets/connection_string_test.rb +32 -0
  63. data/test/replica_sets/count_test.rb +35 -0
  64. data/test/replica_sets/insert_test.rb +53 -0
  65. data/test/replica_sets/pooled_insert_test.rb +55 -0
  66. data/test/replica_sets/query_secondaries.rb +108 -0
  67. data/test/replica_sets/query_test.rb +51 -0
  68. data/test/replica_sets/replication_ack_test.rb +66 -0
  69. data/test/replica_sets/rs_test_helper.rb +27 -0
  70. data/test/safe_test.rb +68 -0
  71. data/test/support/hash_with_indifferent_access.rb +186 -0
  72. data/test/support/keys.rb +45 -0
  73. data/test/support_test.rb +18 -0
  74. data/test/test_helper.rb +102 -0
  75. data/test/threading/threading_with_large_pool_test.rb +90 -0
  76. data/test/threading_test.rb +87 -0
  77. data/test/tools/auth_repl_set_manager.rb +14 -0
  78. data/test/tools/repl_set_manager.rb +266 -0
  79. data/test/unit/collection_test.rb +130 -0
  80. data/test/unit/connection_test.rb +85 -0
  81. data/test/unit/cursor_test.rb +109 -0
  82. data/test/unit/db_test.rb +94 -0
  83. data/test/unit/grid_test.rb +49 -0
  84. data/test/unit/pool_test.rb +9 -0
  85. data/test/unit/repl_set_connection_test.rb +59 -0
  86. data/test/unit/safe_test.rb +125 -0
  87. data/test/uri_test.rb +91 -0
  88. metadata +224 -0
@@ -0,0 +1,51 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require './test/replica_sets/rs_test_helper'
3
+
4
+ # NOTE: This test expects a replica set of three nodes to be running
5
+ # on the local host.
6
+ class ReplicaSetQueryTest < Test::Unit::TestCase
7
+ include Mongo
8
+
9
+ def setup
10
+ @conn = ReplSetConnection.new([RS.host, RS.ports[0]])
11
+ @db = @conn.db(MONGO_TEST_DB)
12
+ @db.drop_collection("test-sets")
13
+ @coll = @db.collection("test-sets")
14
+ end
15
+
16
+ def teardown
17
+ RS.restart_killed_nodes
18
+ end
19
+
20
+ def test_query
21
+ @coll.save({:a => 20}, :safe => {:w => 3})
22
+ @coll.save({:a => 30}, :safe => {:w => 3})
23
+ @coll.save({:a => 40}, :safe => {:w => 3})
24
+ results = []
25
+ @coll.find.each {|r| results << r}
26
+ [20, 30, 40].each do |a|
27
+ assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"
28
+ end
29
+
30
+ puts "Benchmark before failover: #{benchmark_queries}"
31
+
32
+ RS.kill_primary
33
+
34
+ results = []
35
+ rescue_connection_failure do
36
+ @coll.find.each {|r| results << r}
37
+ [20, 30, 40].each do |a|
38
+ assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"
39
+ end
40
+
41
+ puts "Benchmark after failover: #{benchmark_queries}"
42
+ end
43
+ end
44
+
45
+ def benchmark_queries
46
+ t1 = Time.now
47
+ 10000.times { @coll.find_one }
48
+ Time.now - t1
49
+ end
50
+
51
+ end
@@ -0,0 +1,66 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require './test/replica_sets/rs_test_helper'
3
+
4
+ # NOTE: This test expects a replica set of three nodes to be running on local host.
5
+ class ReplicaSetAckTest < Test::Unit::TestCase
6
+ include Mongo
7
+
8
+ def setup
9
+ RS.ensure_up
10
+
11
+ @conn = ReplSetConnection.new([RS.host, RS.ports[0]])
12
+
13
+ @slave1 = Connection.new(@conn.secondary_pools[0].host,
14
+ @conn.secondary_pools[0].port, :slave_ok => true)
15
+
16
+ assert !@slave1.read_primary?
17
+
18
+ @db = @conn.db(MONGO_TEST_DB)
19
+ @db.drop_collection("test-sets")
20
+ @col = @db.collection("test-sets")
21
+ end
22
+
23
+ def test_safe_mode_with_w_failure
24
+ assert_raise_error OperationFailure, "timeout" do
25
+ @col.insert({:foo => 1}, :safe => {:w => 4, :wtimeout => 1, :fsync => true})
26
+ end
27
+ assert_raise_error OperationFailure, "timeout" do
28
+ @col.update({:foo => 1}, {:foo => 2}, :safe => {:w => 4, :wtimeout => 1, :fsync => true})
29
+ end
30
+ assert_raise_error OperationFailure, "timeout" do
31
+ @col.remove({:foo => 2}, :safe => {:w => 4, :wtimeout => 1, :fsync => true})
32
+ end
33
+ end
34
+
35
+ def test_safe_mode_replication_ack
36
+ @col.insert({:baz => "bar"}, :safe => {:w => 2, :wtimeout => 5000})
37
+
38
+ assert @col.insert({:foo => "0" * 5000}, :safe => {:w => 2, :wtimeout => 5000})
39
+ assert_equal 2, @slave1[MONGO_TEST_DB]["test-sets"].count
40
+
41
+ assert @col.update({:baz => "bar"}, {:baz => "foo"}, :safe => {:w => 2, :wtimeout => 5000})
42
+ assert @slave1[MONGO_TEST_DB]["test-sets"].find_one({:baz => "foo"})
43
+
44
+ assert @col.remove({}, :safe => {:w => 2, :wtimeout => 5000})
45
+ assert_equal 0, @slave1[MONGO_TEST_DB]["test-sets"].count
46
+ end
47
+
48
+ def test_last_error_responses
49
+ 20.times { @col.insert({:baz => "bar"}) }
50
+ response = @db.get_last_error(:w => 2, :wtimeout => 5000)
51
+ assert response['ok'] == 1
52
+ assert response['lastOp']
53
+
54
+ @col.update({}, {:baz => "foo"}, :multi => true)
55
+ response = @db.get_last_error(:w => 2, :wtimeout => 5000)
56
+ assert response['ok'] == 1
57
+ assert response['lastOp']
58
+
59
+ @col.remove({})
60
+ response = @db.get_last_error(:w => 2, :wtimeout => 5000)
61
+ assert response['ok'] == 1
62
+ assert response['n'] == 20
63
+ assert response['lastOp']
64
+ end
65
+
66
+ end
@@ -0,0 +1,27 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require './test/test_helper'
3
+ require './test/tools/repl_set_manager'
4
+
5
+ unless defined? RS
6
+ RS = ReplSetManager.new
7
+ RS.start_set
8
+ end
9
+
10
+ class Test::Unit::TestCase
11
+
12
+ # Generic code for rescuing connection failures and retrying operations.
13
+ # This could be combined with some timeout functionality.
14
+ def rescue_connection_failure(max_retries=60)
15
+ retries = 0
16
+ begin
17
+ yield
18
+ rescue Mongo::ConnectionFailure => ex
19
+ puts "Rescue attempt #{retries}: from #{ex}"
20
+ retries += 1
21
+ raise ex if retries > max_retries
22
+ sleep(1)
23
+ retry
24
+ end
25
+ end
26
+
27
+ end
data/test/safe_test.rb ADDED
@@ -0,0 +1,68 @@
1
+ require './test/test_helper'
2
+ include Mongo
3
+
4
+ class SafeTest < Test::Unit::TestCase
5
+ context "Safe mode propogation: " do
6
+ setup do
7
+ @con = standard_connection(:safe => {:w => 1})
8
+ @db = @con[MONGO_TEST_DB]
9
+ @col = @db['test-safe']
10
+ @col.create_index([[:a, 1]], :unique => true)
11
+ @col.remove
12
+ end
13
+
14
+ should "propogate safe option on insert" do
15
+ @col.insert({:a => 1})
16
+
17
+ assert_raise_error(OperationFailure, "duplicate key") do
18
+ @col.insert({:a => 1})
19
+ end
20
+ end
21
+
22
+ should "allow safe override on insert" do
23
+ @col.insert({:a => 1})
24
+ @col.insert({:a => 1}, :safe => false)
25
+ end
26
+
27
+ should "propogate safe option on update" do
28
+ @col.insert({:a => 1})
29
+ @col.insert({:a => 2})
30
+
31
+ assert_raise_error(OperationFailure, "duplicate key") do
32
+ @col.update({:a => 2}, {:a => 1})
33
+ end
34
+ end
35
+
36
+ should "allow safe override on update" do
37
+ @col.insert({:a => 1})
38
+ @col.insert({:a => 2})
39
+ @col.update({:a => 2}, {:a => 1}, :safe => false)
40
+ end
41
+ end
42
+
43
+ context "Safe error objects" do
44
+ setup do
45
+ @con = standard_connection
46
+ @db = @con[MONGO_TEST_DB]
47
+ @col = @db['test']
48
+ @col.remove
49
+ @col.insert({:a => 1})
50
+ @col.insert({:a => 1})
51
+ @col.insert({:a => 1})
52
+ end
53
+
54
+ should "return object on update" do
55
+ response = @col.update({:a => 1}, {"$set" => {:a => 2}},
56
+ :multi => true, :safe => true)
57
+
58
+ assert response['updatedExisting']
59
+ assert_equal 3, response['n']
60
+ end
61
+
62
+ should "return object on remove" do
63
+ response = @col.remove({}, :safe => true)
64
+ assert_equal 3, response['n']
65
+ end
66
+ end
67
+
68
+ end
@@ -0,0 +1,186 @@
1
+ # Note: HashWithIndifferentAccess is so commonly used
2
+ # that we always need to make sure that the driver works
3
+ # with it.
4
+ #require File.join(File.dirname(__FILE__), 'keys.rb')
5
+
6
+ # This class has dubious semantics and we only have it so that
7
+ # people can write params[:key] instead of params['key']
8
+ # and they get the same value for both keys.
9
+
10
+ class Hash
11
+ # Return a new hash with all keys converted to strings.
12
+ def stringify_keys
13
+ dup.stringify_keys!
14
+ end
15
+
16
+ # Destructively convert all keys to strings.
17
+ def stringify_keys!
18
+ keys.each do |key|
19
+ self[key.to_s] = delete(key)
20
+ end
21
+ self
22
+ end
23
+
24
+ # Return a new hash with all keys converted to symbols, as long as
25
+ # they respond to +to_sym+.
26
+ def symbolize_keys
27
+ dup.symbolize_keys!
28
+ end
29
+
30
+ # Destructively convert all keys to symbols, as long as they respond
31
+ # to +to_sym+.
32
+ def symbolize_keys!
33
+ keys.each do |key|
34
+ self[(key.to_sym rescue key) || key] = delete(key)
35
+ end
36
+ self
37
+ end
38
+
39
+ alias_method :to_options, :symbolize_keys
40
+ #alias_method :to_options!, :symbolize_keys!
41
+ end
42
+
43
+ module ActiveSupport
44
+ class HashWithIndifferentAccess < Hash
45
+ def extractable_options?
46
+ true
47
+ end
48
+
49
+ def initialize(constructor = {})
50
+ if constructor.is_a?(Hash)
51
+ super()
52
+ update(constructor)
53
+ else
54
+ super(constructor)
55
+ end
56
+ end
57
+
58
+ def default(key = nil)
59
+ if key.is_a?(Symbol) && include?(key = key.to_s)
60
+ self[key]
61
+ else
62
+ super
63
+ end
64
+ end
65
+
66
+ def self.new_from_hash_copying_default(hash)
67
+ ActiveSupport::HashWithIndifferentAccess.new(hash).tap do |new_hash|
68
+ new_hash.default = hash.default
69
+ end
70
+ end
71
+
72
+ alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
73
+ alias_method :regular_update, :update unless method_defined?(:regular_update)
74
+
75
+ # Assigns a new value to the hash:
76
+ #
77
+ # hash = HashWithIndifferentAccess.new
78
+ # hash[:key] = "value"
79
+ #
80
+ def []=(key, value)
81
+ regular_writer(convert_key(key), convert_value(value))
82
+ end
83
+
84
+ # Updates the instantized hash with values from the second:
85
+ #
86
+ # hash_1 = HashWithIndifferentAccess.new
87
+ # hash_1[:key] = "value"
88
+ #
89
+ # hash_2 = HashWithIndifferentAccess.new
90
+ # hash_2[:key] = "New Value!"
91
+ #
92
+ # hash_1.update(hash_2) # => {"key"=>"New Value!"}
93
+ #
94
+ def update(other_hash)
95
+ other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
96
+ self
97
+ end
98
+
99
+ alias_method :merge!, :update
100
+
101
+ # Checks the hash for a key matching the argument passed in:
102
+ #
103
+ # hash = HashWithIndifferentAccess.new
104
+ # hash["key"] = "value"
105
+ # hash.key? :key # => true
106
+ # hash.key? "key" # => true
107
+ #
108
+ def key?(key)
109
+ super(convert_key(key))
110
+ end
111
+
112
+ alias_method :include?, :key?
113
+ alias_method :has_key?, :key?
114
+ alias_method :member?, :key?
115
+
116
+ # Fetches the value for the specified key, same as doing hash[key]
117
+ def fetch(key, *extras)
118
+ super(convert_key(key), *extras)
119
+ end
120
+
121
+ # Returns an array of the values at the specified indices:
122
+ #
123
+ # hash = HashWithIndifferentAccess.new
124
+ # hash[:a] = "x"
125
+ # hash[:b] = "y"
126
+ # hash.values_at("a", "b") # => ["x", "y"]
127
+ #
128
+ def values_at(*indices)
129
+ indices.collect {|key| self[convert_key(key)]}
130
+ end
131
+
132
+ # Returns an exact copy of the hash.
133
+ def dup
134
+ HashWithIndifferentAccess.new(self)
135
+ end
136
+
137
+ # Merges the instantized and the specified hashes together, giving precedence to the values from the second hash
138
+ # Does not overwrite the existing hash.
139
+ def merge(hash)
140
+ self.dup.update(hash)
141
+ end
142
+
143
+ # Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second.
144
+ # This overloaded definition prevents returning a regular hash, if reverse_merge is called on a HashWithDifferentAccess.
145
+ def reverse_merge(other_hash)
146
+ super self.class.new_from_hash_copying_default(other_hash)
147
+ end
148
+
149
+ def reverse_merge!(other_hash)
150
+ replace(reverse_merge( other_hash ))
151
+ end
152
+
153
+ # Removes a specified key from the hash.
154
+ def delete(key)
155
+ super(convert_key(key))
156
+ end
157
+
158
+ def stringify_keys!; self end
159
+ def stringify_keys; dup end
160
+ def symbolize_keys; to_hash.symbolize_keys end
161
+ def to_options!; self end
162
+
163
+ # Convert to a Hash with String keys.
164
+ def to_hash
165
+ Hash.new(default).merge!(self)
166
+ end
167
+
168
+ protected
169
+ def convert_key(key)
170
+ key.kind_of?(Symbol) ? key.to_s : key
171
+ end
172
+
173
+ def convert_value(value)
174
+ case value
175
+ when Hash
176
+ self.class.new_from_hash_copying_default(value)
177
+ when Array
178
+ value.collect { |e| e.is_a?(Hash) ? self.class.new_from_hash_copying_default(e) : e }
179
+ else
180
+ value
181
+ end
182
+ end
183
+ end
184
+ end
185
+
186
+ HashWithIndifferentAccess = ActiveSupport::HashWithIndifferentAccess
@@ -0,0 +1,45 @@
1
+ class Hash
2
+ # Return a new hash with all keys converted to strings.
3
+ def stringify_keys
4
+ dup.stringify_keys!
5
+ end
6
+
7
+ # Destructively convert all keys to strings.
8
+ def stringify_keys!
9
+ keys.each do |key|
10
+ self[key.to_s] = delete(key)
11
+ end
12
+ self
13
+ end
14
+
15
+ # Return a new hash with all keys converted to symbols, as long as
16
+ # they respond to +to_sym+.
17
+ def symbolize_keys
18
+ dup.symbolize_keys!
19
+ end
20
+
21
+ # Destructively convert all keys to symbols, as long as they respond
22
+ # to +to_sym+.
23
+ def symbolize_keys!
24
+ keys.each do |key|
25
+ self[(key.to_sym rescue key) || key] = delete(key)
26
+ end
27
+ self
28
+ end
29
+
30
+ alias_method :to_options, :symbolize_keys
31
+ #alias_method :to_options!, :symbolize_keys!
32
+
33
+ # Validate all keys in a hash match *valid keys, raising ArgumentError on a mismatch.
34
+ # Note that keys are NOT treated indifferently, meaning if you use strings for keys but assert symbols
35
+ # as keys, this will fail.
36
+ #
37
+ # ==== Examples
38
+ # { :name => "Rob", :years => "28" }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key(s): years"
39
+ # { :name => "Rob", :age => "28" }.assert_valid_keys("name", "age") # => raises "ArgumentError: Unknown key(s): name, age"
40
+ # { :name => "Rob", :age => "28" }.assert_valid_keys(:name, :age) # => passes, raises nothing
41
+ def assert_valid_keys(*valid_keys)
42
+ unknown_keys = keys - [valid_keys].flatten
43
+ raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
44
+ end
45
+ end