mongo 1.3.0 → 1.12.5

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 (185) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/{LICENSE.txt → LICENSE} +1 -1
  4. data/README.md +122 -271
  5. data/Rakefile +25 -209
  6. data/VERSION +1 -0
  7. data/bin/mongo_console +31 -9
  8. data/lib/mongo/bulk_write_collection_view.rb +387 -0
  9. data/lib/mongo/collection.rb +576 -269
  10. data/lib/mongo/collection_writer.rb +364 -0
  11. data/lib/mongo/connection/node.rb +249 -0
  12. data/lib/mongo/connection/pool.rb +340 -0
  13. data/lib/mongo/connection/pool_manager.rb +320 -0
  14. data/lib/mongo/connection/sharding_pool_manager.rb +67 -0
  15. data/lib/mongo/connection/socket/socket_util.rb +37 -0
  16. data/lib/mongo/connection/socket/ssl_socket.rb +95 -0
  17. data/lib/mongo/connection/socket/tcp_socket.rb +87 -0
  18. data/lib/mongo/connection/socket/unix_socket.rb +39 -0
  19. data/lib/mongo/connection/socket.rb +18 -0
  20. data/lib/mongo/connection.rb +7 -875
  21. data/lib/mongo/cursor.rb +403 -117
  22. data/lib/mongo/db.rb +444 -243
  23. data/lib/mongo/exception.rb +145 -0
  24. data/lib/mongo/functional/authentication.rb +455 -0
  25. data/lib/mongo/functional/logging.rb +85 -0
  26. data/lib/mongo/functional/read_preference.rb +183 -0
  27. data/lib/mongo/functional/scram.rb +556 -0
  28. data/lib/mongo/functional/uri_parser.rb +409 -0
  29. data/lib/mongo/functional/write_concern.rb +66 -0
  30. data/lib/mongo/functional.rb +20 -0
  31. data/lib/mongo/gridfs/grid.rb +30 -24
  32. data/lib/mongo/gridfs/grid_ext.rb +6 -10
  33. data/lib/mongo/gridfs/grid_file_system.rb +38 -20
  34. data/lib/mongo/gridfs/grid_io.rb +84 -75
  35. data/lib/mongo/gridfs.rb +18 -0
  36. data/lib/mongo/legacy.rb +140 -0
  37. data/lib/mongo/mongo_client.rb +697 -0
  38. data/lib/mongo/mongo_replica_set_client.rb +535 -0
  39. data/lib/mongo/mongo_sharded_client.rb +159 -0
  40. data/lib/mongo/networking.rb +372 -0
  41. data/lib/mongo/{util → utils}/conversions.rb +29 -8
  42. data/lib/mongo/{util → utils}/core_ext.rb +28 -18
  43. data/lib/mongo/{util → utils}/server_version.rb +4 -6
  44. data/lib/mongo/{util → utils}/support.rb +29 -31
  45. data/lib/mongo/utils/thread_local_variable_manager.rb +25 -0
  46. data/lib/mongo/utils.rb +19 -0
  47. data/lib/mongo.rb +51 -50
  48. data/mongo.gemspec +29 -32
  49. data/test/functional/authentication_test.rb +39 -0
  50. data/test/functional/bulk_api_stress_test.rb +133 -0
  51. data/test/functional/bulk_write_collection_view_test.rb +1198 -0
  52. data/test/functional/client_test.rb +627 -0
  53. data/test/functional/collection_test.rb +2175 -0
  54. data/test/functional/collection_writer_test.rb +83 -0
  55. data/test/{conversions_test.rb → functional/conversions_test.rb} +47 -3
  56. data/test/functional/cursor_fail_test.rb +57 -0
  57. data/test/functional/cursor_message_test.rb +56 -0
  58. data/test/functional/cursor_test.rb +683 -0
  59. data/test/functional/db_api_test.rb +835 -0
  60. data/test/functional/db_connection_test.rb +25 -0
  61. data/test/functional/db_test.rb +348 -0
  62. data/test/functional/grid_file_system_test.rb +285 -0
  63. data/test/{grid_io_test.rb → functional/grid_io_test.rb} +72 -11
  64. data/test/{grid_test.rb → functional/grid_test.rb} +88 -15
  65. data/test/functional/pool_test.rb +136 -0
  66. data/test/functional/safe_test.rb +98 -0
  67. data/test/functional/ssl_test.rb +29 -0
  68. data/test/functional/support_test.rb +62 -0
  69. data/test/functional/timeout_test.rb +60 -0
  70. data/test/functional/uri_test.rb +446 -0
  71. data/test/functional/write_concern_test.rb +118 -0
  72. data/test/helpers/general.rb +50 -0
  73. data/test/helpers/test_unit.rb +476 -0
  74. data/test/replica_set/authentication_test.rb +37 -0
  75. data/test/replica_set/basic_test.rb +189 -0
  76. data/test/replica_set/client_test.rb +393 -0
  77. data/test/replica_set/connection_test.rb +138 -0
  78. data/test/replica_set/count_test.rb +66 -0
  79. data/test/replica_set/cursor_test.rb +220 -0
  80. data/test/replica_set/insert_test.rb +157 -0
  81. data/test/replica_set/max_values_test.rb +151 -0
  82. data/test/replica_set/pinning_test.rb +105 -0
  83. data/test/replica_set/query_test.rb +73 -0
  84. data/test/replica_set/read_preference_test.rb +219 -0
  85. data/test/replica_set/refresh_test.rb +211 -0
  86. data/test/replica_set/replication_ack_test.rb +95 -0
  87. data/test/replica_set/ssl_test.rb +32 -0
  88. data/test/sharded_cluster/basic_test.rb +203 -0
  89. data/test/shared/authentication/basic_auth_shared.rb +260 -0
  90. data/test/shared/authentication/bulk_api_auth_shared.rb +249 -0
  91. data/test/shared/authentication/gssapi_shared.rb +176 -0
  92. data/test/shared/authentication/sasl_plain_shared.rb +96 -0
  93. data/test/shared/authentication/scram_shared.rb +92 -0
  94. data/test/shared/ssl_shared.rb +235 -0
  95. data/test/test_helper.rb +53 -94
  96. data/test/threading/basic_test.rb +120 -0
  97. data/test/tools/mongo_config.rb +708 -0
  98. data/test/tools/mongo_config_test.rb +160 -0
  99. data/test/unit/client_test.rb +381 -0
  100. data/test/unit/collection_test.rb +89 -53
  101. data/test/unit/connection_test.rb +282 -32
  102. data/test/unit/cursor_test.rb +206 -8
  103. data/test/unit/db_test.rb +55 -13
  104. data/test/unit/grid_test.rb +43 -16
  105. data/test/unit/mongo_sharded_client_test.rb +48 -0
  106. data/test/unit/node_test.rb +93 -0
  107. data/test/unit/pool_manager_test.rb +111 -0
  108. data/test/unit/read_pref_test.rb +406 -0
  109. data/test/unit/read_test.rb +159 -0
  110. data/test/unit/safe_test.rb +69 -36
  111. data/test/unit/sharding_pool_manager_test.rb +84 -0
  112. data/test/unit/write_concern_test.rb +175 -0
  113. data.tar.gz.sig +3 -0
  114. metadata +227 -216
  115. metadata.gz.sig +0 -0
  116. data/docs/CREDITS.md +0 -123
  117. data/docs/FAQ.md +0 -116
  118. data/docs/GridFS.md +0 -158
  119. data/docs/HISTORY.md +0 -244
  120. data/docs/RELEASES.md +0 -33
  121. data/docs/REPLICA_SETS.md +0 -72
  122. data/docs/TUTORIAL.md +0 -247
  123. data/docs/WRITE_CONCERN.md +0 -28
  124. data/lib/mongo/exceptions.rb +0 -71
  125. data/lib/mongo/gridfs/grid_io_fix.rb +0 -38
  126. data/lib/mongo/repl_set_connection.rb +0 -342
  127. data/lib/mongo/test.rb +0 -20
  128. data/lib/mongo/util/pool.rb +0 -177
  129. data/lib/mongo/util/uri_parser.rb +0 -185
  130. data/test/async/collection_test.rb +0 -224
  131. data/test/async/connection_test.rb +0 -24
  132. data/test/async/cursor_test.rb +0 -162
  133. data/test/async/worker_pool_test.rb +0 -99
  134. data/test/auxillary/1.4_features.rb +0 -166
  135. data/test/auxillary/authentication_test.rb +0 -68
  136. data/test/auxillary/autoreconnect_test.rb +0 -41
  137. data/test/auxillary/fork_test.rb +0 -30
  138. data/test/auxillary/repl_set_auth_test.rb +0 -58
  139. data/test/auxillary/slave_connection_test.rb +0 -36
  140. data/test/auxillary/threaded_authentication_test.rb +0 -101
  141. data/test/bson/binary_test.rb +0 -15
  142. data/test/bson/bson_test.rb +0 -649
  143. data/test/bson/byte_buffer_test.rb +0 -208
  144. data/test/bson/hash_with_indifferent_access_test.rb +0 -38
  145. data/test/bson/json_test.rb +0 -17
  146. data/test/bson/object_id_test.rb +0 -154
  147. data/test/bson/ordered_hash_test.rb +0 -204
  148. data/test/bson/timestamp_test.rb +0 -24
  149. data/test/collection_test.rb +0 -910
  150. data/test/connection_test.rb +0 -309
  151. data/test/cursor_fail_test.rb +0 -75
  152. data/test/cursor_message_test.rb +0 -43
  153. data/test/cursor_test.rb +0 -483
  154. data/test/db_api_test.rb +0 -726
  155. data/test/db_connection_test.rb +0 -15
  156. data/test/db_test.rb +0 -287
  157. data/test/grid_file_system_test.rb +0 -243
  158. data/test/load/resque/load.rb +0 -21
  159. data/test/load/resque/processor.rb +0 -26
  160. data/test/load/thin/load.rb +0 -24
  161. data/test/load/unicorn/load.rb +0 -23
  162. data/test/load/unicorn/unicorn.rb +0 -29
  163. data/test/replica_sets/connect_test.rb +0 -94
  164. data/test/replica_sets/connection_string_test.rb +0 -32
  165. data/test/replica_sets/count_test.rb +0 -35
  166. data/test/replica_sets/insert_test.rb +0 -53
  167. data/test/replica_sets/pooled_insert_test.rb +0 -55
  168. data/test/replica_sets/query_secondaries.rb +0 -96
  169. data/test/replica_sets/query_test.rb +0 -51
  170. data/test/replica_sets/replication_ack_test.rb +0 -66
  171. data/test/replica_sets/rs_test_helper.rb +0 -27
  172. data/test/safe_test.rb +0 -68
  173. data/test/support/hash_with_indifferent_access.rb +0 -186
  174. data/test/support/keys.rb +0 -45
  175. data/test/support_test.rb +0 -18
  176. data/test/threading/threading_with_large_pool_test.rb +0 -90
  177. data/test/threading_test.rb +0 -87
  178. data/test/tools/auth_repl_set_manager.rb +0 -14
  179. data/test/tools/load.rb +0 -58
  180. data/test/tools/repl_set_manager.rb +0 -266
  181. data/test/tools/sharding_manager.rb +0 -202
  182. data/test/tools/test.rb +0 -4
  183. data/test/unit/pool_test.rb +0 -9
  184. data/test/unit/repl_set_connection_test.rb +0 -59
  185. data/test/uri_test.rb +0 -91
@@ -0,0 +1,203 @@
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'test_helper'
16
+ include Mongo
17
+
18
+ class Cursor
19
+ public :construct_query_spec
20
+ end
21
+
22
+ class ShardedClusterBasicTest < Test::Unit::TestCase
23
+
24
+ def setup
25
+ ensure_cluster(:sc)
26
+ @document = { "name" => "test_user" }
27
+ @seeds = @sc.mongos_seeds
28
+ end
29
+
30
+ # TODO member.primary? ==> true
31
+ def test_connect
32
+ @client = sharded_connection
33
+ assert @client.connected?
34
+ assert_equal(@seeds.size, @client.seeds.size)
35
+ probe(@seeds.size)
36
+ @client.close
37
+ end
38
+
39
+ def test_connect_from_standard_client
40
+ mongos = @seeds.first
41
+ @client = MongoClient.new(*mongos.split(':'))
42
+ assert @client.connected?
43
+ assert @client.mongos?
44
+ @client.close
45
+ end
46
+
47
+ def test_read_from_client
48
+ host, port = @seeds.first.split(':')
49
+ tags = [{:dc => "mongolia"}]
50
+ @client = MongoClient.new(host, port, {:read => :secondary, :tag_sets => tags})
51
+ assert @client.connected?
52
+ cursor = Cursor.new(@client[TEST_DB]['whatever'], {})
53
+ assert_equal cursor.construct_query_spec['$readPreference'], {:mode => 'secondary', :tags => tags}
54
+ end
55
+
56
+ def test_find_one_with_read_secondary
57
+ @client = sharded_connection(:read => :secondary)
58
+ @client[TEST_DB]["users"].insert([ @document ])
59
+ assert_equal @client[TEST_DB]['users'].find_one["name"], "test_user"
60
+ end
61
+
62
+ def test_find_one_with_read_secondary_preferred
63
+ @client = sharded_connection(:read => :secondary_preferred)
64
+ @client[TEST_DB]["users"].insert([ @document ])
65
+ assert_equal @client[TEST_DB]['users'].find_one["name"], "test_user"
66
+ end
67
+
68
+ def test_find_one_with_read_primary
69
+ @client = sharded_connection(:read => :primary)
70
+ @client[TEST_DB]["users"].insert([ @document ])
71
+ assert_equal @client[TEST_DB]['users'].find_one["name"], "test_user"
72
+ end
73
+
74
+ def test_find_one_with_read_primary_preferred
75
+ @client = sharded_connection(:read => :primary_preferred)
76
+ @client[TEST_DB]["users"].insert([ @document ])
77
+ assert_equal @client[TEST_DB]['users'].find_one["name"], "test_user"
78
+ end
79
+
80
+ def test_read_from_sharded_client
81
+ tags = [{:dc => "mongolia"}]
82
+ @client = sharded_connection(:read => :secondary, :tag_sets => tags)
83
+ assert @client.connected?
84
+ cursor = Cursor.new(@client[TEST_DB]['whatever'], {})
85
+ assert_equal cursor.construct_query_spec['$readPreference'], {:mode => 'secondary', :tags => tags}
86
+ end
87
+
88
+ def test_hard_refresh
89
+ @client = sharded_connection
90
+ assert @client.connected?
91
+ @client.hard_refresh!
92
+ assert @client.connected?
93
+ @client.close
94
+ end
95
+
96
+ def test_reconnect
97
+ @client = sharded_connection
98
+ assert @client.connected?
99
+ router = @sc.servers(:routers).first
100
+ router.stop
101
+ probe(@seeds.size)
102
+ assert @client.connected?
103
+ @client.close
104
+ end
105
+
106
+ def test_mongos_failover
107
+ @client = sharded_connection(:refresh_interval => 5, :refresh_mode => :sync)
108
+ assert @client.connected?
109
+ # do a find to pin a pool
110
+ @client[TEST_DB]['test'].find_one
111
+ original_primary = @client.manager.primary
112
+ # stop the pinned member
113
+ @sc.member_by_name("#{original_primary[0]}:#{original_primary[1]}").stop
114
+ # assert that the client fails over to the next available mongos
115
+ assert_nothing_raised do
116
+ @client[TEST_DB]['test'].find_one
117
+ end
118
+
119
+ assert_not_equal original_primary, @client.manager.primary
120
+ assert @client.connected?
121
+ @client.close
122
+ end
123
+
124
+ def test_all_down
125
+ @client = sharded_connection
126
+ assert @client.connected?
127
+ @sc.servers(:routers).each{|router| router.stop}
128
+ assert_raises Mongo::ConnectionFailure do
129
+ probe(@seeds.size)
130
+ end
131
+ assert_false @client.connected?
132
+ @client.close
133
+ end
134
+
135
+ def test_cycle
136
+ @client = sharded_connection
137
+ assert @client.connected?
138
+ routers = @sc.servers(:routers)
139
+ while routers.size > 0 do
140
+ rescue_connection_failure do
141
+ probe(@seeds.size)
142
+ end
143
+ probe(@seeds.size)
144
+ router = routers.detect{|r| r.port == @client.manager.primary.last}
145
+ routers.delete(router)
146
+ router.stop
147
+ end
148
+ assert_raises Mongo::ConnectionFailure do
149
+ probe(@seeds.size)
150
+ end
151
+ assert_false @client.connected?
152
+ routers = @sc.servers(:routers).reverse
153
+ routers.each do |r|
154
+ r.start
155
+ @client.hard_refresh!
156
+ rescue_connection_failure do
157
+ probe(@seeds.size)
158
+ end
159
+ probe(@seeds.size)
160
+ end
161
+ @client.close
162
+ end
163
+
164
+ def test_wire_version_not_in_range
165
+ [
166
+ [Mongo::MongoClient::MAX_WIRE_VERSION+1, Mongo::MongoClient::MAX_WIRE_VERSION+1],
167
+ [Mongo::MongoClient::MIN_WIRE_VERSION-1, Mongo::MongoClient::MIN_WIRE_VERSION-1]
168
+ ].each do |min_wire_version_value, max_wire_version_value|
169
+ Mongo.module_eval <<-EVAL
170
+ class ShardingPoolManager
171
+ def max_wire_version
172
+ return #{max_wire_version_value}
173
+ end
174
+ def min_wire_version
175
+ return #{min_wire_version_value}
176
+ end
177
+ end
178
+ EVAL
179
+ @client = MongoShardedClient.new(@seeds, :connect => false)
180
+ assert !@client.connected?
181
+ assert_raises Mongo::ConnectionFailure do
182
+ @client.connect
183
+ end
184
+ end
185
+ Mongo.module_eval <<-EVAL
186
+ class ShardingPoolManager
187
+ attr_reader :max_wire_version, :min_wire_version
188
+ end
189
+ EVAL
190
+ end
191
+
192
+ private
193
+
194
+ def sharded_connection(opts={})
195
+ client = MongoShardedClient.new(@seeds, opts)
196
+ authenticate_client(client)
197
+ end
198
+
199
+ def probe(size)
200
+ authenticate_client(@client)
201
+ assert_equal(size, @client['config']['mongos'].find.to_a.size)
202
+ end
203
+ end
@@ -0,0 +1,260 @@
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module BasicAuthTests
16
+
17
+ def init_auth_basic
18
+ @test_user = 'bob'
19
+ @test_user_pwd = 'user'
20
+
21
+ # db user for cleanup (for pre-2.4)
22
+ @db.add_user('admin', 'cleanup', nil, :roles => [])
23
+ end
24
+
25
+ def teardown
26
+ return unless @client && @db
27
+ unless has_auth?(TEST_DB, TEST_USER)
28
+ @client[TEST_DB].authenticate(TEST_USER, TEST_USER_PWD)
29
+ end
30
+
31
+ if @client.server_version < '2.5'
32
+ @db['system.users'].remove
33
+ else
34
+ @db.command(:dropAllUsersFromDatabase => 1)
35
+ end
36
+ end
37
+
38
+ def remove_user(database, username, password)
39
+ database.authenticate(username, password) unless has_auth?(database.name, username)
40
+ database.remove_user(username)
41
+ database.logout
42
+ end
43
+
44
+ def has_auth?(db_name, username)
45
+ @client.auths.any? { |a| a[:source] == db_name && a[:username] == username }
46
+ end
47
+
48
+ def test_descriptive_mech_error
49
+ assert_raise_error Mongo::MongoArgumentError, Mongo::Authentication::MECHANISM_ERROR do
50
+ @db.authenticate('emily', nil, nil, nil, 'FAKE_MECHANISM')
51
+ end
52
+ assert_raise_error Mongo::MongoArgumentError, Mongo::Authentication::MECHANISM_ERROR do
53
+ uri = "mongodb://user:pwd@host:port/example?authSource=$external&authMechanism=FAKE_MECHANISM"
54
+ Mongo::MongoClient.from_uri(uri)
55
+ end
56
+ end
57
+
58
+ def test_add_remove_user
59
+ init_auth_basic
60
+
61
+ # add user
62
+ silently { @db.add_user(@test_user, @test_user_pwd) }
63
+ assert @db.authenticate(@test_user, @test_user_pwd)
64
+
65
+ # remove user
66
+ assert @db.remove_user(@test_user)
67
+ end
68
+
69
+ def test_update_user
70
+ init_auth_basic
71
+
72
+ # add user
73
+ silently { @db.add_user(@test_user, @test_user_pwd) }
74
+ assert @db.authenticate(@test_user, @test_user_pwd)
75
+ @db.logout
76
+
77
+ # update user
78
+ silently { @db.add_user(@test_user, 'updated') }
79
+ assert_raise Mongo::AuthenticationError do
80
+ @db.authenticate('bob', 'user')
81
+ end
82
+ assert @db.authenticate('bob', 'updated')
83
+ end
84
+
85
+ def test_remove_non_existent_user
86
+ init_auth_basic
87
+
88
+ if @client.server_version < '2.5'
89
+ assert_equal false, @db.remove_user('joe')
90
+ else
91
+ assert_raise Mongo::OperationFailure do
92
+ assert @db.remove_user('joe')
93
+ end
94
+ end
95
+ end
96
+
97
+ def test_authenticate
98
+ init_auth_basic
99
+ silently { @db.add_user(@test_user, @test_user_pwd) }
100
+ assert @db.authenticate(@test_user, @test_user_pwd)
101
+ end
102
+
103
+ def test_authenticate_non_existent_user
104
+ init_auth_basic
105
+ assert_raise Mongo::AuthenticationError do
106
+ @db.authenticate('frank', 'thetank')
107
+ end
108
+ end
109
+
110
+ def test_logout
111
+ init_auth_basic
112
+ silently { @db.add_user(@test_user, @test_user_pwd) }
113
+ assert @db.authenticate(@test_user, @test_user_pwd)
114
+ assert @db.logout
115
+ end
116
+
117
+ def test_authenticate_with_special_characters
118
+ init_auth_basic
119
+ silently { assert @db.add_user('foo:bar','@foo') }
120
+ assert @db.authenticate('foo:bar','@foo')
121
+ end
122
+
123
+ def test_authenticate_read_only
124
+ init_auth_basic
125
+ silently { @db.add_user(@test_user, @test_user_pwd, true) }
126
+ assert @db.authenticate(@test_user, @test_user_pwd)
127
+ end
128
+
129
+ def test_authenticate_with_connection_uri
130
+ init_auth_basic
131
+ silently { @db.add_user(@test_user, @test_user_pwd) }
132
+
133
+ uri = "mongodb://#{@test_user}:#{@test_user_pwd}@#{@host_info}/#{@db.name}"
134
+ client = Mongo::URIParser.new(uri).connection
135
+
136
+ assert client
137
+ assert_equal client.auths.size, 1
138
+ assert client[@db.name]['auth_test'].count
139
+
140
+ auth = client.auths.first
141
+ assert_equal @db.name, auth[:db_name]
142
+ assert_equal @test_user, auth[:username]
143
+ assert_equal @test_user_pwd, auth[:password]
144
+ end
145
+
146
+ def test_socket_auths
147
+ init_auth_basic
148
+ # setup
149
+ db_a = @client[TEST_DB + '_a']
150
+ silently { db_a.add_user('user_a', 'password') }
151
+ assert db_a.authenticate('user_a', 'password')
152
+
153
+ db_b = @client[TEST_DB + '_b']
154
+ silently { db_b.add_user('user_b', 'password') }
155
+ assert db_b.authenticate('user_b', 'password')
156
+
157
+ db_c = @client[TEST_DB + '_c']
158
+ silently { db_c.add_user('user_c', 'password') }
159
+ assert db_c.authenticate('user_c', 'password')
160
+
161
+ # client auths should be applied to socket on checkout
162
+ socket = @client.checkout_reader(:mode => :primary)
163
+ assert_equal 4, socket.auths.size
164
+ assert_equal @client.auths, socket.auths
165
+ @client.checkin(socket)
166
+
167
+ # logout should remove saved auth on socket and client
168
+ assert db_b.logout
169
+ socket = @client.checkout_reader(:mode => :primary)
170
+ assert_equal 3, socket.auths.size
171
+ assert_equal @client.auths, socket.auths
172
+ @client.checkin(socket)
173
+
174
+ # clean-up
175
+ db_b.authenticate('user_b', 'password')
176
+ remove_user(db_a, 'user_a', 'password')
177
+ remove_user(db_b, 'user_b', 'password')
178
+ remove_user(db_c, 'user_c', 'password')
179
+ end
180
+
181
+ def test_default_roles_non_admin
182
+ init_auth_basic
183
+ @db.stubs(:command).returns({}, true)
184
+ @db.expects(:command).with do |command, cmd_opts|
185
+ command[:createUser] == @test_user
186
+ cmd_opts[:roles] == ['dbOwner'] if cmd_opts
187
+ end
188
+
189
+ silently { @db.add_user(@test_user, @test_user_pwd) }
190
+ end
191
+
192
+ def test_default_roles_non_admin_read_only
193
+ init_auth_basic
194
+ @db.stubs(:command).returns({}, true)
195
+ @db.expects(:command).with do |command, cmd_opts|
196
+ command[:createUser] == @test_user
197
+ cmd_opts[:roles] == ['read'] if cmd_opts
198
+ end
199
+ silently { @db.add_user(@test_user, @test_user_pwd, true) }
200
+ end
201
+
202
+ def test_delegated_authentication
203
+ return unless @client.server_version >= '2.4' && @client.server_version < '2.5'
204
+ with_auth(@client) do
205
+ init_auth_basic
206
+ # create user in test databases
207
+ accounts = @client[TEST_DB + '_accounts']
208
+ silently do
209
+ accounts.add_user('emily', 'password')
210
+ @db.add_user('emily', nil, nil, :roles => ['read'], :userSource => accounts.name)
211
+ end
212
+ @admin.logout
213
+
214
+ # validate that direct authentication is not allowed
215
+ assert_raise Mongo::AuthenticationError do
216
+ @db.authenticate('emily', 'password')
217
+ end
218
+
219
+ # validate delegated authentication
220
+ assert accounts.authenticate('emily', 'password')
221
+ assert @db.collection_names
222
+ accounts.logout
223
+ assert_raise Mongo::OperationFailure do
224
+ @db.collection_names
225
+ end
226
+
227
+ # validate auth using source database
228
+ @db.authenticate('emily', 'password', nil, accounts.name)
229
+ assert @db.collection_names
230
+ accounts.logout
231
+ assert_raise Mongo::OperationFailure do
232
+ @db.collection_names
233
+ end
234
+
235
+ remove_user(accounts, 'emily', 'password')
236
+ end
237
+ end
238
+
239
+ def test_update_user_to_read_only
240
+ with_auth(@client) do
241
+ init_auth_basic
242
+ silently { @db.add_user(@test_user, @test_user_pwd) }
243
+ @admin.logout
244
+ @db.authenticate(@test_user, @test_user_pwd)
245
+ @db['test'].insert({})
246
+ @db.logout
247
+
248
+ @admin.authenticate(TEST_USER, TEST_USER_PWD)
249
+ silently { @db.add_user('emily', 'password', true) }
250
+ @admin.logout
251
+
252
+ silently { @db.authenticate('emily', 'password') }
253
+ assert_raise Mongo::OperationFailure do
254
+ @db['test'].insert({})
255
+ end
256
+ @db.logout
257
+ @admin.authenticate(TEST_USER, TEST_USER_PWD)
258
+ end
259
+ end
260
+ end
@@ -0,0 +1,249 @@
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License")
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0x
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module BulkAPIAuthTests
16
+
17
+ include Mongo
18
+
19
+ def init_auth_bulk
20
+ # Set up the test db
21
+ @collection = @db["bulk-api-auth-tests"]
22
+
23
+ # db user can insert but not remove
24
+ res = BSON::OrderedHash.new
25
+ res[:db] = @db.name
26
+ res[:collection] = ""
27
+
28
+ cmd = BSON::OrderedHash.new
29
+ cmd[:createRole] = "insertOnly"
30
+ cmd[:privileges] = [{:resource => res, :actions => [ "insert", "find" ]}]
31
+ cmd[:roles] = []
32
+ @db.command(cmd)
33
+ @db.add_user('insertOnly', 'password', nil, :roles => ['insertOnly'])
34
+
35
+ # db user can insert and remove
36
+ cmd = BSON::OrderedHash.new
37
+ cmd[:createRole] = "insertAndRemove"
38
+ cmd[:privileges] = [{:resource => res, :actions => [ "insert", "remove", "find" ]}]
39
+ cmd[:roles] = []
40
+ @db.command(cmd)
41
+ @db.add_user('insertAndRemove', 'password', nil, :roles => ['insertAndRemove'])
42
+
43
+ @admin.logout
44
+ end
45
+
46
+ def clear_collection(collection)
47
+ @admin.authenticate(TEST_USER, TEST_USER_PWD)
48
+ collection.remove
49
+ @admin.logout
50
+ end
51
+
52
+ def teardown_bulk
53
+ remove_all_users_and_roles(@db)
54
+ remove_all_users_and_roles(@admin)
55
+ end
56
+
57
+ def remove_all_users_and_roles(database)
58
+ @admin.authenticate(TEST_USER, TEST_USER_PWD)
59
+ if @version < '2.5.3'
60
+ database['system.users'].remove
61
+ else
62
+ database.command({:dropAllRolesFromDatabase => 1})
63
+ # Don't delete the TEST_USER from the TEST_DB, it is needed for future tests
64
+ database.command({:dropAllUsersFromDatabase => 1}) unless database.name == TEST_DB
65
+ end
66
+ @admin.logout
67
+ end
68
+
69
+ def test_auth_no_error
70
+ return unless @version >= '2.5.3'
71
+ init_auth_bulk
72
+ with_write_commands_and_operations(@db.connection) do |wire_version|
73
+ clear_collection(@collection)
74
+ @db.authenticate('insertAndRemove', 'password')
75
+ bulk = @collection.initialize_ordered_bulk_op
76
+ bulk.insert({:a => 1})
77
+ bulk.find({:a => 1}).remove_one
78
+
79
+ result = bulk.execute
80
+ assert_match_document(
81
+ {
82
+ "ok" => 1,
83
+ "nInserted" => 1,
84
+ "nRemoved" => 1
85
+ }, result, "wire_version:#{wire_version}")
86
+ assert_equal 0, @collection.count
87
+ @db.logout
88
+ end
89
+ teardown_bulk
90
+ end
91
+
92
+ def test_auth_error
93
+ return unless @version >= '2.5.3'
94
+ init_auth_bulk
95
+ with_write_commands_and_operations(@db.connection) do |wire_version|
96
+ clear_collection(@collection)
97
+ @db.authenticate('insertOnly', 'password')
98
+ bulk = @collection.initialize_ordered_bulk_op
99
+ bulk.insert({:a => 1})
100
+ bulk.find({:a => 1}).remove
101
+ bulk.insert({:a => 2})
102
+
103
+ ex = assert_raise Mongo::BulkWriteError do
104
+ bulk.execute
105
+ end
106
+ result = ex.result
107
+ assert_match_document(
108
+ {
109
+ "ok" => 1,
110
+ "n" => 1,
111
+ "writeErrors" =>
112
+ [{
113
+ "index" => 1,
114
+ "code" => 13,
115
+ "errmsg" => /not authorized/
116
+ }],
117
+ "code" => 65,
118
+ "errmsg" => "batch item errors occurred",
119
+ "nInserted" => 1
120
+ }, result, "wire_version:#{wire_version}")
121
+ assert_equal 1, @collection.count
122
+ @db.logout
123
+ end
124
+ teardown_bulk
125
+ end
126
+
127
+ def test_auth_error_unordered
128
+ return unless @version >= '2.5.3'
129
+ init_auth_bulk
130
+ with_write_commands_and_operations(@db.connection) do |wire_version|
131
+ clear_collection(@collection)
132
+ @db.authenticate('insertOnly', 'password')
133
+ bulk = @collection.initialize_unordered_bulk_op
134
+ bulk.insert({:a => 1})
135
+ bulk.find({:a => 1}).remove_one
136
+ bulk.insert({:a => 2})
137
+
138
+ ex = assert_raise Mongo::BulkWriteError do
139
+ bulk.execute
140
+ end
141
+ result = ex.result
142
+ assert_equal 1, result["writeErrors"].length
143
+ assert_equal 2, result["n"]
144
+ assert_equal 2, result["nInserted"]
145
+ assert_equal 2, @collection.count
146
+ @db.logout
147
+ end
148
+ teardown_bulk
149
+ end
150
+
151
+ def test_duplicate_key_with_auth_error
152
+ return unless @version >= '2.5.3'
153
+ init_auth_bulk
154
+ with_write_commands_and_operations(@db.connection) do |wire_version|
155
+ clear_collection(@collection)
156
+ @db.authenticate('insertOnly', 'password')
157
+ bulk = @collection.initialize_ordered_bulk_op
158
+ bulk.insert({:_id => 1, :a => 1})
159
+ bulk.insert({:_id => 1, :a => 2})
160
+ bulk.find({:a => 1}).remove_one
161
+
162
+ ex = assert_raise Mongo::BulkWriteError do
163
+ bulk.execute
164
+ end
165
+ result = ex.result
166
+ assert_match_document(
167
+ {
168
+ "ok" => 1,
169
+ "n" => 1,
170
+ "writeErrors" =>
171
+ [{
172
+ "index" => 1,
173
+ "code" => 11000,
174
+ "errmsg" => /duplicate key error/
175
+ }],
176
+ "code" => 65,
177
+ "errmsg" => "batch item errors occurred",
178
+ "nInserted" => 1
179
+ }, result, "wire_version:#{wire_version}")
180
+ assert_equal 1, @collection.count
181
+ @db.logout
182
+ end
183
+ teardown_bulk
184
+ end
185
+
186
+ def test_duplicate_key_with_auth_error_unordered
187
+ return unless @version >= '2.5.3'
188
+ init_auth_bulk
189
+ with_write_commands_and_operations(@db.connection) do |wire_version|
190
+ clear_collection(@collection)
191
+ @db.authenticate('insertOnly', 'password')
192
+ bulk = @collection.initialize_unordered_bulk_op
193
+ bulk.insert({:_id => 1, :a => 1})
194
+ bulk.insert({:_id => 1, :a => 1})
195
+ bulk.find({:a => 1}).remove_one
196
+
197
+ ex = assert_raise Mongo::BulkWriteError do
198
+ bulk.execute
199
+ end
200
+ result = ex.result
201
+ assert_equal 2, result["writeErrors"].length
202
+ assert_equal 1, result["n"]
203
+ assert_equal 1, result["nInserted"]
204
+ assert_equal 1, @collection.count
205
+ @db.logout
206
+ end
207
+ teardown_bulk
208
+ end
209
+
210
+ def test_write_concern_error_with_auth_error
211
+ with_no_replication(@db.connection) do
212
+ return unless @version >= '2.5.3'
213
+ init_auth_bulk
214
+ with_write_commands_and_operations(@db.connection) do |wire_version|
215
+ clear_collection(@collection)
216
+ @db.authenticate('insertOnly', 'password')
217
+ bulk = @collection.initialize_ordered_bulk_op
218
+ bulk.insert({:_id => 1, :a => 1})
219
+ bulk.insert({:_id => 2, :a => 1})
220
+ bulk.find({:a => 1}).remove_one
221
+
222
+ ex = assert_raise Mongo::BulkWriteError do
223
+ bulk.execute({:w => 2})
224
+ end
225
+ result = ex.result
226
+
227
+ assert_match_document(
228
+ {
229
+ "ok" => 0,
230
+ "n" => 0,
231
+ "nInserted" => 0,
232
+ "writeErrors" =>
233
+ [{
234
+ "index" => 0,
235
+ "code" => 2,
236
+ "errmsg" => /'w' > 1/
237
+ }],
238
+ "code" => 65,
239
+ "errmsg" => "batch item errors occurred"
240
+ }, result, "wire_version#{wire_version}")
241
+ # Re-visit this when RUBY-731 is resolved:
242
+ assert (@collection.count == batch_commands?(wire_version) ? 0 : 1)
243
+ @db.logout
244
+ end
245
+ teardown_bulk
246
+ end
247
+ end
248
+
249
+ end