mongo 1.10.0-java

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 (116) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/LICENSE +190 -0
  5. data/README.md +149 -0
  6. data/Rakefile +31 -0
  7. data/VERSION +1 -0
  8. data/bin/mongo_console +43 -0
  9. data/ext/jsasl/target/jsasl.jar +0 -0
  10. data/lib/mongo.rb +90 -0
  11. data/lib/mongo/bulk_write_collection_view.rb +380 -0
  12. data/lib/mongo/collection.rb +1164 -0
  13. data/lib/mongo/collection_writer.rb +364 -0
  14. data/lib/mongo/connection.rb +19 -0
  15. data/lib/mongo/connection/node.rb +239 -0
  16. data/lib/mongo/connection/pool.rb +347 -0
  17. data/lib/mongo/connection/pool_manager.rb +325 -0
  18. data/lib/mongo/connection/sharding_pool_manager.rb +67 -0
  19. data/lib/mongo/connection/socket.rb +18 -0
  20. data/lib/mongo/connection/socket/socket_util.rb +37 -0
  21. data/lib/mongo/connection/socket/ssl_socket.rb +95 -0
  22. data/lib/mongo/connection/socket/tcp_socket.rb +86 -0
  23. data/lib/mongo/connection/socket/unix_socket.rb +39 -0
  24. data/lib/mongo/cursor.rb +719 -0
  25. data/lib/mongo/db.rb +735 -0
  26. data/lib/mongo/exception.rb +88 -0
  27. data/lib/mongo/functional.rb +21 -0
  28. data/lib/mongo/functional/authentication.rb +318 -0
  29. data/lib/mongo/functional/logging.rb +85 -0
  30. data/lib/mongo/functional/read_preference.rb +174 -0
  31. data/lib/mongo/functional/sasl_java.rb +48 -0
  32. data/lib/mongo/functional/uri_parser.rb +374 -0
  33. data/lib/mongo/functional/write_concern.rb +66 -0
  34. data/lib/mongo/gridfs.rb +18 -0
  35. data/lib/mongo/gridfs/grid.rb +112 -0
  36. data/lib/mongo/gridfs/grid_ext.rb +53 -0
  37. data/lib/mongo/gridfs/grid_file_system.rb +163 -0
  38. data/lib/mongo/gridfs/grid_io.rb +484 -0
  39. data/lib/mongo/legacy.rb +140 -0
  40. data/lib/mongo/mongo_client.rb +702 -0
  41. data/lib/mongo/mongo_replica_set_client.rb +523 -0
  42. data/lib/mongo/mongo_sharded_client.rb +159 -0
  43. data/lib/mongo/networking.rb +370 -0
  44. data/lib/mongo/utils.rb +19 -0
  45. data/lib/mongo/utils/conversions.rb +110 -0
  46. data/lib/mongo/utils/core_ext.rb +70 -0
  47. data/lib/mongo/utils/server_version.rb +69 -0
  48. data/lib/mongo/utils/support.rb +80 -0
  49. data/lib/mongo/utils/thread_local_variable_manager.rb +25 -0
  50. data/mongo.gemspec +36 -0
  51. data/test/functional/authentication_test.rb +35 -0
  52. data/test/functional/bulk_api_stress_test.rb +133 -0
  53. data/test/functional/bulk_write_collection_view_test.rb +1129 -0
  54. data/test/functional/client_test.rb +565 -0
  55. data/test/functional/collection_test.rb +2073 -0
  56. data/test/functional/collection_writer_test.rb +83 -0
  57. data/test/functional/conversions_test.rb +163 -0
  58. data/test/functional/cursor_fail_test.rb +63 -0
  59. data/test/functional/cursor_message_test.rb +57 -0
  60. data/test/functional/cursor_test.rb +625 -0
  61. data/test/functional/db_api_test.rb +819 -0
  62. data/test/functional/db_connection_test.rb +27 -0
  63. data/test/functional/db_test.rb +344 -0
  64. data/test/functional/grid_file_system_test.rb +285 -0
  65. data/test/functional/grid_io_test.rb +252 -0
  66. data/test/functional/grid_test.rb +273 -0
  67. data/test/functional/pool_test.rb +62 -0
  68. data/test/functional/safe_test.rb +98 -0
  69. data/test/functional/ssl_test.rb +29 -0
  70. data/test/functional/support_test.rb +62 -0
  71. data/test/functional/timeout_test.rb +58 -0
  72. data/test/functional/uri_test.rb +330 -0
  73. data/test/functional/write_concern_test.rb +118 -0
  74. data/test/helpers/general.rb +50 -0
  75. data/test/helpers/test_unit.rb +317 -0
  76. data/test/replica_set/authentication_test.rb +35 -0
  77. data/test/replica_set/basic_test.rb +174 -0
  78. data/test/replica_set/client_test.rb +341 -0
  79. data/test/replica_set/complex_connect_test.rb +77 -0
  80. data/test/replica_set/connection_test.rb +138 -0
  81. data/test/replica_set/count_test.rb +64 -0
  82. data/test/replica_set/cursor_test.rb +212 -0
  83. data/test/replica_set/insert_test.rb +140 -0
  84. data/test/replica_set/max_values_test.rb +145 -0
  85. data/test/replica_set/pinning_test.rb +55 -0
  86. data/test/replica_set/query_test.rb +73 -0
  87. data/test/replica_set/read_preference_test.rb +214 -0
  88. data/test/replica_set/refresh_test.rb +175 -0
  89. data/test/replica_set/replication_ack_test.rb +94 -0
  90. data/test/replica_set/ssl_test.rb +32 -0
  91. data/test/sharded_cluster/basic_test.rb +197 -0
  92. data/test/shared/authentication/basic_auth_shared.rb +286 -0
  93. data/test/shared/authentication/bulk_api_auth_shared.rb +259 -0
  94. data/test/shared/authentication/gssapi_shared.rb +164 -0
  95. data/test/shared/authentication/sasl_plain_shared.rb +96 -0
  96. data/test/shared/ssl_shared.rb +235 -0
  97. data/test/test_helper.rb +56 -0
  98. data/test/threading/basic_test.rb +120 -0
  99. data/test/tools/mongo_config.rb +608 -0
  100. data/test/tools/mongo_config_test.rb +160 -0
  101. data/test/unit/client_test.rb +347 -0
  102. data/test/unit/collection_test.rb +166 -0
  103. data/test/unit/connection_test.rb +325 -0
  104. data/test/unit/cursor_test.rb +299 -0
  105. data/test/unit/db_test.rb +136 -0
  106. data/test/unit/grid_test.rb +76 -0
  107. data/test/unit/mongo_sharded_client_test.rb +48 -0
  108. data/test/unit/node_test.rb +93 -0
  109. data/test/unit/pool_manager_test.rb +142 -0
  110. data/test/unit/read_pref_test.rb +115 -0
  111. data/test/unit/read_test.rb +159 -0
  112. data/test/unit/safe_test.rb +158 -0
  113. data/test/unit/sharding_pool_manager_test.rb +84 -0
  114. data/test/unit/write_concern_test.rb +175 -0
  115. metadata +260 -0
  116. metadata.gz.sig +0 -0
@@ -0,0 +1,140 @@
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
+
17
+ class ReplicaSetInsertTest < Test::Unit::TestCase
18
+
19
+ def setup
20
+ ensure_cluster(:rs)
21
+ @client = MongoReplicaSetClient.new @rs.repl_set_seeds
22
+ @version = @client.server_version
23
+ @db = @client.db(TEST_DB)
24
+ @db.drop_collection("test-sets")
25
+ @coll = @db.collection("test-sets")
26
+ end
27
+
28
+ def teardown
29
+ @client.close if @conn
30
+ end
31
+
32
+ def test_insert
33
+ @coll.save({:a => 20}, :w => 3)
34
+
35
+ @rs.primary.stop
36
+
37
+ rescue_connection_failure do
38
+ @coll.save({:a => 30}, :w => 1)
39
+ end
40
+
41
+ @coll.save({:a => 40}, :w => 1)
42
+ @coll.save({:a => 50}, :w => 1)
43
+ @coll.save({:a => 60}, :w => 1)
44
+ @coll.save({:a => 70}, :w => 1)
45
+
46
+ # Restart the old master and wait for sync
47
+ @rs.start
48
+ sleep(5)
49
+ results = []
50
+
51
+ rescue_connection_failure do
52
+ @coll.find.each {|r| results << r}
53
+ [20, 30, 40, 50, 60, 70].each do |a|
54
+ assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"
55
+ end
56
+ end
57
+
58
+ @coll.save({:a => 80}, :w => 3)
59
+ @coll.find.each {|r| results << r}
60
+ [20, 30, 40, 50, 60, 70, 80].each do |a|
61
+ assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a} on second find"
62
+ end
63
+ end
64
+
65
+ context "Bulk API CollectionView" do
66
+ setup do
67
+ setup
68
+ end
69
+
70
+ should "handle error with deferred write concern error - spec Merging Results" do
71
+ with_write_commands_and_operations(@db.connection) do |wire_version|
72
+ @coll.remove
73
+ @coll.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
74
+ bulk = @coll.initialize_ordered_bulk_op
75
+ bulk.insert({:a => 1})
76
+ bulk.find({:a => 2}).upsert.update({'$set' => {:a => 2}})
77
+ bulk.insert({:a => 1})
78
+ ex = assert_raise BulkWriteError do
79
+ bulk.execute({:w => 5, :wtimeout => 1})
80
+ end
81
+ result = ex.result
82
+ assert_match_document(
83
+ {
84
+ "ok" => 1,
85
+ "n" => 2,
86
+ "writeErrors" => [
87
+ {
88
+ "index" => 2,
89
+ "code" => 11000,
90
+ "errmsg" => /duplicate key error/,
91
+ }
92
+ ],
93
+ "writeConcernError" => [
94
+ {
95
+ "errmsg" => /waiting for replication timed out|timed out waiting for slaves|timeout/,
96
+ "code" => 64,
97
+ "errInfo" => {"wtimeout" => true},
98
+ "index" => 0
99
+ },
100
+ {
101
+ "errmsg" => /waiting for replication timed out|timed out waiting for slaves|timeout/,
102
+ "code" => 64,
103
+ "errInfo" => {"wtimeout" => true},
104
+ "index" => 1
105
+ }
106
+ ],
107
+ "code" => 65,
108
+ "errmsg" => "batch item errors occurred",
109
+ "nInserted" => 1
110
+ }, result, "wire_version:#{wire_version}")
111
+ end
112
+ assert_equal 2, @coll.find.to_a.size
113
+ end
114
+
115
+ should "handle unordered errors with deferred write concern error - spec Merging Results" do # TODO - spec review
116
+ with_write_commands_and_operations(@db.connection) do |wire_version|
117
+ @coll.remove
118
+ @coll.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
119
+ bulk = @coll.initialize_unordered_bulk_op
120
+ bulk.insert({:a => 1})
121
+ bulk.find({:a => 2}).upsert.update({'$set' => {:a => 1}})
122
+ bulk.insert({:a => 3})
123
+ ex = assert_raise BulkWriteError do
124
+ bulk.execute({:w => 5, :wtimeout => 1})
125
+ end
126
+ result = ex.result # unordered varies, don't use assert_bulk_exception
127
+ assert_equal(1, result["ok"], "wire_version:#{wire_version}")
128
+ assert_equal(2, result["n"], "wire_version:#{wire_version}")
129
+ assert(result["nInserted"] >= 1, "wire_version:#{wire_version}")
130
+ assert_equal(65, result["code"], "wire_version:#{wire_version}")
131
+ assert_equal("batch item errors occurred", result["errmsg"], "wire_version:#{wire_version}")
132
+ assert(result["writeErrors"].size >= 1, "wire_version:#{wire_version}")
133
+ assert(result["writeConcernError"].size >= 1, "wire_version:#{wire_version}") if wire_version >= 2
134
+ assert(@coll.size >= 1, "wire_version:#{wire_version}")
135
+ end
136
+ end
137
+
138
+ end
139
+
140
+ end
@@ -0,0 +1,145 @@
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
+
17
+ class MaxValuesTest < Test::Unit::TestCase
18
+
19
+ include Mongo
20
+
21
+ def setup
22
+ ensure_cluster(:rs)
23
+ @client = MongoReplicaSetClient.new(@rs.repl_set_seeds, :name => @rs.repl_set_name)
24
+ @db = new_mock_db
25
+ @client.stubs(:[]).returns(@db)
26
+ @ismaster = {
27
+ 'hosts' => @client.local_manager.hosts.to_a,
28
+ 'arbiters' => @client.local_manager.arbiters
29
+ }
30
+ end
31
+
32
+ def test_initial_max_and_min_values
33
+ assert @client.max_bson_size
34
+ assert @client.max_message_size
35
+ assert @client.max_wire_version
36
+ assert @client.min_wire_version
37
+ end
38
+
39
+ def test_updated_max_and_min_sizes_after_node_config_change
40
+ @db.stubs(:command).returns(
41
+ @ismaster.merge({'ismaster' => true}),
42
+ @ismaster.merge({'secondary' => true, 'maxMessageSizeBytes' => 1024 * MESSAGE_SIZE_FACTOR}),
43
+ @ismaster.merge({'secondary' => true, 'maxBsonObjectSize' => 1024}),
44
+ @ismaster.merge({'secondary' => true, 'maxWireVersion' => 0}),
45
+ @ismaster.merge({'secondary' => true, 'minWireVersion' => 0})
46
+ )
47
+ @client.local_manager.stubs(:refresh_required?).returns(true)
48
+ @client.refresh
49
+
50
+ assert_equal 1024, @client.max_bson_size
51
+ assert_equal 1024 * MESSAGE_SIZE_FACTOR, @client.max_message_size
52
+ assert_equal 0, @client.max_wire_version
53
+ assert_equal 0, @client.min_wire_version
54
+ end
55
+
56
+ def test_no_values_in_config
57
+ @db.stubs(:command).returns(
58
+ @ismaster.merge({'ismaster' => true}),
59
+ @ismaster.merge({'secondary' => true}),
60
+ @ismaster.merge({'secondary' => true})
61
+ )
62
+ @client.local_manager.stubs(:refresh_required?).returns(true)
63
+ @client.refresh
64
+
65
+ assert_equal DEFAULT_MAX_BSON_SIZE, @client.max_bson_size
66
+ assert_equal DEFAULT_MAX_BSON_SIZE * MESSAGE_SIZE_FACTOR, @client.max_message_size
67
+ assert_equal 0, @client.max_wire_version
68
+ assert_equal 0, @client.min_wire_version
69
+ end
70
+
71
+ def test_only_bson_size_in_config
72
+ @db.stubs(:command).returns(
73
+ @ismaster.merge({'ismaster' => true}),
74
+ @ismaster.merge({'secondary' => true}),
75
+ @ismaster.merge({'secondary' => true, 'maxBsonObjectSize' => 1024})
76
+ )
77
+ @client.local_manager.stubs(:refresh_required?).returns(true)
78
+ @client.refresh
79
+
80
+ assert_equal 1024, @client.max_bson_size
81
+ assert_equal 1024 * MESSAGE_SIZE_FACTOR, @client.max_message_size
82
+ assert_equal 0, @client.max_wire_version
83
+ assert_equal 0, @client.min_wire_version
84
+ end
85
+
86
+ def test_values_in_config
87
+ #ismaster is called three times on the first node
88
+ @db.stubs(:command).returns(
89
+ @ismaster.merge({'ismaster' => true, 'maxMessageSizeBytes' => 1024 * 2 * MESSAGE_SIZE_FACTOR,
90
+ 'maxBsonObjectSize' => 1024, 'maxWireVersion' => 2, 'minWireVersion' => 1}),
91
+ @ismaster.merge({'ismaster' => true, 'maxMessageSizeBytes' => 1024 * 2 * MESSAGE_SIZE_FACTOR,
92
+ 'maxBsonObjectSize' => 1024, 'maxWireVersion' => 2, 'minWireVersion' => 1}),
93
+ @ismaster.merge({'ismaster' => true, 'maxMessageSizeBytes' => 1024 * 2 * MESSAGE_SIZE_FACTOR,
94
+ 'maxBsonObjectSize' => 1024, 'maxWireVersion' => 2, 'minWireVersion' => 1}),
95
+ @ismaster.merge({'secondary' => true, 'maxMessageSizeBytes' => 1024 * 2 * MESSAGE_SIZE_FACTOR,
96
+ 'maxBsonObjectSize' => 1024, 'maxWireVersion' => 2, 'minWireVersion' => 0}),
97
+ @ismaster.merge({'secondary' => true, 'maxMessageSizeBytes' => 1024 * 2 * MESSAGE_SIZE_FACTOR,
98
+ 'maxBsonObjectSize' => 1024, 'maxWireVersion' => 1, 'minWireVersion' => 0})
99
+ )
100
+ @client.local_manager.stubs(:refresh_required?).returns(true)
101
+ @client.refresh
102
+
103
+ assert_equal 1024, @client.max_bson_size
104
+ assert_equal 1024 * 2 * MESSAGE_SIZE_FACTOR, @client.max_message_size
105
+ assert_equal 1, @client.max_wire_version # minimum of all max_wire_version
106
+ assert_equal 1, @client.min_wire_version # maximum of all min_wire_version
107
+ end
108
+
109
+ def test_wire_version_not_in_range
110
+ min_wire_version, max_wire_version = [Mongo::MongoClient::MIN_WIRE_VERSION-1, Mongo::MongoClient::MIN_WIRE_VERSION-1]
111
+ #ismaster is called three times on the first node
112
+ @db.stubs(:command).returns(
113
+ @ismaster.merge({'ismaster' => true, 'maxWireVersion' => max_wire_version, 'minWireVersion' => min_wire_version}),
114
+ @ismaster.merge({'ismaster' => true, 'maxWireVersion' => max_wire_version, 'minWireVersion' => min_wire_version}),
115
+ @ismaster.merge({'ismaster' => true, 'maxWireVersion' => max_wire_version, 'minWireVersion' => min_wire_version}),
116
+ @ismaster.merge({'secondary' => true, 'maxWireVersion' => max_wire_version, 'minWireVersion' => min_wire_version}),
117
+ @ismaster.merge({'secondary' => true, 'maxWireVersion' => max_wire_version, 'minWireVersion' => min_wire_version})
118
+ )
119
+ @client.local_manager.stubs(:refresh_required?).returns(true)
120
+ assert_raises Mongo::ConnectionFailure do
121
+ @client.refresh
122
+ end
123
+ end
124
+
125
+ def test_use_write_command
126
+ with_write_commands(@client) do
127
+ assert_true @client.use_write_command?({:w => 1})
128
+ assert_false @client.use_write_command?({:w => 0})
129
+ end
130
+ with_write_operations(@client) do
131
+ assert_false @client.use_write_command?({:w => 1})
132
+ assert_false @client.use_write_command?({:w => 0})
133
+ end
134
+ @client.local_manager.primary_pool.node.expects(:wire_version_feature?).at_least_once.returns(true)
135
+ assert_true @client.use_write_command?({:w => 1})
136
+ assert_false @client.use_write_command?({:w => 0})
137
+ end
138
+
139
+ def test_max_write_batch_size
140
+ assert_equal Mongo::MongoClient::DEFAULT_MAX_WRITE_BATCH_SIZE, @client.max_write_batch_size
141
+ @client.local_manager.primary_pool.node.stubs(:max_write_batch_size).returns(999)
142
+ assert_equal 999, @client.max_write_batch_size
143
+ end
144
+ end
145
+
@@ -0,0 +1,55 @@
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
+
17
+ class ReplicaSetPinningTest < Test::Unit::TestCase
18
+ def setup
19
+ ensure_cluster(:rs)
20
+ @client = MongoReplicaSetClient.new(@rs.repl_set_seeds, :name => @rs.repl_set_name)
21
+ @db = @client.db(TEST_DB)
22
+ @coll = @db.collection("test-sets")
23
+ @coll.insert({:a => 1})
24
+ end
25
+
26
+ def test_unpinning
27
+ # pin primary
28
+ @coll.find_one
29
+ assert_equal @client.pinned_pool[:pool], @client.primary_pool
30
+
31
+ # pin secondary
32
+ @coll.find_one({}, :read => :secondary_preferred)
33
+ assert @client.secondary_pools.include? @client.pinned_pool[:pool]
34
+
35
+ # repin primary
36
+ @coll.find_one({}, :read => :primary_preferred)
37
+ assert_equal @client.pinned_pool[:pool], @client.primary_pool
38
+ end
39
+
40
+ def test_pinned_pool_is_local_to_thread
41
+ threads = []
42
+ 30.times do |i|
43
+ threads << Thread.new do
44
+ if i % 2 == 0
45
+ @coll.find_one({}, :read => :secondary_preferred)
46
+ assert @client.secondary_pools.include? @client.pinned_pool[:pool]
47
+ else
48
+ @coll.find_one({}, :read => :primary_preferred)
49
+ assert_equal @client.pinned_pool[:pool], @client.primary_pool
50
+ end
51
+ end
52
+ end
53
+ threads.each(&:join)
54
+ end
55
+ end
@@ -0,0 +1,73 @@
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
+
17
+ class ReplicaSetQueryTest < Test::Unit::TestCase
18
+
19
+ def setup
20
+ ensure_cluster(:rs)
21
+ @client = MongoReplicaSetClient.new @rs.repl_set_seeds
22
+ @db = @client.db(TEST_DB)
23
+ @db.drop_collection("test-sets")
24
+ @coll = @db.collection("test-sets")
25
+ end
26
+
27
+ def teardown
28
+ @client.close if @conn
29
+ end
30
+
31
+ def test_query
32
+ @coll.save({:a => 20}, :w => 3)
33
+ @coll.save({:a => 30}, :w => 3)
34
+ @coll.save({:a => 40}, :w => 3)
35
+ results = []
36
+ @coll.find.each {|r| results << r}
37
+ [20, 30, 40].each do |a|
38
+ assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"
39
+ end
40
+
41
+ @rs.primary.stop
42
+
43
+ results = []
44
+ rescue_connection_failure do
45
+ @coll.find.each {|r| results << r}
46
+ [20, 30, 40].each do |a|
47
+ assert results.any? {|r| r['a'] == a}, "Could not find record for a => #{a}"
48
+ end
49
+ end
50
+ end
51
+
52
+ # Create a large collection and do a secondary query that returns
53
+ # enough records to require sending a GETMORE. In between opening
54
+ # the cursor and sending the GETMORE, do a :primary query. Confirm
55
+ # that the cursor reading from the secondary continues to talk to
56
+ # the secondary, rather than trying to read the cursor from the
57
+ # primary, where it does not exist.
58
+ # def test_secondary_getmore
59
+ # 200.times do |i|
60
+ # @coll.save({:a => i}, :w => 3)
61
+ # end
62
+ # as = []
63
+ # # Set an explicit batch size, in case the default ever changes.
64
+ # @coll.find({}, { :batch_size => 100, :read => :secondary }) do |c|
65
+ # c.each do |result|
66
+ # as << result['a']
67
+ # @coll.find({:a => result['a']}, :read => :primary).map
68
+ # end
69
+ # end
70
+ # assert_equal(as.sort, 0.upto(199).to_a)
71
+ # end
72
+
73
+ end
@@ -0,0 +1,214 @@
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
+
17
+ class ReadPreferenceTest < Test::Unit::TestCase
18
+
19
+ def setup
20
+ ensure_cluster(:rs, :replicas => 2, :arbiters => 0)
21
+
22
+ # Insert data
23
+ primary = @rs.primary
24
+ conn = Connection.new(primary.host, primary.port)
25
+ db = conn.db(TEST_DB)
26
+ coll = db.collection("test-sets")
27
+ coll.save({:a => 20}, {:w => 2})
28
+ end
29
+
30
+ def test_read_primary
31
+ conn = make_connection
32
+ rescue_connection_failure do
33
+ assert conn.read_primary?
34
+ assert conn.primary?
35
+ end
36
+
37
+ conn = make_connection(:primary_preferred)
38
+ rescue_connection_failure do
39
+ assert conn.read_primary?
40
+ assert conn.primary?
41
+ end
42
+
43
+ conn = make_connection(:secondary)
44
+ rescue_connection_failure do
45
+ assert !conn.read_primary?
46
+ assert !conn.primary?
47
+ end
48
+
49
+ conn = make_connection(:secondary_preferred)
50
+ rescue_connection_failure do
51
+ assert !conn.read_primary?
52
+ assert !conn.primary?
53
+ end
54
+ end
55
+
56
+ def test_connection_pools
57
+ conn = make_connection
58
+ assert conn.primary_pool, "No primary pool!"
59
+ assert conn.read_pool, "No read pool!"
60
+ assert conn.primary_pool.port == conn.read_pool.port,
61
+ "Primary port and read port are not the same!"
62
+
63
+ conn = make_connection(:primary_preferred)
64
+ assert conn.primary_pool, "No primary pool!"
65
+ assert conn.read_pool, "No read pool!"
66
+ assert conn.primary_pool.port == conn.read_pool.port,
67
+ "Primary port and read port are not the same!"
68
+
69
+ conn = make_connection(:secondary)
70
+ assert conn.primary_pool, "No primary pool!"
71
+ assert conn.read_pool, "No read pool!"
72
+ assert conn.primary_pool.port != conn.read_pool.port,
73
+ "Primary port and read port are the same!"
74
+
75
+ conn = make_connection(:secondary_preferred)
76
+ assert conn.primary_pool, "No primary pool!"
77
+ assert conn.read_pool, "No read pool!"
78
+ assert conn.primary_pool.port != conn.read_pool.port,
79
+ "Primary port and read port are the same!"
80
+ end
81
+
82
+ def test_read_routing
83
+ prepare_routing_test
84
+
85
+ # Test that reads are going to the right members
86
+ assert_query_route(@primary, @primary_direct)
87
+ assert_query_route(@primary_preferred, @primary_direct)
88
+ assert_query_route(@secondary, @secondary_direct)
89
+ assert_query_route(@secondary_preferred, @secondary_direct)
90
+ end
91
+
92
+ def test_read_routing_with_primary_down
93
+ prepare_routing_test
94
+
95
+ # Test that reads are going to the right members
96
+ assert_query_route(@primary, @primary_direct)
97
+ assert_query_route(@primary_preferred, @primary_direct)
98
+ assert_query_route(@secondary, @secondary_direct)
99
+ assert_query_route(@secondary_preferred, @secondary_direct)
100
+
101
+ # Kill the primary so only a single secondary exists
102
+ @rs.primary.kill
103
+
104
+ # Test that reads are going to the right members
105
+ assert_raise_error ConnectionFailure do
106
+ @primary[TEST_DB]['test-sets'].find_one
107
+ end
108
+ assert_query_route(@primary_preferred, @secondary_direct)
109
+ assert_query_route(@secondary, @secondary_direct)
110
+ assert_query_route(@secondary_preferred, @secondary_direct)
111
+
112
+ # Restore set
113
+ @rs.restart
114
+ sleep(1)
115
+ @repl_cons.each { |con| con.refresh }
116
+ sleep(1)
117
+ @primary_direct = Connection.new(
118
+ @rs.config['host'],
119
+ @primary.read_pool.port
120
+ )
121
+
122
+ # Test that reads are going to the right members
123
+ assert_query_route(@primary, @primary_direct)
124
+ assert_query_route(@primary_preferred, @primary_direct)
125
+ assert_query_route(@secondary, @secondary_direct)
126
+ assert_query_route(@secondary_preferred, @secondary_direct)
127
+ end
128
+
129
+ def test_read_routing_with_secondary_down
130
+ prepare_routing_test
131
+
132
+ # Test that reads are going to the right members
133
+ assert_query_route(@primary, @primary_direct)
134
+ assert_query_route(@primary_preferred, @primary_direct)
135
+ assert_query_route(@secondary, @secondary_direct)
136
+ assert_query_route(@secondary_preferred, @secondary_direct)
137
+
138
+ # Kill the secondary so that only primary exists
139
+ @rs.secondaries.first.kill
140
+
141
+ # Test that reads are going to the right members
142
+ assert_query_route(@primary, @primary_direct)
143
+ assert_query_route(@primary_preferred, @primary_direct)
144
+ assert_raise_error ConnectionFailure do
145
+ @secondary[TEST_DB]['test-sets'].find_one
146
+ end
147
+ assert_query_route(@secondary_preferred, @primary_direct)
148
+
149
+ # Restore set
150
+ @rs.restart
151
+ sleep(1)
152
+ @repl_cons.each { |con| con.refresh }
153
+ sleep(1)
154
+ @secondary_direct = Connection.new(
155
+ @rs.config['host'],
156
+ @secondary.read_pool.port,
157
+ :slave_ok => true
158
+ )
159
+
160
+ # Test that reads are going to the right members
161
+ assert_query_route(@primary, @primary_direct)
162
+ assert_query_route(@primary_preferred, @primary_direct)
163
+ assert_query_route(@secondary, @secondary_direct)
164
+ assert_query_route(@secondary_preferred, @secondary_direct)
165
+ end
166
+
167
+ def test_write_lots_of_data
168
+ @conn = make_connection(:secondary_preferred)
169
+ @db = @conn[TEST_DB]
170
+ @coll = @db.collection("test-sets", {:w => 2})
171
+
172
+ 6000.times do |n|
173
+ @coll.save({:a => n})
174
+ end
175
+
176
+ cursor = @coll.find()
177
+ cursor.next
178
+ cursor.close
179
+ end
180
+
181
+ private
182
+
183
+ def prepare_routing_test
184
+ # Setup replica set connections
185
+ @primary = make_connection(:primary)
186
+ @primary_preferred = make_connection(:primary_preferred)
187
+ @secondary = make_connection(:secondary)
188
+ @secondary_preferred = make_connection(:secondary_preferred)
189
+ @repl_cons = [@primary, @primary_preferred, @secondary, @secondary_preferred]
190
+
191
+ # Setup direct connections
192
+ @primary_direct = Connection.new(@rs.config['host'], @primary.read_pool.port)
193
+ @secondary_direct = Connection.new(@rs.config['host'], @secondary.read_pool.port, :slave_ok => true)
194
+ end
195
+
196
+ def make_connection(mode = :primary, opts = {})
197
+ opts.merge!({:read => mode})
198
+ MongoReplicaSetClient.new(@rs.repl_set_seeds, opts)
199
+ end
200
+
201
+ def query_count(connection)
202
+ connection['admin'].command({:serverStatus => 1})['opcounters']['query']
203
+ end
204
+
205
+ def assert_query_route(test_connection, expected_target)
206
+ #puts "#{test_connection.read_pool.port} #{expected_target.read_pool.port}"
207
+ queries_before = query_count(expected_target)
208
+ assert_nothing_raised do
209
+ test_connection[TEST_DB]['test-sets'].find_one
210
+ end
211
+ queries_after = query_count(expected_target)
212
+ assert_equal 1, queries_after - queries_before
213
+ end
214
+ end