mongo 1.1.5 → 1.3.0

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 (76) hide show
  1. data/README.md +15 -15
  2. data/Rakefile +38 -17
  3. data/docs/FAQ.md +4 -0
  4. data/docs/HISTORY.md +59 -0
  5. data/docs/RELEASES.md +33 -0
  6. data/docs/REPLICA_SETS.md +13 -16
  7. data/lib/mongo/collection.rb +157 -69
  8. data/lib/mongo/connection.rb +189 -65
  9. data/lib/mongo/cursor.rb +43 -29
  10. data/lib/mongo/db.rb +63 -43
  11. data/lib/mongo/exceptions.rb +4 -1
  12. data/lib/mongo/gridfs/grid.rb +1 -1
  13. data/lib/mongo/gridfs/grid_ext.rb +1 -1
  14. data/lib/mongo/gridfs/grid_file_system.rb +1 -1
  15. data/lib/mongo/gridfs/grid_io.rb +89 -8
  16. data/lib/mongo/gridfs/grid_io_fix.rb +1 -1
  17. data/lib/mongo/repl_set_connection.rb +72 -20
  18. data/lib/mongo/test.rb +20 -0
  19. data/lib/mongo/util/conversions.rb +1 -1
  20. data/lib/mongo/util/core_ext.rb +11 -1
  21. data/lib/mongo/util/pool.rb +67 -15
  22. data/lib/mongo/util/server_version.rb +1 -1
  23. data/lib/mongo/util/support.rb +1 -1
  24. data/lib/mongo/util/uri_parser.rb +127 -13
  25. data/lib/mongo.rb +38 -2
  26. data/test/async/collection_test.rb +224 -0
  27. data/test/async/connection_test.rb +24 -0
  28. data/test/async/cursor_test.rb +162 -0
  29. data/test/async/worker_pool_test.rb +99 -0
  30. data/test/auxillary/fork_test.rb +30 -0
  31. data/test/auxillary/repl_set_auth_test.rb +58 -0
  32. data/test/auxillary/threaded_authentication_test.rb +101 -0
  33. data/test/bson/bson_test.rb +140 -28
  34. data/test/bson/byte_buffer_test.rb +18 -0
  35. data/test/bson/object_id_test.rb +14 -1
  36. data/test/bson/ordered_hash_test.rb +7 -0
  37. data/test/bson/timestamp_test.rb +24 -0
  38. data/test/collection_test.rb +104 -15
  39. data/test/connection_test.rb +78 -2
  40. data/test/conversions_test.rb +10 -11
  41. data/test/cursor_fail_test.rb +1 -1
  42. data/test/cursor_message_test.rb +1 -1
  43. data/test/cursor_test.rb +33 -4
  44. data/test/db_api_test.rb +30 -52
  45. data/test/db_test.rb +3 -3
  46. data/test/grid_file_system_test.rb +0 -1
  47. data/test/grid_io_test.rb +72 -1
  48. data/test/grid_test.rb +16 -16
  49. data/test/load/resque/load.rb +21 -0
  50. data/test/load/resque/processor.rb +26 -0
  51. data/test/load/thin/load.rb +24 -0
  52. data/test/load/unicorn/load.rb +23 -0
  53. data/test/load/unicorn/unicorn.rb +29 -0
  54. data/test/replica_sets/connect_test.rb +11 -1
  55. data/test/replica_sets/connection_string_test.rb +32 -0
  56. data/test/replica_sets/query_secondaries.rb +16 -0
  57. data/test/replica_sets/query_test.rb +10 -0
  58. data/test/replica_sets/replication_ack_test.rb +2 -0
  59. data/test/replica_sets/rs_test_helper.rb +9 -11
  60. data/test/support/hash_with_indifferent_access.rb +0 -13
  61. data/test/support_test.rb +0 -1
  62. data/test/test_helper.rb +27 -8
  63. data/test/tools/auth_repl_set_manager.rb +14 -0
  64. data/test/tools/load.rb +58 -0
  65. data/test/tools/repl_set_manager.rb +34 -9
  66. data/test/tools/sharding_manager.rb +202 -0
  67. data/test/tools/test.rb +3 -12
  68. data/test/unit/collection_test.rb +20 -24
  69. data/test/unit/connection_test.rb +4 -18
  70. data/test/unit/cursor_test.rb +16 -6
  71. data/test/unit/db_test.rb +10 -11
  72. data/test/unit/repl_set_connection_test.rb +0 -23
  73. data/test/unit/safe_test.rb +3 -3
  74. data/test/uri_test.rb +91 -0
  75. metadata +49 -12
  76. data/docs/1.0_UPGRADE.md +0 -21
@@ -0,0 +1,162 @@
1
+ require 'test/test_helper'
2
+ require 'logger'
3
+
4
+ class CursorTest < Test::Unit::TestCase
5
+
6
+ include Mongo
7
+
8
+ @@connection = Connection.new(ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
9
+ ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT)
10
+ @@db = @@connection.db(MONGO_TEST_DB)
11
+ @@coll = @@db.collection('test')
12
+ @@version = @@connection.server_version
13
+
14
+ def wait_for_async
15
+ sleep 0.2
16
+ end
17
+
18
+ def setup
19
+ @@coll.remove
20
+ @@coll.insert('a' => 1) # collection not created until it's used
21
+ @@coll_full_name = "#{MONGO_TEST_DB}.test"
22
+ end
23
+
24
+ def test_async_explain
25
+ failsafe = mock('failsafe will get called in block', :call => true)
26
+
27
+ cursor = @@coll.find('a' => 1)
28
+
29
+ cursor.explain(:async => true) do |error, result|
30
+ assert_not_nil result['cursor']
31
+ assert_kind_of Numeric, result['n']
32
+ assert_kind_of Numeric, result['millis']
33
+ assert_kind_of Numeric, result['nscanned']
34
+ failsafe.call
35
+ end
36
+ wait_for_async
37
+ end
38
+
39
+ def test_async_count
40
+ failsafe = mock('failsafe will get called in block')
41
+ failsafe.expects(:call).times(3)
42
+
43
+ @@coll.remove
44
+
45
+ @@coll.find.count(:async => true) do |error, count|
46
+ assert_equal 0, count
47
+ failsafe.call
48
+ end
49
+ wait_for_async
50
+
51
+ 10.times do |i|
52
+ @@coll.save("x" => i)
53
+ end
54
+
55
+ @@coll.find.count(:async => true) do |error, count|
56
+ assert_equal 10, count
57
+ failsafe.call
58
+ end
59
+ wait_for_async
60
+
61
+ @@coll.find({"x" => 1}).count(:async => true) do |error, count|
62
+ assert_equal 1, count
63
+ failsafe.call
64
+ end
65
+ wait_for_async
66
+ end
67
+
68
+ def test_async_close
69
+ failsafe = mock('failsafe will get called in block', :call => true)
70
+
71
+ @@coll.remove
72
+ cursor = @@coll.find
73
+
74
+ cursor.close(:async => true) do |error, result|
75
+ assert_nil error
76
+ assert result
77
+ assert cursor.closed?
78
+ failsafe.call
79
+ end
80
+ wait_for_async
81
+ end
82
+
83
+ def test_async_has_next
84
+ failsafe = mock('failsafe will get called in block', :call => true)
85
+
86
+ @@coll.remove
87
+ 200.times do |n|
88
+ @@coll.save("x" => n)
89
+ end
90
+
91
+ cursor = @@coll.find
92
+ cursor.has_next?(:async => true) do |error, result|
93
+ assert_nil error
94
+ assert result
95
+ failsafe.call
96
+ end
97
+ wait_for_async
98
+ end
99
+
100
+ def test_async_next_document
101
+ failsafe = mock('failsafe will get called in block')
102
+ failsafe.expects(:call).times(2)
103
+
104
+ @@coll.remove
105
+ 200.times do |n|
106
+ @@coll.save("x" => n)
107
+ end
108
+
109
+ cursor = @@coll.find
110
+ cursor.next_document(:async => true) do |error, result|
111
+ assert_nil error
112
+ assert result
113
+ failsafe.call
114
+ end
115
+ wait_for_async
116
+
117
+ callback = Proc.new do |error, result|
118
+ assert_nil error
119
+ assert result
120
+ failsafe.call
121
+ end
122
+
123
+ cursor.next_document(:async => true, :callback => callback)
124
+ wait_for_async
125
+ end
126
+
127
+ def test_async_to_a
128
+ failsafe = mock('failsafe will get called in block')
129
+ failsafe.expects(:call)
130
+
131
+ @@coll.remove
132
+ total = 200
133
+ total.times do |n|
134
+ @@coll.save("x" => n)
135
+ end
136
+
137
+ cursor = @@coll.find
138
+ cursor.to_a(:async => true) do |error, result|
139
+ assert_nil error
140
+ assert_equal total, result.size
141
+ failsafe.call
142
+ end
143
+ wait_for_async
144
+ end
145
+
146
+ def test_async_each
147
+ @@coll.remove
148
+ total = 200
149
+ total.times do |n|
150
+ @@coll.save("x" => n)
151
+ end
152
+
153
+ cursor = @@coll.find
154
+ count = 0
155
+ cursor.each(:async => true) do |error, result|
156
+ count += 1
157
+ end
158
+ wait_for_async
159
+
160
+ assert_equal total, count
161
+ end
162
+ end
@@ -0,0 +1,99 @@
1
+ require 'test/test_helper'
2
+ include Mongo
3
+
4
+ class WorkerPoolTest < Test::Unit::TestCase
5
+ context "Initialization: " do
6
+
7
+ def wait_for_async
8
+ sleep 0.2
9
+ end
10
+
11
+ setup do
12
+ def new_mock_queue
13
+ stub_everything('queue')
14
+ end
15
+
16
+ def new_mock_thread
17
+ stub_everything('thread')
18
+ end
19
+ end
20
+
21
+ context "given a size" do
22
+ setup do
23
+ @size = 5
24
+ end
25
+
26
+ should "allocate a Thread 'size' times" do
27
+ Queue.stubs(:new).returns(new_mock_queue)
28
+ Thread.expects(:new).times(@size).returns(new_mock_thread)
29
+ Async::WorkerPool.new @size
30
+ end
31
+
32
+ should "set 'abort_on_exception' for each current thread" do
33
+ Queue.stubs(:new).returns(new_mock_queue)
34
+ thread = new_mock_thread
35
+ Thread.stubs(:new).returns(thread)
36
+
37
+ thread.expects(:abort_on_exception=).with(true).times(@size)
38
+
39
+ Async::WorkerPool.new @size
40
+ end
41
+
42
+ should "save each thread into the workers queue" do
43
+ assert_equal @size, Async::WorkerPool.new(@size).workers.size
44
+ end
45
+
46
+ end # context 'given a size'
47
+
48
+
49
+ context "given a job" do
50
+ setup do
51
+ @pool = Async::WorkerPool.new 1
52
+ @command = stub_everything('command')
53
+ @cmd_args = stub_everything('command args')
54
+ @callback = stub_everything('callback')
55
+ end
56
+
57
+ should "remove nils from the command args array and pass the results to the callback" do
58
+ args = [nil, @cmd_args]
59
+ @command.expects(:call).with(@cmd_args).returns(2)
60
+ @callback.expects(:call).with(nil, 2)
61
+
62
+ @pool.enqueue @command, args, @callback
63
+ wait_for_async
64
+ end
65
+
66
+ should "execute the original command with args and pass the results to the callback" do
67
+ @cmd_args.expects(:compact).returns(@cmd_args)
68
+ @command.expects(:call).with(@cmd_args).returns(2)
69
+ @callback.expects(:call).with(nil, 2)
70
+
71
+ @pool.enqueue @command, @cmd_args, @callback
72
+ wait_for_async
73
+ end
74
+
75
+ should "capture any exceptions and pass them to the callback" do
76
+ args = [@cmd_args]
77
+ error = StandardError.new
78
+ @command.expects(:call).with(@cmd_args).raises(error)
79
+ @callback.expects(:call).with(error, nil)
80
+
81
+ @pool.enqueue @command, args, @callback
82
+ wait_for_async
83
+ end
84
+
85
+ should "abort the thread when the callback raises an exception" do
86
+ args = [@cmd_args]
87
+ error = StandardError.new
88
+ @callback.expects(:call).raises(error)
89
+
90
+ assert_raises(StandardError) do
91
+ @pool.enqueue @command, args, @callback
92
+ wait_for_async
93
+ end
94
+ end
95
+ end # context 'given a job'
96
+
97
+
98
+ end
99
+ end
@@ -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
@@ -0,0 +1,58 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require './test/test_helper'
3
+ require './test/tools/auth_repl_set_manager'
4
+
5
+ class AuthTest < Test::Unit::TestCase
6
+ include Mongo
7
+
8
+ def setup
9
+ @manager = AuthReplSetManager.new(:start_port => 40000)
10
+ @manager.start_set
11
+ end
12
+
13
+ def teardown
14
+ @manager.cleanup_set
15
+ end
16
+
17
+ def test_repl_set_auth
18
+ @conn = ReplSetConnection.new([@manager.host, @manager.ports[0]], [@manager.host, @manager.ports[1]],
19
+ [@manager.host, @manager.ports[2]], :name => @manager.name)
20
+
21
+ # Add an admin user
22
+ @conn['admin'].add_user("me", "secret")
23
+
24
+ # Ensure that insert fails
25
+ assert_raise_error Mongo::OperationFailure, "unauthorized" do
26
+ @conn['foo']['stuff'].insert({:a => 2}, :safe => {:w => 3})
27
+ end
28
+
29
+ # Then authenticate
30
+ assert @conn['admin'].authenticate("me", "secret")
31
+
32
+ # Insert should succeed now
33
+ assert @conn['foo']['stuff'].insert({:a => 2}, :safe => {:w => 3})
34
+
35
+ # So should a query
36
+ assert @conn['foo']['stuff'].find_one
37
+
38
+ # But not when we logout
39
+ @conn['admin'].logout
40
+
41
+ assert_raise_error Mongo::OperationFailure, "unauthorized" do
42
+ @conn['foo']['stuff'].find_one
43
+ end
44
+
45
+ # Same should apply to a random secondary
46
+ @slave1 = Connection.new(@conn.secondary_pools[0].host,
47
+ @conn.secondary_pools[0].port, :slave_ok => true)
48
+
49
+ # Find should fail
50
+ assert_raise_error Mongo::OperationFailure, "unauthorized" do
51
+ @slave1['foo']['stuff'].find_one
52
+ end
53
+
54
+ # But not when authenticated
55
+ @slave1['admin'].authenticate("me", "secret")
56
+ assert @slave1['foo']['stuff'].find_one
57
+ end
58
+ end
@@ -0,0 +1,101 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require 'mongo'
3
+ require 'thread'
4
+ require 'test/unit'
5
+ require './test/test_helper'
6
+
7
+ # NOTE: This test requires bouncing the server.
8
+ # It also requires that a user exists on the admin database.
9
+ class AuthenticationTest < Test::Unit::TestCase
10
+ include Mongo
11
+
12
+ def setup
13
+ @conn = standard_connection(:pool_size => 10)
14
+ @db1 = @conn.db('mongo-ruby-test-auth1')
15
+ @db2 = @conn.db('mongo-ruby-test-auth2')
16
+ @admin = @conn.db('admin')
17
+ end
18
+
19
+ def teardown
20
+ @db1.authenticate('user1', 'secret')
21
+ @db2.authenticate('user2', 'secret')
22
+ @conn.drop_database('mongo-ruby-test-auth1')
23
+ @conn.drop_database('mongo-ruby-test-auth2')
24
+ end
25
+
26
+ def threaded_exec
27
+ threads = []
28
+
29
+ 100.times do
30
+ threads << Thread.new do
31
+ yield
32
+ end
33
+ end
34
+
35
+ 100.times do |n|
36
+ threads[n].join
37
+ end
38
+ end
39
+
40
+ def test_authenticate
41
+ @admin.authenticate('bob', 'secret')
42
+ @db1.add_user('user1', 'secret')
43
+ @db2.add_user('user2', 'secret')
44
+ @admin.logout
45
+
46
+ threaded_exec do
47
+ assert_raise Mongo::OperationFailure do
48
+ @db1['stuff'].insert({:a => 2}, :safe => true)
49
+ end
50
+ end
51
+
52
+ threaded_exec do
53
+ assert_raise Mongo::OperationFailure do
54
+ @db2['stuff'].insert({:a => 2}, :safe => true)
55
+ end
56
+ end
57
+
58
+ @db1.authenticate('user1', 'secret')
59
+ @db2.authenticate('user2', 'secret')
60
+
61
+ threaded_exec do
62
+ assert @db1['stuff'].insert({:a => 2}, :safe => true)
63
+ end
64
+
65
+ threaded_exec do
66
+ assert @db2['stuff'].insert({:a => 2}, :safe => true)
67
+ end
68
+
69
+ puts "Please bounce the server."
70
+ gets
71
+
72
+ # Here we reconnect.
73
+ begin
74
+ @db1['stuff'].find.to_a
75
+ rescue Mongo::ConnectionFailure
76
+ end
77
+
78
+ threaded_exec do
79
+ assert @db1['stuff'].insert({:a => 2}, :safe => true)
80
+ end
81
+
82
+ threaded_exec do
83
+ assert @db2['stuff'].insert({:a => 2}, :safe => true)
84
+ end
85
+
86
+ @db1.logout
87
+ threaded_exec do
88
+ assert_raise Mongo::OperationFailure do
89
+ @db1['stuff'].insert({:a => 2}, :safe => true)
90
+ end
91
+ end
92
+
93
+ @db2.logout
94
+ threaded_exec do
95
+ assert_raise Mongo::OperationFailure do
96
+ assert @db2['stuff'].insert({:a => 2}, :safe => true)
97
+ end
98
+ end
99
+ end
100
+
101
+ end