mongo 2.4.0.rc1 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/mongo/auth/cr/conversation.rb +1 -1
  5. data/lib/mongo/auth/ldap/conversation.rb +1 -1
  6. data/lib/mongo/auth/scram/conversation.rb +1 -1
  7. data/lib/mongo/auth/x509/conversation.rb +4 -2
  8. data/lib/mongo/client.rb +7 -4
  9. data/lib/mongo/cluster.rb +55 -5
  10. data/lib/mongo/cluster/app_metadata.rb +7 -1
  11. data/lib/mongo/cluster/topology.rb +7 -6
  12. data/lib/mongo/cluster/topology/replica_set.rb +48 -2
  13. data/lib/mongo/cluster/topology/sharded.rb +47 -1
  14. data/lib/mongo/cluster/topology/single.rb +55 -4
  15. data/lib/mongo/cluster/topology/unknown.rb +65 -9
  16. data/lib/mongo/error/invalid_server_preference.rb +3 -1
  17. data/lib/mongo/event.rb +8 -0
  18. data/lib/mongo/event/description_changed.rb +20 -2
  19. data/lib/mongo/event/member_discovered.rb +65 -0
  20. data/lib/mongo/event/primary_elected.rb +3 -1
  21. data/lib/mongo/event/standalone_discovered.rb +1 -1
  22. data/lib/mongo/monitoring.rb +41 -0
  23. data/lib/mongo/monitoring/event.rb +6 -0
  24. data/lib/mongo/monitoring/event/server_closed.rb +46 -0
  25. data/lib/mongo/monitoring/event/server_description_changed.rb +58 -0
  26. data/lib/mongo/monitoring/event/server_opening.rb +46 -0
  27. data/lib/mongo/monitoring/event/topology_changed.rb +46 -0
  28. data/lib/mongo/monitoring/event/topology_closed.rb +41 -0
  29. data/lib/mongo/monitoring/event/topology_opening.rb +41 -0
  30. data/lib/mongo/monitoring/publishable.rb +12 -0
  31. data/lib/mongo/monitoring/sdam_log_subscriber.rb +54 -0
  32. data/lib/mongo/monitoring/server_closed_log_subscriber.rb +30 -0
  33. data/lib/mongo/monitoring/server_description_changed_log_subscriber.rb +33 -0
  34. data/lib/mongo/monitoring/server_opening_log_subscriber.rb +30 -0
  35. data/lib/mongo/monitoring/topology_changed_log_subscriber.rb +40 -0
  36. data/lib/mongo/monitoring/topology_opening_log_subscriber.rb +30 -0
  37. data/lib/mongo/server.rb +6 -0
  38. data/lib/mongo/server/connection.rb +1 -1
  39. data/lib/mongo/server/description.rb +23 -3
  40. data/lib/mongo/server/description/inspector.rb +4 -2
  41. data/lib/mongo/server/description/inspector/description_changed.rb +2 -2
  42. data/lib/mongo/server/description/inspector/member_discovered.rb +59 -0
  43. data/lib/mongo/server/description/inspector/primary_elected.rb +2 -0
  44. data/lib/mongo/server_selector.rb +10 -5
  45. data/lib/mongo/server_selector/nearest.rb +1 -1
  46. data/lib/mongo/server_selector/primary_preferred.rb +1 -1
  47. data/lib/mongo/server_selector/secondary.rb +1 -1
  48. data/lib/mongo/server_selector/secondary_preferred.rb +1 -1
  49. data/lib/mongo/server_selector/selectable.rb +24 -12
  50. data/lib/mongo/uri.rb +1 -1
  51. data/lib/mongo/version.rb +1 -1
  52. data/mongo.gemspec +1 -1
  53. data/spec/mongo/auth/cr_spec.rb +6 -1
  54. data/spec/mongo/auth/ldap_spec.rb +6 -1
  55. data/spec/mongo/auth/scram_spec.rb +6 -1
  56. data/spec/mongo/auth/x509/conversation_spec.rb +69 -0
  57. data/spec/mongo/auth/x509_spec.rb +9 -4
  58. data/spec/mongo/client_spec.rb +40 -2
  59. data/spec/mongo/cluster/topology/replica_set_spec.rb +218 -9
  60. data/spec/mongo/cluster/topology/sharded_spec.rb +17 -2
  61. data/spec/mongo/cluster/topology/single_spec.rb +19 -4
  62. data/spec/mongo/cluster/topology/unknown_spec.rb +19 -1
  63. data/spec/mongo/cluster/topology_spec.rb +11 -7
  64. data/spec/mongo/cluster_spec.rb +25 -7
  65. data/spec/mongo/max_staleness_spec.rb +40 -22
  66. data/spec/mongo/monitoring_spec.rb +2 -2
  67. data/spec/mongo/sdam_monitoring_spec.rb +60 -0
  68. data/spec/mongo/sdam_spec.rb +77 -0
  69. data/spec/mongo/server/connection_pool_spec.rb +6 -1
  70. data/spec/mongo/server/connection_spec.rb +6 -1
  71. data/spec/mongo/server/description_spec.rb +90 -1
  72. data/spec/mongo/server_selection_spec.rb +7 -6
  73. data/spec/mongo/server_selector/nearest_spec.rb +7 -7
  74. data/spec/mongo/server_selector/primary_preferred_spec.rb +7 -7
  75. data/spec/mongo/server_selector/primary_spec.rb +4 -4
  76. data/spec/mongo/server_selector/secondary_preferred_spec.rb +6 -6
  77. data/spec/mongo/server_selector/secondary_spec.rb +6 -6
  78. data/spec/mongo/server_selector_spec.rb +8 -0
  79. data/spec/mongo/server_spec.rb +6 -1
  80. data/spec/mongo/uri_spec.rb +4 -4
  81. data/spec/spec_helper.rb +2 -0
  82. data/spec/support/max_staleness/ReplicaSetNoPrimary/Incompatible.yml +4 -4
  83. data/spec/support/max_staleness/ReplicaSetNoPrimary/LastUpdateTime.yml +3 -3
  84. data/spec/support/max_staleness/ReplicaSetNoPrimary/Nearest.yml +3 -3
  85. data/spec/support/max_staleness/ReplicaSetNoPrimary/Nearest2.yml +3 -3
  86. data/spec/support/max_staleness/ReplicaSetNoPrimary/NoKnownServers.yml +15 -0
  87. data/spec/support/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred.yml +1 -1
  88. data/spec/support/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred_tags.yml +3 -3
  89. data/spec/support/max_staleness/ReplicaSetNoPrimary/Secondary.yml +3 -3
  90. data/spec/support/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred.yml +1 -1
  91. data/spec/support/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred_tags.yml +3 -3
  92. data/spec/support/max_staleness/ReplicaSetNoPrimary/ZeroMaxStaleness.yml +23 -0
  93. data/spec/support/max_staleness/ReplicaSetWithPrimary/Incompatible.yml +4 -4
  94. data/spec/support/max_staleness/ReplicaSetWithPrimary/LastUpdateTime.yml +5 -5
  95. data/spec/support/max_staleness/ReplicaSetWithPrimary/{ShortHeartbeartShortMaxStaleness2.yml → LongHeartbeat.yml} +4 -4
  96. data/spec/support/max_staleness/ReplicaSetWithPrimary/{ShortHeartbeartShortMaxStaleness.yml → LongHeartbeat2.yml} +6 -10
  97. data/spec/support/max_staleness/ReplicaSetWithPrimary/MaxStalenessTooSmall.yml +3 -2
  98. data/spec/support/max_staleness/ReplicaSetWithPrimary/MaxStalenessWithModePrimary.yml +2 -2
  99. data/spec/support/max_staleness/ReplicaSetWithPrimary/Nearest.yml +3 -3
  100. data/spec/support/max_staleness/ReplicaSetWithPrimary/Nearest2.yml +3 -3
  101. data/spec/support/max_staleness/ReplicaSetWithPrimary/Nearest_tags.yml +3 -3
  102. data/spec/support/max_staleness/ReplicaSetWithPrimary/PrimaryPreferred.yml +2 -2
  103. data/spec/support/max_staleness/ReplicaSetWithPrimary/PrimaryPreferred_incompatible.yml +3 -3
  104. data/spec/support/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred.yml +1 -1
  105. data/spec/support/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags.yml +3 -3
  106. data/spec/support/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags2.yml +3 -3
  107. data/spec/support/max_staleness/ReplicaSetWithPrimary/Secondary_tags.yml +3 -3
  108. data/spec/support/max_staleness/ReplicaSetWithPrimary/Secondary_tags2.yml +3 -3
  109. data/spec/support/max_staleness/ReplicaSetWithPrimary/ZeroMaxStaleness.yml +7 -11
  110. data/spec/support/max_staleness/Sharded/Incompatible.yml +4 -4
  111. data/spec/support/max_staleness/Sharded/SmallMaxStaleness.yml +10 -2
  112. data/spec/support/max_staleness/Single/Incompatible.yml +4 -4
  113. data/spec/support/max_staleness/Single/SmallMaxStaleness.yml +2 -2
  114. data/spec/support/max_staleness/Unknown/SmallMaxStaleness.yml +14 -0
  115. data/spec/support/sdam/rs/primary_mismatched_me.yml +2 -2
  116. data/spec/support/sdam/rs/secondary_mismatched_me.yml +2 -2
  117. data/spec/support/sdam_monitoring.rb +144 -0
  118. data/spec/support/sdam_monitoring/replica_set_with_no_primary.yml +112 -0
  119. data/spec/support/sdam_monitoring/replica_set_with_primary.yml +111 -0
  120. data/spec/support/sdam_monitoring/replica_set_with_removal.yml +106 -0
  121. data/spec/support/sdam_monitoring/required_replica_set.yml +84 -0
  122. data/spec/support/sdam_monitoring/standalone.yml +70 -0
  123. data/spec/support/server_discovery_and_monitoring.rb +34 -1
  124. data/spec/support/server_selection.rb +14 -11
  125. data/spec/support/shared/server_selector.rb +6 -0
  126. metadata +49 -13
  127. metadata.gz.sig +0 -0
  128. data/spec/mongo/server_discovery_and_monitoring_spec.rb +0 -115
@@ -17,5 +17,5 @@ module Mongo
17
17
  # The current version of the driver.
18
18
  #
19
19
  # @since 2.0.0
20
- VERSION = '2.4.0.rc1'.freeze
20
+ VERSION = '2.4.0'.freeze
21
21
  end
@@ -30,5 +30,5 @@ Gem::Specification.new do |s|
30
30
  s.has_rdoc = 'yard'
31
31
  s.bindir = 'bin'
32
32
 
33
- s.add_dependency 'bson', '~> 4.2.0.rc1'
33
+ s.add_dependency 'bson', '~> 4.2.0'
34
34
  end
@@ -7,7 +7,7 @@ describe Mongo::Auth::CR do
7
7
  end
8
8
 
9
9
  let(:monitoring) do
10
- Mongo::Monitoring.new
10
+ Mongo::Monitoring.new(monitoring: false)
11
11
  end
12
12
 
13
13
  let(:listeners) do
@@ -16,10 +16,15 @@ describe Mongo::Auth::CR do
16
16
 
17
17
  let(:cluster) do
18
18
  double('cluster').tap do |cl|
19
+ allow(cl).to receive(:topology).and_return(topology)
19
20
  allow(cl).to receive(:app_metadata).and_return(app_metadata)
20
21
  end
21
22
  end
22
23
 
24
+ let(:topology) do
25
+ double('topology')
26
+ end
27
+
23
28
  let(:server) do
24
29
  Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
25
30
  end
@@ -7,7 +7,7 @@ describe Mongo::Auth::LDAP do
7
7
  end
8
8
 
9
9
  let(:monitoring) do
10
- Mongo::Monitoring.new
10
+ Mongo::Monitoring.new(monitoring: false)
11
11
  end
12
12
 
13
13
  let(:listeners) do
@@ -16,10 +16,15 @@ describe Mongo::Auth::LDAP do
16
16
 
17
17
  let(:cluster) do
18
18
  double('cluster').tap do |cl|
19
+ allow(cl).to receive(:topology).and_return(topology)
19
20
  allow(cl).to receive(:app_metadata).and_return(app_metadata)
20
21
  end
21
22
  end
22
23
 
24
+ let(:topology) do
25
+ double('topology')
26
+ end
27
+
23
28
  let(:server) do
24
29
  Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
25
30
  end
@@ -7,7 +7,7 @@ describe Mongo::Auth::SCRAM do
7
7
  end
8
8
 
9
9
  let(:monitoring) do
10
- Mongo::Monitoring.new
10
+ Mongo::Monitoring.new(monitoring: false)
11
11
  end
12
12
 
13
13
  let(:listeners) do
@@ -16,10 +16,15 @@ describe Mongo::Auth::SCRAM do
16
16
 
17
17
  let(:cluster) do
18
18
  double('cluster').tap do |cl|
19
+ allow(cl).to receive(:topology).and_return(topology)
19
20
  allow(cl).to receive(:app_metadata).and_return(app_metadata)
20
21
  end
21
22
  end
22
23
 
24
+ let(:topology) do
25
+ double('topology')
26
+ end
27
+
23
28
  let(:server) do
24
29
  Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
25
30
  end
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::Auth::X509::Conversation do
4
+
5
+ let(:user) do
6
+ Mongo::Auth::User.new(
7
+ database: Mongo::Database::ADMIN,
8
+ user: 'user',
9
+ )
10
+ end
11
+
12
+ let(:conversation) do
13
+ described_class.new(user)
14
+ end
15
+
16
+ describe '#start' do
17
+
18
+ let(:query) do
19
+ conversation.start
20
+ end
21
+
22
+ let(:selector) do
23
+ query.selector
24
+ end
25
+
26
+ it 'sets username' do
27
+ expect(selector[:user]).to eq('user')
28
+ end
29
+
30
+ it 'sets the mechanism' do
31
+ expect(selector[:mechanism]).to eq('MONGODB-X509')
32
+ end
33
+
34
+ context 'when a username is not provided' do
35
+
36
+ let(:user) do
37
+ Mongo::Auth::User.new(
38
+ database: Mongo::Database::ADMIN
39
+ )
40
+ end
41
+
42
+ it 'does not set the username' do
43
+ expect(selector[:user]).to be_nil
44
+ end
45
+
46
+ it 'sets the mechanism' do
47
+ expect(selector[:mechanism]).to eq('MONGODB-X509')
48
+ end
49
+ end
50
+
51
+ context 'when the username is nil' do
52
+
53
+ let(:user) do
54
+ Mongo::Auth::User.new(
55
+ database: Mongo::Database::ADMIN,
56
+ user: nil
57
+ )
58
+ end
59
+
60
+ it 'does not set the username' do
61
+ expect(selector.has_key?(:user)).to be(false)
62
+ end
63
+
64
+ it 'sets the mechanism' do
65
+ expect(selector[:mechanism]).to eq('MONGODB-X509')
66
+ end
67
+ end
68
+ end
69
+ end
@@ -7,7 +7,7 @@ describe Mongo::Auth::X509 do
7
7
  end
8
8
 
9
9
  let(:monitoring) do
10
- Mongo::Monitoring.new
10
+ Mongo::Monitoring.new(monitoring: false)
11
11
  end
12
12
 
13
13
  let(:listeners) do
@@ -16,10 +16,15 @@ describe Mongo::Auth::X509 do
16
16
 
17
17
  let(:cluster) do
18
18
  double('cluster').tap do |cl|
19
+ allow(cl).to receive(:topology).and_return(topology)
19
20
  allow(cl).to receive(:app_metadata).and_return(app_metadata)
20
21
  end
21
22
  end
22
23
 
24
+ let(:topology) do
25
+ double('topology')
26
+ end
27
+
23
28
  let(:server) do
24
29
  Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
25
30
  end
@@ -36,17 +41,17 @@ describe Mongo::Auth::X509 do
36
41
 
37
42
  context 'when the user is not authorized for the database' do
38
43
 
39
- let(:cr) do
44
+ let(:x509) do
40
45
  described_class.new(user)
41
46
  end
42
47
 
43
48
  let(:login) do
44
- cr.login(connection).documents[0]
49
+ x509.login(connection).documents[0]
45
50
  end
46
51
 
47
52
  it 'logs the user into the connection' do
48
53
  expect {
49
- cr.login(connection)
54
+ x509.login(connection)
50
55
  }.to raise_error(Mongo::Auth::Unauthorized)
51
56
  end
52
57
  end
@@ -158,7 +158,7 @@ describe Mongo::Client do
158
158
  described_class.new(
159
159
  ['127.0.0.1:27017'],
160
160
  :read => { :mode => :primary },
161
- :local_threshold => 10,
161
+ :local_threshold => 0.010,
162
162
  :server_selection_timeout => 10000,
163
163
  :database => TEST_DB
164
164
  )
@@ -166,7 +166,7 @@ describe Mongo::Client do
166
166
 
167
167
  let(:options) do
168
168
  Mongo::Options::Redacted.new(:read => { :mode => :primary },
169
- :local_threshold => 10,
169
+ :local_threshold => 0.010,
170
170
  :server_selection_timeout => 10000,
171
171
  :database => TEST_DB)
172
172
  end
@@ -271,6 +271,44 @@ describe Mongo::Client do
271
271
  expect(client.cluster.options[:heartbeat_frequency]).to eq(client.options[:heartbeat_frequency])
272
272
  end
273
273
  end
274
+
275
+ context 'when platform details are specified' do
276
+
277
+ let(:app_metadata) do
278
+ client.cluster.app_metadata
279
+ end
280
+
281
+ let(:client) do
282
+ described_class.new(['127.0.0.1:27017'], :platform => 'mongoid-6.0.2')
283
+ end
284
+
285
+ it 'includes the platform info in the app metadata' do
286
+ expect(app_metadata.send(:full_client_document)[:platform]).to match(/mongoid-6\.0\.2/)
287
+ end
288
+ end
289
+
290
+ context 'when platform details are not specified' do
291
+
292
+ let(:app_metadata) do
293
+ client.cluster.app_metadata
294
+ end
295
+
296
+ let(:client) do
297
+ described_class.new(['127.0.0.1:27017'])
298
+ end
299
+
300
+ let(:platform_string) do
301
+ [
302
+ RUBY_VERSION,
303
+ RUBY_PLATFORM,
304
+ RbConfig::CONFIG['build']
305
+ ].join(', ')
306
+ end
307
+
308
+ it 'does not include the platform info in the app metadata' do
309
+ expect(app_metadata.send(:full_client_document)[:platform]).to eq(platform_string)
310
+ end
311
+ end
274
312
  end
275
313
 
276
314
  context 'when providing a connection string' do
@@ -11,11 +11,12 @@ describe Mongo::Cluster::Topology::ReplicaSet do
11
11
  end
12
12
 
13
13
  let(:monitoring) do
14
- Mongo::Monitoring.new
14
+ Mongo::Monitoring.new(monitoring: false)
15
15
  end
16
16
 
17
17
  let(:cluster) do
18
18
  double('cluster').tap do |cl|
19
+ allow(cl).to receive(:topology).and_return(topology)
19
20
  allow(cl).to receive(:app_metadata).and_return(app_metadata)
20
21
  end
21
22
  end
@@ -64,7 +65,7 @@ describe Mongo::Cluster::Topology::ReplicaSet do
64
65
  context 'when no replica set name is provided' do
65
66
 
66
67
  let(:topology) do
67
- described_class.new({})
68
+ described_class.new({}, monitoring, [])
68
69
  end
69
70
 
70
71
  let(:servers) do
@@ -79,7 +80,7 @@ describe Mongo::Cluster::Topology::ReplicaSet do
79
80
  context 'when a replica set name is provided' do
80
81
 
81
82
  let(:topology) do
82
- described_class.new(:replica_set => 'testing')
83
+ described_class.new({ :replica_set => 'testing' }, monitoring)
83
84
  end
84
85
 
85
86
  let(:servers) do
@@ -95,21 +96,229 @@ describe Mongo::Cluster::Topology::ReplicaSet do
95
96
  describe '.replica_set?' do
96
97
 
97
98
  it 'returns true' do
98
- expect(described_class.new({})).to be_replica_set
99
+ expect(described_class.new({}, monitoring)).to be_replica_set
99
100
  end
100
101
  end
101
102
 
102
103
  describe '.sharded?' do
103
104
 
104
105
  it 'returns false' do
105
- expect(described_class.new({})).to_not be_sharded
106
+ expect(described_class.new({}, monitoring)).to_not be_sharded
106
107
  end
107
108
  end
108
109
 
109
110
  describe '.single?' do
110
111
 
111
112
  it 'returns false' do
112
- expect(described_class.new({})).to_not be_single
113
+ expect(described_class.new({}, monitoring)).to_not be_single
114
+ end
115
+ end
116
+
117
+ describe '#has_readable_servers?' do
118
+
119
+ let(:topology) do
120
+ described_class.new({}, monitoring, [])
121
+ end
122
+
123
+ let(:cluster) do
124
+ double('cluster', servers: servers, single?: false, sharded?: false, unknown?: false)
125
+ end
126
+
127
+ context 'when the read preference is primary' do
128
+
129
+ let(:selector) do
130
+ Mongo::ServerSelector.get(:mode => :primary)
131
+ end
132
+
133
+ context 'when a primary exists' do
134
+
135
+ let(:servers) do
136
+ [ double('server', primary?: true) ]
137
+ end
138
+
139
+ it 'returns true' do
140
+ expect(topology).to have_readable_server(cluster, selector)
141
+ end
142
+ end
143
+
144
+ context 'when a primary does not exist' do
145
+
146
+ let(:servers) do
147
+ [ double('server', primary?: false) ]
148
+ end
149
+
150
+ it 'returns false' do
151
+ expect(topology).to_not have_readable_server(cluster, selector)
152
+ end
153
+ end
154
+ end
155
+
156
+ context 'when the read preference is primary preferred' do
157
+
158
+ let(:selector) do
159
+ Mongo::ServerSelector.get(:mode => :primary_preferred)
160
+ end
161
+
162
+ context 'when a primary exists' do
163
+
164
+ let(:servers) do
165
+ [ double('server', primary?: true, secondary?: false) ]
166
+ end
167
+
168
+ it 'returns true' do
169
+ expect(topology).to have_readable_server(cluster, selector)
170
+ end
171
+ end
172
+
173
+ context 'when a primary does not exist' do
174
+
175
+ let(:servers) do
176
+ [ double('server', primary?: false, secondary?: true, average_round_trip_time: 0.01) ]
177
+ end
178
+
179
+ it 'returns true' do
180
+ expect(topology).to have_readable_server(cluster, selector)
181
+ end
182
+ end
183
+ end
184
+
185
+ context 'when the read preference is secondary' do
186
+
187
+ let(:selector) do
188
+ Mongo::ServerSelector.get(:mode => :secondary)
189
+ end
190
+
191
+ context 'when a secondary exists' do
192
+
193
+ let(:servers) do
194
+ [ double('server', primary?: false, secondary?: true, average_round_trip_time: 0.01) ]
195
+ end
196
+
197
+ it 'returns true' do
198
+ expect(topology).to have_readable_server(cluster, selector)
199
+ end
200
+ end
201
+
202
+ context 'when a secondary does not exist' do
203
+
204
+ let(:servers) do
205
+ [ double('server', primary?: true, secondary?: false) ]
206
+ end
207
+
208
+ it 'returns false' do
209
+ expect(topology).to_not have_readable_server(cluster, selector)
210
+ end
211
+ end
212
+ end
213
+
214
+ context 'when the read preference is secondary preferred' do
215
+
216
+ let(:selector) do
217
+ Mongo::ServerSelector.get(:mode => :secondary_preferred)
218
+ end
219
+
220
+ context 'when a secondary exists' do
221
+
222
+ let(:servers) do
223
+ [ double('server', primary?: false, secondary?: true, average_round_trip_time: 0.01) ]
224
+ end
225
+
226
+ it 'returns true' do
227
+ expect(topology).to have_readable_server(cluster, selector)
228
+ end
229
+ end
230
+
231
+ context 'when a secondary does not exist' do
232
+
233
+ let(:servers) do
234
+ [ double('server', secondary?: false, primary?: true) ]
235
+ end
236
+
237
+ it 'returns true' do
238
+ expect(topology).to have_readable_server(cluster, selector)
239
+ end
240
+ end
241
+ end
242
+
243
+ context 'when the read preference is nearest' do
244
+
245
+ let(:selector) do
246
+ Mongo::ServerSelector.get(:mode => :nearest)
247
+ end
248
+
249
+ let(:servers) do
250
+ [ double('server', primary?: false, secondary?: true, average_round_trip_time: 0.01) ]
251
+ end
252
+
253
+ it 'returns true' do
254
+ expect(topology).to have_readable_server(cluster, selector)
255
+ end
256
+ end
257
+
258
+ context 'when the read preference is not provided' do
259
+
260
+ context 'when a primary exists' do
261
+
262
+ let(:servers) do
263
+ [ double('server', primary?: true, secondary?: false) ]
264
+ end
265
+
266
+ it 'returns true' do
267
+ expect(topology).to have_readable_server(cluster)
268
+ end
269
+ end
270
+
271
+ context 'when a primary does not exist' do
272
+
273
+ let(:servers) do
274
+ [ double('server', primary?: false, secondary?: true, average_round_trip_time: 0.01) ]
275
+ end
276
+
277
+ it 'returns false' do
278
+ expect(topology).to_not have_readable_server(cluster)
279
+ end
280
+ end
281
+ end
282
+ end
283
+
284
+ describe '#has_writable_servers?' do
285
+
286
+ let(:topology) do
287
+ described_class.new({}, monitoring, [])
288
+ end
289
+
290
+ context 'when a primary server exists' do
291
+
292
+ let(:primary) do
293
+ double('server', :primary? => true)
294
+ end
295
+
296
+ let(:secondary) do
297
+ double('server', :primary? => false)
298
+ end
299
+
300
+ let(:cluster) do
301
+ double('cluster', servers: [ primary, secondary ])
302
+ end
303
+
304
+ it 'returns true' do
305
+ expect(topology).to have_writable_server(cluster)
306
+ end
307
+ end
308
+
309
+ context 'when no primary server exists' do
310
+
311
+ let(:server) do
312
+ double('server', :primary? => false)
313
+ end
314
+
315
+ let(:cluster) do
316
+ double('cluster', servers: [ server ])
317
+ end
318
+
319
+ it 'returns false' do
320
+ expect(topology).to_not have_writable_server(cluster)
321
+ end
113
322
  end
114
323
  end
115
324
 
@@ -133,7 +342,7 @@ describe Mongo::Cluster::Topology::ReplicaSet do
133
342
  end
134
343
 
135
344
  let(:topology) do
136
- described_class.new(:replica_set => 'testing')
345
+ described_class.new({ :replica_set => 'testing' }, monitoring)
137
346
  end
138
347
 
139
348
  before do
@@ -207,7 +416,7 @@ describe Mongo::Cluster::Topology::ReplicaSet do
207
416
  end
208
417
 
209
418
  let(:topology) do
210
- described_class.new(:replica_set => 'testing')
419
+ described_class.new({ :replica_set => 'testing' }, monitoring)
211
420
  end
212
421
 
213
422
  before do
@@ -289,7 +498,7 @@ describe Mongo::Cluster::Topology::ReplicaSet do
289
498
  end
290
499
 
291
500
  let(:topology) do
292
- described_class.new(:replica_set => 'testing')
501
+ described_class.new({ :replica_set => 'testing' }, monitoring)
293
502
  end
294
503
 
295
504
  before do