mongo-lyon 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/LICENSE.txt +190 -0
  2. data/README.md +344 -0
  3. data/Rakefile +202 -0
  4. data/bin/mongo_console +34 -0
  5. data/docs/1.0_UPGRADE.md +21 -0
  6. data/docs/CREDITS.md +123 -0
  7. data/docs/FAQ.md +116 -0
  8. data/docs/GridFS.md +158 -0
  9. data/docs/HISTORY.md +225 -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 +77 -0
  14. data/lib/mongo/collection.rb +872 -0
  15. data/lib/mongo/connection.rb +875 -0
  16. data/lib/mongo/cursor.rb +449 -0
  17. data/lib/mongo/db.rb +607 -0
  18. data/lib/mongo/exceptions.rb +68 -0
  19. data/lib/mongo/gridfs/grid.rb +106 -0
  20. data/lib/mongo/gridfs/grid_ext.rb +57 -0
  21. data/lib/mongo/gridfs/grid_file_system.rb +145 -0
  22. data/lib/mongo/gridfs/grid_io.rb +394 -0
  23. data/lib/mongo/gridfs/grid_io_fix.rb +38 -0
  24. data/lib/mongo/repl_set_connection.rb +342 -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 +185 -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 +181 -0
  31. data/lib/mongo/version.rb +3 -0
  32. data/mongo.gemspec +34 -0
  33. data/test/auxillary/1.4_features.rb +166 -0
  34. data/test/auxillary/authentication_test.rb +68 -0
  35. data/test/auxillary/autoreconnect_test.rb +41 -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 +614 -0
  41. data/test/bson/byte_buffer_test.rb +190 -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 +197 -0
  46. data/test/collection_test.rb +893 -0
  47. data/test/connection_test.rb +303 -0
  48. data/test/conversions_test.rb +120 -0
  49. data/test/cursor_fail_test.rb +75 -0
  50. data/test/cursor_message_test.rb +43 -0
  51. data/test/cursor_test.rb +457 -0
  52. data/test/db_api_test.rb +715 -0
  53. data/test/db_connection_test.rb +15 -0
  54. data/test/db_test.rb +287 -0
  55. data/test/grid_file_system_test.rb +244 -0
  56. data/test/grid_io_test.rb +120 -0
  57. data/test/grid_test.rb +200 -0
  58. data/test/load/thin/load.rb +24 -0
  59. data/test/load/unicorn/load.rb +23 -0
  60. data/test/replica_sets/connect_test.rb +86 -0
  61. data/test/replica_sets/connection_string_test.rb +32 -0
  62. data/test/replica_sets/count_test.rb +35 -0
  63. data/test/replica_sets/insert_test.rb +53 -0
  64. data/test/replica_sets/pooled_insert_test.rb +55 -0
  65. data/test/replica_sets/query_secondaries.rb +96 -0
  66. data/test/replica_sets/query_test.rb +51 -0
  67. data/test/replica_sets/replication_ack_test.rb +66 -0
  68. data/test/replica_sets/rs_test_helper.rb +27 -0
  69. data/test/safe_test.rb +68 -0
  70. data/test/support/hash_with_indifferent_access.rb +199 -0
  71. data/test/support/keys.rb +45 -0
  72. data/test/support_test.rb +19 -0
  73. data/test/test_helper.rb +83 -0
  74. data/test/threading/threading_with_large_pool_test.rb +90 -0
  75. data/test/threading_test.rb +87 -0
  76. data/test/tools/auth_repl_set_manager.rb +14 -0
  77. data/test/tools/repl_set_manager.rb +266 -0
  78. data/test/unit/collection_test.rb +130 -0
  79. data/test/unit/connection_test.rb +98 -0
  80. data/test/unit/cursor_test.rb +99 -0
  81. data/test/unit/db_test.rb +96 -0
  82. data/test/unit/grid_test.rb +49 -0
  83. data/test/unit/pool_test.rb +9 -0
  84. data/test/unit/repl_set_connection_test.rb +72 -0
  85. data/test/unit/safe_test.rb +125 -0
  86. data/test/uri_test.rb +91 -0
  87. metadata +202 -0
@@ -0,0 +1,32 @@
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 RS.host,
5
+ # on ports TEST_PORT, RS.ports[1], and TEST + 2.
6
+ class ConnectionStringTest < Test::Unit::TestCase
7
+ include Mongo
8
+
9
+ def setup
10
+ RS.restart_killed_nodes
11
+ end
12
+
13
+ def teardown
14
+ RS.restart_killed_nodes
15
+ end
16
+
17
+ def test_connect_with_connection_string
18
+ @conn = Connection.from_uri("mongodb://#{RS.host}:#{RS.ports[0]},#{RS.host}:#{RS.ports[1]}?replicaset=#{RS.name}")
19
+ assert @conn.is_a?(ReplSetConnection)
20
+ assert @conn.connected?
21
+ end
22
+
23
+ def test_connect_with_full_connection_string
24
+ @conn = Connection.from_uri("mongodb://#{RS.host}:#{RS.ports[0]},#{RS.host}:#{RS.ports[1]}?replicaset=#{RS.name};safe=true;w=2;fsync=true;slaveok=true")
25
+ assert @conn.is_a?(ReplSetConnection)
26
+ assert @conn.connected?
27
+ assert_equal 2, @conn.safe[:w]
28
+ assert @conn.safe[:fsync]
29
+ assert @conn.read_pool
30
+ end
31
+
32
+ end
@@ -0,0 +1,35 @@
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 ReplicaSetCountTest < Test::Unit::TestCase
7
+ include Mongo
8
+
9
+ def setup
10
+ @conn = ReplSetConnection.new([RS.host, RS.ports[0]], [RS.host, RS.ports[1]], [RS.host, RS.ports[2]])
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_correct_count_after_insertion_reconnect
21
+ @coll.insert({:a => 20}, :safe => {:w => 2, :wtimeout => 10000})
22
+ assert_equal 1, @coll.count
23
+
24
+ # Kill the current master node
25
+ @node = RS.kill_primary
26
+
27
+ rescue_connection_failure do
28
+ @coll.insert({:a => 30}, :safe => true)
29
+ end
30
+
31
+ @coll.insert({:a => 40}, :safe => true)
32
+ assert_equal 3, @coll.count, "Second count failed"
33
+ end
34
+
35
+ end
@@ -0,0 +1,53 @@
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 ReplicaSetInsertTest < Test::Unit::TestCase
7
+ include Mongo
8
+
9
+ def setup
10
+ @conn = ReplSetConnection.new([TEST_HOST, RS.ports[0]], [TEST_HOST, RS.ports[1]], [TEST_HOST, RS.ports[2]])
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_insert
21
+ @coll.save({:a => 20}, :safe => true)
22
+
23
+ RS.kill_primary
24
+
25
+ rescue_connection_failure do
26
+ @coll.save({:a => 30}, :safe => true)
27
+ end
28
+
29
+ @coll.save({:a => 40}, :safe => true)
30
+ @coll.save({:a => 50}, :safe => true)
31
+ @coll.save({:a => 60}, :safe => true)
32
+ @coll.save({:a => 70}, :safe => true)
33
+
34
+ # Restart the old master and wait for sync
35
+ RS.restart_killed_nodes
36
+ sleep(1)
37
+ results = []
38
+
39
+ rescue_connection_failure do
40
+ @coll.find.each {|r| results << r}
41
+ [20, 30, 40, 50, 60, 70].each do |a|
42
+ assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"
43
+ end
44
+ end
45
+
46
+ @coll.save({:a => 80}, :safe => true)
47
+ @coll.find.each {|r| results << r}
48
+ [20, 30, 40, 50, 60, 70, 80].each do |a|
49
+ assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a} on second find"
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,55 @@
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 ReplicaSetPooledInsertTest < Test::Unit::TestCase
7
+ include Mongo
8
+
9
+ def setup
10
+ @conn = ReplSetConnection.new([RS.host, RS.ports[0]], [RS.host, RS.ports[1]],
11
+ [RS.host, RS.ports[2]], :pool_size => 10, :timeout => 5)
12
+ @db = @conn.db(MONGO_TEST_DB)
13
+ @db.drop_collection("test-sets")
14
+ @coll = @db.collection("test-sets")
15
+ end
16
+
17
+ def teardown
18
+ RS.restart_killed_nodes
19
+ end
20
+
21
+ def test_insert
22
+ expected_results = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
23
+ @coll.save({:a => -1}, :safe => true)
24
+
25
+ RS.kill_primary
26
+
27
+ threads = []
28
+ 10.times do |i|
29
+ threads[i] = Thread.new do
30
+ rescue_connection_failure do
31
+ @coll.save({:a => i}, :safe => true)
32
+ end
33
+ end
34
+ end
35
+
36
+ # Restart the old master and wait for sync
37
+ RS.restart_killed_nodes
38
+ sleep(1)
39
+ results = []
40
+
41
+ rescue_connection_failure do
42
+ @coll.find.each {|r| results << r}
43
+ expected_results.each do |a|
44
+ assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"
45
+ end
46
+ end
47
+
48
+ @coll.save({:a => 10}, :safe => true)
49
+ @coll.find.each {|r| results << r}
50
+ (expected_results + [10]).each do |a|
51
+ assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a} on second find"
52
+ end
53
+ end
54
+
55
+ end
@@ -0,0 +1,96 @@
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 ReplicaSetQuerySecondariesTest < Test::Unit::TestCase
7
+ include Mongo
8
+
9
+ def setup
10
+ @conn = ReplSetConnection.new([RS.host, RS.ports[0]], :read_secondary => true)
11
+ @db = @conn.db(MONGO_TEST_DB)
12
+ @db.drop_collection("test-sets")
13
+ end
14
+
15
+ def teardown
16
+ RS.restart_killed_nodes
17
+ end
18
+
19
+ def test_read_primary
20
+ rescue_connection_failure do
21
+ assert !@conn.read_primary?
22
+ assert !@conn.primary?
23
+ end
24
+ end
25
+
26
+ def test_con
27
+ assert @conn.primary_pool, "No primary pool!"
28
+ assert @conn.read_pool, "No read pool!"
29
+ assert @conn.primary_pool.port != @conn.read_pool.port,
30
+ "Primary port and read port at the same!"
31
+ end
32
+
33
+ def test_query_secondaries
34
+ @coll = @db.collection("test-sets", :safe => {:w => 3, :wtimeout => 10000})
35
+ @coll.save({:a => 20})
36
+ @coll.save({:a => 30})
37
+ @coll.save({:a => 40})
38
+ results = []
39
+ @coll.find.each {|r| results << r["a"]}
40
+ assert results.include?(20)
41
+ assert results.include?(30)
42
+ assert results.include?(40)
43
+
44
+ RS.kill_primary
45
+
46
+ results = []
47
+ rescue_connection_failure do
48
+ @coll.find.each {|r| results << r}
49
+ [20, 30, 40].each do |a|
50
+ assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"
51
+ end
52
+ end
53
+ end
54
+
55
+ def test_kill_primary
56
+ @coll = @db.collection("test-sets", :safe => {:w => 3, :wtimeout => 10000})
57
+ @coll.save({:a => 20})
58
+ @coll.save({:a => 30})
59
+ assert_equal 2, @coll.find.to_a.length
60
+
61
+ # Should still be able to read immediately after killing master node
62
+ RS.kill_primary
63
+ assert_equal 2, @coll.find.to_a.length
64
+ rescue_connection_failure do
65
+ @coll.save({:a => 50}, :safe => {:w => 2, :wtimeout => 10000})
66
+ end
67
+ RS.restart_killed_nodes
68
+ @coll.save({:a => 50}, :safe => {:w => 2, :wtimeout => 10000})
69
+ assert_equal 4, @coll.find.to_a.length
70
+ end
71
+
72
+ def test_kill_secondary
73
+ @coll = @db.collection("test-sets", {:safe => {:w => 3, :wtimeout => 10000}})
74
+ @coll.save({:a => 20})
75
+ @coll.save({:a => 30})
76
+ assert_equal 2, @coll.find.to_a.length
77
+
78
+ read_node = RS.get_node_from_port(@conn.read_pool.port)
79
+ RS.kill(read_node)
80
+
81
+ # Should fail immediately on next read
82
+ old_read_pool_port = @conn.read_pool.port
83
+ assert_raise ConnectionFailure do
84
+ @coll.find.to_a.length
85
+ end
86
+
87
+ # Should eventually reconnect and be able to read
88
+ rescue_connection_failure do
89
+ length = @coll.find.to_a.length
90
+ assert_equal 2, length
91
+ end
92
+ new_read_pool_port = @conn.read_pool.port
93
+ assert old_read_pool != new_read_pool
94
+ end
95
+
96
+ end
@@ -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