mongo 1.9.2 → 1.10.0.rc0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/LICENSE +1 -1
  5. data/README.md +94 -334
  6. data/Rakefile +6 -4
  7. data/VERSION +1 -1
  8. data/bin/mongo_console +13 -6
  9. data/lib/mongo.rb +22 -27
  10. data/lib/mongo/bulk_write_collection_view.rb +352 -0
  11. data/lib/mongo/collection.rb +128 -188
  12. data/lib/mongo/collection_writer.rb +348 -0
  13. data/lib/mongo/connection.rb +19 -0
  14. data/lib/mongo/{util → connection}/node.rb +15 -1
  15. data/lib/mongo/{util → connection}/pool.rb +34 -19
  16. data/lib/mongo/{util → connection}/pool_manager.rb +8 -2
  17. data/lib/mongo/{util → connection}/sharding_pool_manager.rb +1 -1
  18. data/lib/mongo/connection/socket.rb +18 -0
  19. data/lib/mongo/{util → connection/socket}/socket_util.rb +5 -2
  20. data/lib/mongo/{util → connection/socket}/ssl_socket.rb +3 -4
  21. data/lib/mongo/{util → connection/socket}/tcp_socket.rb +25 -15
  22. data/lib/mongo/{util → connection/socket}/unix_socket.rb +6 -4
  23. data/lib/mongo/cursor.rb +113 -47
  24. data/lib/mongo/db.rb +203 -131
  25. data/lib/mongo/{exceptions.rb → exception.rb} +7 -1
  26. data/lib/mongo/functional.rb +19 -0
  27. data/lib/mongo/functional/authentication.rb +303 -0
  28. data/lib/mongo/{util → functional}/logging.rb +1 -1
  29. data/lib/mongo/{util → functional}/read_preference.rb +49 -1
  30. data/lib/mongo/{util → functional}/uri_parser.rb +81 -69
  31. data/lib/mongo/{util → functional}/write_concern.rb +2 -1
  32. data/{test/unit/pool_test.rb → lib/mongo/gridfs.rb} +5 -10
  33. data/lib/mongo/gridfs/grid.rb +1 -3
  34. data/lib/mongo/gridfs/grid_ext.rb +1 -1
  35. data/lib/mongo/gridfs/grid_file_system.rb +1 -1
  36. data/lib/mongo/gridfs/grid_io.rb +1 -1
  37. data/lib/mongo/legacy.rb +63 -8
  38. data/lib/mongo/mongo_client.rb +128 -154
  39. data/lib/mongo/mongo_replica_set_client.rb +17 -11
  40. data/lib/mongo/mongo_sharded_client.rb +2 -1
  41. data/lib/mongo/networking.rb +19 -10
  42. data/lib/mongo/utils.rb +19 -0
  43. data/lib/mongo/{util → utils}/conversions.rb +1 -1
  44. data/lib/mongo/{util → utils}/core_ext.rb +1 -1
  45. data/lib/mongo/{util → utils}/server_version.rb +1 -1
  46. data/lib/mongo/{util → utils}/support.rb +10 -57
  47. data/lib/mongo/{util → utils}/thread_local_variable_manager.rb +1 -1
  48. data/test/functional/authentication_test.rb +8 -21
  49. data/test/functional/bulk_write_collection_view_test.rb +782 -0
  50. data/test/functional/{connection_test.rb → client_test.rb} +153 -78
  51. data/test/functional/collection_test.rb +343 -97
  52. data/test/functional/collection_writer_test.rb +83 -0
  53. data/test/functional/conversions_test.rb +1 -3
  54. data/test/functional/cursor_fail_test.rb +3 -3
  55. data/test/functional/cursor_message_test.rb +3 -3
  56. data/test/functional/cursor_test.rb +38 -3
  57. data/test/functional/db_api_test.rb +5 -5
  58. data/test/functional/db_connection_test.rb +2 -2
  59. data/test/functional/db_test.rb +35 -11
  60. data/test/functional/grid_file_system_test.rb +2 -2
  61. data/test/functional/grid_io_test.rb +2 -2
  62. data/test/functional/grid_test.rb +2 -2
  63. data/test/functional/pool_test.rb +2 -3
  64. data/test/functional/safe_test.rb +5 -5
  65. data/test/functional/ssl_test.rb +22 -102
  66. data/test/functional/support_test.rb +1 -1
  67. data/test/functional/timeout_test.rb +6 -22
  68. data/test/functional/uri_test.rb +113 -12
  69. data/test/functional/write_concern_test.rb +6 -6
  70. data/test/helpers/general.rb +50 -0
  71. data/test/helpers/test_unit.rb +309 -0
  72. data/test/replica_set/authentication_test.rb +8 -23
  73. data/test/replica_set/basic_test.rb +41 -14
  74. data/test/replica_set/client_test.rb +179 -117
  75. data/test/replica_set/complex_connect_test.rb +6 -7
  76. data/test/replica_set/connection_test.rb +46 -38
  77. data/test/replica_set/count_test.rb +2 -2
  78. data/test/replica_set/cursor_test.rb +8 -8
  79. data/test/replica_set/insert_test.rb +64 -2
  80. data/test/replica_set/max_values_test.rb +59 -10
  81. data/test/replica_set/pinning_test.rb +2 -2
  82. data/test/replica_set/query_test.rb +2 -2
  83. data/test/replica_set/read_preference_test.rb +6 -6
  84. data/test/replica_set/refresh_test.rb +7 -7
  85. data/test/replica_set/replication_ack_test.rb +5 -5
  86. data/test/replica_set/ssl_test.rb +24 -106
  87. data/test/sharded_cluster/basic_test.rb +43 -15
  88. data/test/shared/authentication/basic_auth_shared.rb +215 -0
  89. data/test/shared/authentication/sasl_plain_shared.rb +96 -0
  90. data/test/shared/ssl_shared.rb +173 -0
  91. data/test/test_helper.rb +31 -199
  92. data/test/threading/basic_test.rb +29 -3
  93. data/test/tools/mongo_config.rb +45 -20
  94. data/test/tools/mongo_config_test.rb +1 -1
  95. data/test/unit/client_test.rb +136 -57
  96. data/test/unit/collection_test.rb +31 -55
  97. data/test/unit/connection_test.rb +135 -72
  98. data/test/unit/cursor_test.rb +2 -2
  99. data/test/unit/db_test.rb +19 -15
  100. data/test/unit/grid_test.rb +2 -2
  101. data/test/unit/mongo_sharded_client_test.rb +17 -15
  102. data/test/unit/node_test.rb +2 -2
  103. data/test/unit/pool_manager_test.rb +7 -5
  104. data/test/unit/read_pref_test.rb +82 -2
  105. data/test/unit/read_test.rb +14 -14
  106. data/test/unit/safe_test.rb +9 -9
  107. data/test/unit/sharding_pool_manager_test.rb +11 -5
  108. data/test/unit/write_concern_test.rb +9 -9
  109. metadata +71 -56
  110. metadata.gz.sig +0 -0
  111. data/test/functional/threading_test.rb +0 -109
  112. data/test/shared/authentication.rb +0 -121
  113. data/test/unit/util_test.rb +0 -69
@@ -1,109 +1,29 @@
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
+
1
15
  require 'test_helper'
16
+ require 'shared/ssl_shared'
2
17
 
3
- class SSLCertValidationTest < Test::Unit::TestCase
18
+ class SSLTest < Test::Unit::TestCase
4
19
  include Mongo
20
+ include SSLTests
5
21
 
6
- CERT_PATH = "#{Dir.pwd}/test/fixtures/certificates/"
7
- CLIENT_CERT = "#{CERT_PATH}client.pem"
8
- CA_CERT = "#{CERT_PATH}ca.pem"
9
-
10
- # This test doesn't connect, no server config required
11
- def test_ssl_configuration
12
- # raises when ssl=false and ssl opts specified
13
- assert_raise MongoArgumentError do
14
- MongoClient.new('server', 27017, :connect => false,
15
- :ssl => false,
16
- :ssl_cert => CLIENT_CERT)
17
- end
18
-
19
- # raises when ssl=nil and ssl opts specified
20
- assert_raise MongoArgumentError do
21
- MongoClient.new('server', 27017, :connect => false,
22
- :ssl_key => CLIENT_CERT)
23
- end
24
-
25
- # raises when verify=true and no ca_cert
26
- assert_raise MongoArgumentError do
27
- MongoClient.new('server', 27017, :connect => false,
28
- :ssl => true,
29
- :ssl_key => CLIENT_CERT,
30
- :ssl_cert => CLIENT_CERT,
31
- :ssl_verify => true)
32
- end
33
- end
34
-
35
- # Requires MongoDB built with SSL and the follow options:
36
- #
37
- # mongod --dbpath /path/to/data/directory --sslOnNormalPorts \
38
- # --sslPEMKeyFile /path/to/server.pem \
39
- # --sslCAFile /path/to/ca.pem \
40
- # --sslCRLFile /path/to/crl.pem \
41
- # --sslWeakCertificateValidation
42
- #
43
- # Make sure you have 'server' as an alias for localhost in /etc/hosts
44
- #
45
- def test_ssl_basic
46
- client = MongoClient.new('server', 27017, :connect => false,
47
- :ssl => true)
48
- assert client.connect
49
- end
50
-
51
- # Requires MongoDB built with SSL and the follow options:
52
- #
53
- # mongod --dbpath /path/to/data/directory --sslOnNormalPorts \
54
- # --sslPEMKeyFile /path/to/server.pem \
55
- # --sslCAFile /path/to/ca.pem \
56
- # --sslCRLFile /path/to/crl.pem
57
- #
58
- # Make sure you have 'server' as an alias for localhost in /etc/hosts
59
- #
60
- def test_ssl_with_cert
61
- client = MongoClient.new('server', 27017, :connect => false,
62
- :ssl => true,
63
- :ssl_cert => CLIENT_CERT,
64
- :ssl_key => CLIENT_CERT)
65
- assert client.connect
66
- end
67
-
68
- def test_ssl_with_peer_cert_validation
69
- client = MongoClient.new('server', 27017, :connect => false,
70
- :ssl => true,
71
- :ssl_key => CLIENT_CERT,
72
- :ssl_cert => CLIENT_CERT,
73
- :ssl_verify => true,
74
- :ssl_ca_cert => CA_CERT)
75
- assert client.connect
76
- end
77
-
78
- def test_ssl_peer_cert_validation_hostname_fail
79
- client = MongoClient.new('localhost', 27017, :connect => false,
80
- :ssl => true,
81
- :ssl_key => CLIENT_CERT,
82
- :ssl_cert => CLIENT_CERT,
83
- :ssl_verify => true,
84
- :ssl_ca_cert => CA_CERT)
85
- assert_raise ConnectionFailure do
86
- client.connect
87
- end
88
- end
89
-
90
- # Requires mongod built with SSL and the follow options:
91
- #
92
- # mongod --dbpath /path/to/data/directory --sslOnNormalPorts \
93
- # --sslPEMKeyFile /path/to/server.pem \
94
- # --sslCAFile /path/to/ca.pem \
95
- # --sslCRLFile /path/to/crl_client_revoked.pem
96
- #
97
- # Make sure you have 'server' as an alias for localhost in /etc/hosts
98
- #
99
- def test_ssl_with_invalid_cert
100
- assert_raise ConnectionFailure do
101
- MongoClient.new('server', 27017, :ssl => true,
102
- :ssl_key => CLIENT_CERT,
103
- :ssl_cert => CLIENT_CERT,
104
- :ssl_verify => true,
105
- :ssl_ca_cert => CA_CERT)
106
- end
22
+ def setup
23
+ @client_class = MongoClient
24
+ @uri_info = 'server'
25
+ @connect_info = ['server', 27017]
26
+ @bad_connect_info = ['localhost', 27017]
107
27
  end
108
28
 
109
29
  end
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2013 10gen Inc.
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2013 10gen Inc.
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -14,7 +14,8 @@
14
14
 
15
15
  require 'test_helper'
16
16
 
17
- class TestTimeout < Test::Unit::TestCase
17
+ class TimeoutTest < Test::Unit::TestCase
18
+
18
19
  def test_op_timeout
19
20
  connection = standard_connection(:op_timeout => 0.5)
20
21
 
@@ -32,9 +33,9 @@ class TestTimeout < Test::Unit::TestCase
32
33
  end
33
34
 
34
35
  def test_external_timeout_does_not_leave_socket_in_bad_state
35
- client = Mongo::MongoClient.new
36
- db = client[MONGO_TEST_DB]
37
- coll = db['timeout-tests']
36
+ client = standard_connection
37
+ db = client[TEST_DB]
38
+ coll = db['timeout-tests']
38
39
 
39
40
  # prepare the database
40
41
  coll.drop
@@ -54,21 +55,4 @@ class TestTimeout < Test::Unit::TestCase
54
55
  end
55
56
  end
56
57
 
57
- =begin
58
- def test_ssl_op_timeout
59
- connection = standard_connection(:op_timeout => 1, :ssl => true)
60
-
61
- coll = connection.db(MONGO_TEST_DB).collection("test")
62
- coll.insert({:a => 1})
63
- # Should not timeout
64
- assert coll.find_one({"$where" => "sleep(100); return true;"})
65
-
66
- # Should timeout
67
- assert_raise Mongo::OperationTimeout do
68
- coll.find_one({"$where" => "sleep(5 * 1000); return true;"})
69
- end
70
-
71
- coll.remove
72
- end
73
- =end
74
58
  end
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2013 10gen Inc.
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -31,6 +31,40 @@ class URITest < Test::Unit::TestCase
31
31
  assert_equal 27018, parser.nodes[0][1]
32
32
  end
33
33
 
34
+ def test_ipv6_format
35
+ parser = Mongo::URIParser.new('mongodb://[::1]:27018')
36
+ assert_equal 1, parser.nodes.length
37
+ assert_equal '::1', parser.nodes[0][0]
38
+ assert_equal 27018, parser.nodes[0][1]
39
+
40
+ parser = Mongo::URIParser.new('mongodb://[::1]')
41
+ assert_equal 1, parser.nodes.length
42
+ assert_equal '::1', parser.nodes[0][0]
43
+ end
44
+
45
+ def test_ipv6_format_multi
46
+ parser = Mongo::URIParser.new('mongodb://[::1]:27017,[::1]:27018')
47
+ assert_equal 2, parser.nodes.length
48
+ assert_equal '::1', parser.nodes[0][0]
49
+ assert_equal 27017, parser.nodes[0][1]
50
+ assert_equal '::1', parser.nodes[1][0]
51
+ assert_equal 27018, parser.nodes[1][1]
52
+
53
+ parser = Mongo::URIParser.new('mongodb://[::1]:27017,localhost:27018')
54
+ assert_equal 2, parser.nodes.length
55
+ assert_equal '::1', parser.nodes[0][0]
56
+ assert_equal 27017, parser.nodes[0][1]
57
+ assert_equal 'localhost', parser.nodes[1][0]
58
+ assert_equal 27018, parser.nodes[1][1]
59
+
60
+ parser = Mongo::URIParser.new('mongodb://localhost:27017,[::1]:27018')
61
+ assert_equal 2, parser.nodes.length
62
+ assert_equal 'localhost', parser.nodes[0][0]
63
+ assert_equal 27017, parser.nodes[0][1]
64
+ assert_equal '::1', parser.nodes[1][0]
65
+ assert_equal 27018, parser.nodes[1][1]
66
+ end
67
+
34
68
  def test_multiple_uris
35
69
  parser = Mongo::URIParser.new('mongodb://a.example.com:27018,b.example.com')
36
70
  assert_equal 2, parser.nodes.length
@@ -38,37 +72,72 @@ class URITest < Test::Unit::TestCase
38
72
  assert_equal ['b.example.com', 27017], parser.nodes[1]
39
73
  end
40
74
 
75
+ def test_username_without_password
76
+ parser = Mongo::URIParser.new('mongodb://bob:@localhost?authMechanism=GSSAPI')
77
+ assert_equal "bob", parser.auths.first[:username]
78
+ assert_equal nil, parser.auths.first[:password]
79
+
80
+ parser = Mongo::URIParser.new('mongodb://bob@localhost?authMechanism=GSSAPI')
81
+ assert_equal nil, parser.auths.first[:password]
82
+
83
+ assert_raise_error MongoArgumentError do
84
+ Mongo::URIParser.new('mongodb://bob:@localhost')
85
+ end
86
+
87
+ assert_raise_error MongoArgumentError do
88
+ Mongo::URIParser.new('mongodb://bob@localhost')
89
+ end
90
+ end
91
+
41
92
  def test_complex_passwords
42
93
  parser = Mongo::URIParser.new('mongodb://bob:secret.word@a.example.com:27018/test')
43
- assert_equal "bob", parser.auths[0][:username]
44
- assert_equal "secret.word", parser.auths[0][:password]
94
+ assert_equal "bob", parser.auths.first[:username]
95
+ assert_equal "secret.word", parser.auths.first[:password]
45
96
 
46
97
  parser = Mongo::URIParser.new('mongodb://bob:s-_3#%R.t@a.example.com:27018/test')
47
- assert_equal "bob", parser.auths[0][:username]
48
- assert_equal "s-_3#%R.t", parser.auths[0][:password]
98
+ assert_equal "bob", parser.auths.first[:username]
99
+ assert_equal "s-_3#%R.t", parser.auths.first[:password]
100
+
101
+ assert_raise_error MongoArgumentError do
102
+ Mongo::URIParser.new('mongodb://doctor:bad:wolf@gallifrey.com:27018/test')
103
+ end
104
+
105
+ assert_raise_error MongoArgumentError do
106
+ Mongo::URIParser.new('mongodb://doctor:bow@tie@gallifrey.com:27018/test')
107
+ end
49
108
  end
50
109
 
51
110
  def test_complex_usernames
52
- parser = Mongo::URIParser.new('mongodb://b:ob:secret.word@a.example.com:27018/test')
53
- assert_equal "b:ob", parser.auths[0][:username]
111
+ parser = Mongo::URIParser.new('mongodb://s-_3#%R.t:secret.word@a.example.com:27018/test')
112
+ assert_equal "s-_3#%R.t", parser.auths.first[:username]
113
+
114
+ assert_raise_error MongoArgumentError do
115
+ Mongo::URIParser.new('mongodb://doc:tor:badwolf@gallifrey.com:27018/test')
116
+ end
117
+
118
+ assert_raise_error MongoArgumentError do
119
+ Mongo::URIParser.new('mongodb://d@ctor:bowtie@gallifrey.com:27018/test')
120
+ end
54
121
  end
55
122
 
56
123
  def test_username_with_encoded_symbol
57
124
  parser = Mongo::URIParser.new('mongodb://f%40o:bar@localhost/admin')
58
125
  username = parser.auths.first[:username]
59
126
  assert_equal 'f@o', username
127
+
128
+ parser = Mongo::URIParser.new('mongodb://f%3Ao:bar@localhost/admin')
129
+ username = parser.auths.first[:username]
130
+ assert_equal 'f:o', username
60
131
  end
61
132
 
62
133
  def test_password_with_encoded_symbol
63
134
  parser = Mongo::URIParser.new('mongodb://foo:b%40r@localhost/admin')
64
135
  password = parser.auths.first[:password]
65
136
  assert_equal 'b@r', password
66
- end
67
137
 
68
- def test_passwords_contain_no_commas
69
- assert_raise MongoArgumentError do
70
- Mongo::URIParser.new('mongodb://bob:a,b@a.example.com:27018/test')
71
- end
138
+ parser = Mongo::URIParser.new('mongodb://foo:b%3Ar@localhost/admin')
139
+ password = parser.auths.first[:password]
140
+ assert_equal 'b:r', password
72
141
  end
73
142
 
74
143
  def test_opts_with_semincolon_separator
@@ -209,4 +278,36 @@ class URITest < Test::Unit::TestCase
209
278
  assert_equal :nearest, client.read
210
279
  assert_true client.mongos?
211
280
  end
281
+
282
+ def test_auth_source
283
+ parser = Mongo::URIParser.new("mongodb://user:pass@localhost?authSource=foobar")
284
+ assert_equal 'foobar', parser.authsource
285
+ end
286
+
287
+ def test_auth_mechanism
288
+ parser = Mongo::URIParser.new("mongodb://user@localhost?authMechanism=MONGODB-X509")
289
+ assert_equal 'MONGODB-X509', parser.authmechanism
290
+
291
+ assert_raise_error MongoArgumentError do
292
+ Mongo::URIParser.new("mongodb://user@localhost?authMechanism=INVALID")
293
+ end
294
+ end
295
+
296
+ def test_sasl_plain
297
+ parser = Mongo::URIParser.new("mongodb://user:pass@localhost?authMechanism=PLAIN")
298
+ assert_equal 'PLAIN', parser.auths.first[:mechanism]
299
+ assert_equal 'user', parser.auths.first[:username]
300
+ assert_equal 'pass', parser.auths.first[:password]
301
+ assert_equal 'admin', parser.auths.first[:source]
302
+
303
+ parser = Mongo::URIParser.new("mongodb://foo%2Fbar%40example.net:pass@localhost/some_db?authMechanism=PLAIN")
304
+ assert_equal 'PLAIN', parser.auths.first[:mechanism]
305
+ assert_equal 'foo/bar@example.net', parser.auths.first[:username]
306
+ assert_equal 'pass', parser.auths.first[:password]
307
+ assert_equal 'some_db', parser.auths.first[:source]
308
+
309
+ assert_raise_error MongoArgumentError do
310
+ Mongo::URIParser.new("mongodb://user@localhost/some_db?authMechanism=PLAIN")
311
+ end
312
+ end
212
313
  end
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2013 10gen Inc.
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@ class WriteConcernTest < Test::Unit::TestCase
19
19
  context "Write concern propogation: " do
20
20
  setup do
21
21
  @con = standard_connection
22
- @db = @con[MONGO_TEST_DB]
22
+ @db = @con[TEST_DB]
23
23
  @col = @db['test-safe']
24
24
  @col.create_index([[:a, 1]], :unique => true)
25
25
  @col.remove
@@ -59,7 +59,7 @@ class WriteConcernTest < Test::Unit::TestCase
59
59
  context "Write concern error objects" do
60
60
  setup do
61
61
  @con = standard_connection
62
- @db = @con[MONGO_TEST_DB]
62
+ @db = @con[TEST_DB]
63
63
  @col = @db['test']
64
64
  @col.remove
65
65
  @col.insert({:a => 1})
@@ -71,8 +71,8 @@ class WriteConcernTest < Test::Unit::TestCase
71
71
  response = @col.update({:a => 1}, {"$set" => {:a => 2}},
72
72
  :multi => true)
73
73
 
74
- assert response['updatedExisting']
75
- assert_equal 3, response['n']
74
+ assert(response['updatedExisting'] || @db.connection.wire_version_feature?(Mongo::MongoClient::BATCH_COMMANDS)) # TODO - review new write command return values
75
+ assert(response['n'] == 3 || @db.connection.wire_version_feature?(Mongo::MongoClient::BATCH_COMMANDS)) # TODO - update command top pending
76
76
  end
77
77
 
78
78
  should "return object on remove" do
@@ -83,7 +83,7 @@ class WriteConcernTest < Test::Unit::TestCase
83
83
 
84
84
  context "Write concern in gridfs" do
85
85
  setup do
86
- @db = standard_connection.db(MONGO_TEST_DB)
86
+ @db = standard_connection.db(TEST_DB)
87
87
  @grid = Mongo::GridFileSystem.new(@db)
88
88
  @filename = 'sample'
89
89
  end
@@ -0,0 +1,50 @@
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
+ # Redirects output while yielding a given block of code.
16
+ #
17
+ # @return [Object] The result of the block.
18
+ def silently
19
+ warn_level = $VERBOSE
20
+ $VERBOSE = nil
21
+ begin
22
+ result = yield
23
+ ensure
24
+ $VERBOSE = warn_level
25
+ end
26
+ result
27
+ end
28
+
29
+ class Hash
30
+ def stringify_keys
31
+ dup.stringify_keys!
32
+ end
33
+
34
+ def stringify_keys!
35
+ keys.each do |key|
36
+ self[key.to_s] = delete(key)
37
+ end
38
+ self
39
+ end
40
+
41
+ def except(*keys)
42
+ dup.except!(*keys)
43
+ end
44
+
45
+ # Replaces the hash without the given keys.
46
+ def except!(*keys)
47
+ keys.each { |key| delete(key) }
48
+ self
49
+ end
50
+ end
@@ -0,0 +1,309 @@
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
+ TEST_DB = 'ruby_test' unless defined? TEST_DB
16
+ TEST_HOST = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost' unless defined? TEST_HOST
17
+ TEST_DATA = File.join(File.dirname(__FILE__), 'fixtures/data')
18
+ TEST_BASE = Test::Unit::TestCase
19
+
20
+ unless defined? TEST_PORT
21
+ TEST_PORT = if ENV['MONGO_RUBY_DRIVER_PORT']
22
+ ENV['MONGO_RUBY_DRIVER_PORT'].to_i
23
+ else
24
+ Mongo::MongoClient::DEFAULT_PORT
25
+ end
26
+ end
27
+
28
+ class Test::Unit::TestCase
29
+ include Mongo
30
+ include BSON
31
+
32
+ # Handles creating a pre-defined MongoDB cluster for integration testing.
33
+ #
34
+ # @param kind=nil [Symbol] Type of cluster (:rs or :sc).
35
+ # @param opts={} [Hash] Options to be passed through to the cluster manager.
36
+ #
37
+ # @return [ClusterManager] The cluster manager instance being used.
38
+ def ensure_cluster(kind=nil, opts={})
39
+ cluster_instance = nil
40
+ class_vars = TEST_BASE.class_eval { class_variables }
41
+ if class_vars.include?("@@cluster_#{kind}") || class_vars.include?("@@cluster_#{kind}".to_sym)
42
+ cluster_instance = TEST_BASE.class_eval { class_variable_get("@@cluster_#{kind}") }
43
+ end
44
+
45
+ unless cluster_instance
46
+ if kind == :rs
47
+ cluster_opts = Config::DEFAULT_REPLICA_SET.dup
48
+ else
49
+ cluster_opts = Config::DEFAULT_SHARDED_SIMPLE.dup
50
+ end
51
+
52
+ cluster_opts.merge!(opts)
53
+ cluster_opts.merge!(:dbpath => ENV['MONGO_DBPATH'] || 'data')
54
+ config = Config.cluster(cluster_opts)
55
+
56
+ cluster_instance = Config::ClusterManager.new(config)
57
+ TEST_BASE.class_eval { class_variable_set("@@cluster_#{kind}", cluster_instance) }
58
+ end
59
+
60
+ cluster_instance.start
61
+ instance_variable_set("@#{kind}", cluster_instance)
62
+ end
63
+
64
+ # Generic helper to rescue and retry from a connection failure.
65
+ #
66
+ # @param max_retries=30 [Integer] The number of times to attempt a retry.
67
+ #
68
+ # @return [Object] The block result.
69
+ def rescue_connection_failure(max_retries=30)
70
+ retries = 0
71
+ begin
72
+ yield
73
+ rescue Mongo::ConnectionFailure => ex
74
+ retries += 1
75
+ raise ex if retries > max_retries
76
+ sleep(2)
77
+ retry
78
+ end
79
+ end
80
+
81
+ # Creates and connects a standard, pre-defined MongoClient instance.
82
+ #
83
+ # @param options={} [Hash] Options to be passed to the client instance.
84
+ # @param legacy=false [Boolean] When true, uses deprecated Mongo::Connection.
85
+ #
86
+ # @return [MongoClient] The client instance.
87
+ def self.standard_connection(options={}, legacy=false)
88
+ if legacy
89
+ Connection.new(TEST_HOST, TEST_PORT, options)
90
+ else
91
+ MongoClient.new(TEST_HOST, TEST_PORT, options)
92
+ end
93
+ end
94
+
95
+ # Creates and connects a standard, pre-defined MongoClient instance.
96
+ #
97
+ # @param options={} [Hash] Options to be passed to the client instance.
98
+ # @param legacy=false [Boolean] When true, uses deprecated Mongo::Connection.
99
+ #
100
+ # @return [MongoClient] The client instance.
101
+ def standard_connection(options={}, legacy=false)
102
+ self.class.standard_connection(options, legacy)
103
+ end
104
+
105
+ def self.host_port
106
+ "#{mongo_host}:#{mongo_port}"
107
+ end
108
+
109
+ def self.mongo_host
110
+ TEST_HOST
111
+ end
112
+
113
+ def self.mongo_port
114
+ TEST_PORT
115
+ end
116
+
117
+ def host_port
118
+ self.class.host_port
119
+ end
120
+
121
+ def mongo_host
122
+ self.class.mongo_host
123
+ end
124
+
125
+ def mongo_port
126
+ self.class.mongo_port
127
+ end
128
+
129
+ def method_name
130
+ caller[0]=~/`(.*?)'/
131
+ $1
132
+ end
133
+
134
+ def perform_step_down(member)
135
+ start = Time.now
136
+ timeout = 20 # seconds
137
+ begin
138
+ step_down_command = BSON::OrderedHash.new
139
+ step_down_command[:replSetStepDown] = 30
140
+ member['admin'].command(step_down_command)
141
+ rescue Mongo::OperationFailure => e
142
+ retry unless (Time.now - start) > timeout
143
+ raise e
144
+ end
145
+ end
146
+
147
+ def new_mock_socket(host='localhost', port=27017)
148
+ socket = Object.new
149
+ socket.stubs(:setsockopt).with(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
150
+ socket.stubs(:close)
151
+ socket.stubs(:closed?)
152
+ socket.stubs(:checkin)
153
+ socket.stubs(:pool)
154
+ socket
155
+ end
156
+
157
+ def new_mock_unix_socket(sockfile='/tmp/mongod.sock')
158
+ socket = Object.new
159
+ socket.stubs(:setsockopt).with(Socket::IPPROTO_TCP)
160
+ socket.stubs(:close)
161
+ socket.stubs(:closed?)
162
+ socket
163
+ end
164
+
165
+ def new_mock_db
166
+ Object.new
167
+ end
168
+
169
+ def assert_raise_error(klass, message=nil)
170
+ begin
171
+ yield
172
+ rescue => e
173
+ if klass.to_s != e.class.to_s
174
+ flunk "Expected exception class #{klass} but got #{e.class}.\n #{e.backtrace}"
175
+ end
176
+
177
+ if message && !e.message.include?(message)
178
+ p e.backtrace
179
+ flunk "#{e.message} does not include #{message}.\n#{e.backtrace}"
180
+ end
181
+ else
182
+ flunk "Expected assertion #{klass} but none was raised."
183
+ end
184
+ end
185
+
186
+ def match_document(key, expected, actual) # special cases for Regexp match, BSON::ObjectId, Range
187
+ if expected.is_a?(Hash) && actual.is_a?(Hash)
188
+ expected_keys = expected.keys.sort
189
+ actual_keys = actual.keys.sort
190
+ #currently allow extra fields in actual as the following check for equality of keys is commented out
191
+ #raise "field:#{key.inspect} - Hash keys expected:#{expected_keys.inspect} actual:#{actual_keys.inspect}" if expected_keys != actual_keys
192
+ expected_keys.each{|k| match_document(k, expected[k], actual[k])}
193
+ elsif expected.is_a?(Array) && actual.is_a?(Array)
194
+ raise "field:#{key.inspect} - Array size expected:#{expected.size} actual:#{actual.size}" if expected.size != actual.size
195
+ (0...expected.size).each{|i| match_document(i, expected[i], actual[i])}
196
+ elsif expected.is_a?(Regexp) && actual.is_a?(String)
197
+ raise "field:#{key.inspect} - Regexp expected:#{expected.inspect} actual:#{actual.inspect}" if expected !~ actual
198
+ elsif expected.is_a?(BSON::ObjectId) && actual.is_a?(BSON::ObjectId)
199
+ # match type but not value
200
+ elsif expected.is_a?(Range)
201
+ raise "field:#{key.inspect} - Range expected:#{expected.inspect} actual:#{actual.inspect}" if !expected.include?(actual)
202
+ elsif expected.is_a?(Set)
203
+ raise "field:#{key.inspect} - Set expected:#{expected.inspect} actual:#{actual.inspect}" if !expected.include?(actual)
204
+ else
205
+ raise "field:#{key.inspect} - expected:#{expected.inspect} actual:#{actual.inspect}" if expected != actual
206
+ end
207
+ true
208
+ end
209
+
210
+ def assert_match_document(expected, actual, message = '')
211
+ match = begin
212
+ match_document('', expected, actual)
213
+ rescue => ex
214
+ message = ex.message + ' - ' + message
215
+ false
216
+ end
217
+ assert(match, message)
218
+ end
219
+
220
+ def with_forced_timeout(client, &block)
221
+ cmd_line_args = client['admin'].command({ :getCmdLineOpts => 1 })['argv']
222
+ if cmd_line_args.include?('enableTestCommands=1') && client.server_version >= "2.5.3"
223
+ begin
224
+ #Force any query or command with valid non-zero max time to fail (SERVER-10650)
225
+ fail_point_cmd = OrderedHash.new
226
+ fail_point_cmd[:configureFailPoint] = 'maxTimeAlwaysTimeOut'
227
+ fail_point_cmd[:mode] = 'alwaysOn'
228
+ client['admin'].command(fail_point_cmd)
229
+ yield
230
+ fail_point_cmd[:mode] = 'off'
231
+ client['admin'].command(fail_point_cmd)
232
+ end
233
+ end
234
+ end
235
+
236
+ def with_default_journaling(client, &block)
237
+ cmd_line_args = client['admin'].command({ :getCmdLineOpts => 1 })['parsed']
238
+ unless client.server_version < "2.0" || cmd_line_args.include?('nojournal')
239
+ yield
240
+ end
241
+ end
242
+
243
+ def with_no_replication(client, &block)
244
+ if client.class == MongoClient
245
+ yield
246
+ end
247
+ end
248
+
249
+ def with_no_journaling(client, &block)
250
+ cmd_line_args = client['admin'].command({ :getCmdLineOpts => 1 })['parsed']
251
+ unless client.server_version < "2.0" || !cmd_line_args.include?('nojournal')
252
+ yield
253
+ end
254
+ end
255
+
256
+ def with_ipv6_enabled(client, &block)
257
+ cmd_line_args = client['admin'].command({ :getCmdLineOpts => 1 })['parsed']
258
+ if cmd_line_args.include?('ipv6')
259
+ yield
260
+ end
261
+ end
262
+
263
+ def with_write_commands(client, &block)
264
+ wire_version = Mongo::MongoClient::BATCH_COMMANDS
265
+ if client.primary_wire_version_feature?(wire_version)
266
+ yield wire_version
267
+ end
268
+ end
269
+
270
+ def with_preserved_env_uri(new_uri=nil, &block)
271
+ old_mongodb_uri = ENV['MONGODB_URI']
272
+ begin
273
+ ENV['MONGODB_URI'] = new_uri
274
+ yield
275
+ ensure
276
+ ENV['MONGODB_URI'] = old_mongodb_uri
277
+ end
278
+ end
279
+
280
+ def with_write_operations(client, &block)
281
+ wire_version = Mongo::MongoClient::RELEASE_2_4_AND_BEFORE
282
+ if client.primary_wire_version_feature?(wire_version)
283
+ client.class.class_eval(%Q{
284
+ alias :old_use_write_command? :use_write_command?
285
+ def use_write_command?(write_concern)
286
+ false
287
+ end
288
+ })
289
+ yield wire_version
290
+ client.class.class_eval(%Q{
291
+ alias :use_write_command? :old_use_write_command?
292
+ })
293
+ end
294
+ end
295
+
296
+ def with_write_commands_and_operations(client, &block)
297
+ with_write_commands(client, &block)
298
+ with_write_operations(client, &block)
299
+ end
300
+
301
+ end
302
+
303
+ # Before and after hooks for the entire test run
304
+ # handles mop up after the cluster manager is done.
305
+ Test::Unit.at_exit do
306
+ TEST_BASE.class_eval { class_variables }.select { |v| v =~ /@@cluster_/ }.each do |cluster|
307
+ TEST_BASE.class_eval { class_variable_get(cluster) }.stop
308
+ end
309
+ end