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.
- data/README.md +15 -15
- data/Rakefile +38 -17
- data/docs/FAQ.md +4 -0
- data/docs/HISTORY.md +59 -0
- data/docs/RELEASES.md +33 -0
- data/docs/REPLICA_SETS.md +13 -16
- data/lib/mongo/collection.rb +157 -69
- data/lib/mongo/connection.rb +189 -65
- data/lib/mongo/cursor.rb +43 -29
- data/lib/mongo/db.rb +63 -43
- data/lib/mongo/exceptions.rb +4 -1
- data/lib/mongo/gridfs/grid.rb +1 -1
- data/lib/mongo/gridfs/grid_ext.rb +1 -1
- data/lib/mongo/gridfs/grid_file_system.rb +1 -1
- data/lib/mongo/gridfs/grid_io.rb +89 -8
- data/lib/mongo/gridfs/grid_io_fix.rb +1 -1
- data/lib/mongo/repl_set_connection.rb +72 -20
- data/lib/mongo/test.rb +20 -0
- data/lib/mongo/util/conversions.rb +1 -1
- data/lib/mongo/util/core_ext.rb +11 -1
- data/lib/mongo/util/pool.rb +67 -15
- data/lib/mongo/util/server_version.rb +1 -1
- data/lib/mongo/util/support.rb +1 -1
- data/lib/mongo/util/uri_parser.rb +127 -13
- data/lib/mongo.rb +38 -2
- data/test/async/collection_test.rb +224 -0
- data/test/async/connection_test.rb +24 -0
- data/test/async/cursor_test.rb +162 -0
- data/test/async/worker_pool_test.rb +99 -0
- data/test/auxillary/fork_test.rb +30 -0
- data/test/auxillary/repl_set_auth_test.rb +58 -0
- data/test/auxillary/threaded_authentication_test.rb +101 -0
- data/test/bson/bson_test.rb +140 -28
- data/test/bson/byte_buffer_test.rb +18 -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 +104 -15
- data/test/connection_test.rb +78 -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 +30 -52
- 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/load/resque/load.rb +21 -0
- data/test/load/resque/processor.rb +26 -0
- data/test/load/thin/load.rb +24 -0
- data/test/load/unicorn/load.rb +23 -0
- data/test/load/unicorn/unicorn.rb +29 -0
- data/test/replica_sets/connect_test.rb +11 -1
- data/test/replica_sets/connection_string_test.rb +32 -0
- data/test/replica_sets/query_secondaries.rb +16 -0
- data/test/replica_sets/query_test.rb +10 -0
- data/test/replica_sets/replication_ack_test.rb +2 -0
- data/test/replica_sets/rs_test_helper.rb +9 -11
- 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/tools/auth_repl_set_manager.rb +14 -0
- data/test/tools/load.rb +58 -0
- data/test/tools/repl_set_manager.rb +34 -9
- data/test/tools/sharding_manager.rb +202 -0
- data/test/tools/test.rb +3 -12
- data/test/unit/collection_test.rb +20 -24
- data/test/unit/connection_test.rb +4 -18
- data/test/unit/cursor_test.rb +16 -6
- data/test/unit/db_test.rb +10 -11
- data/test/unit/repl_set_connection_test.rb +0 -23
- data/test/unit/safe_test.rb +3 -3
- data/test/uri_test.rb +91 -0
- metadata +49 -12
- 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
|