mongo 2.10.5 → 2.11.0.rc0

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 (191) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CONTRIBUTING.md +1 -1
  5. data/lib/mongo.rb +2 -0
  6. data/lib/mongo/address.rb +4 -0
  7. data/lib/mongo/address/validator.rb +99 -0
  8. data/lib/mongo/auth.rb +7 -2
  9. data/lib/mongo/auth/user.rb +1 -7
  10. data/lib/mongo/background_thread.rb +135 -0
  11. data/lib/mongo/bulk_write/transformable.rb +3 -3
  12. data/lib/mongo/client.rb +74 -16
  13. data/lib/mongo/cluster.rb +193 -41
  14. data/lib/mongo/cluster/periodic_executor.rb +31 -43
  15. data/lib/mongo/cluster/sdam_flow.rb +26 -3
  16. data/lib/mongo/cluster/srv_monitor.rb +127 -0
  17. data/lib/mongo/collection/view/readable.rb +3 -5
  18. data/lib/mongo/collection/view/writable.rb +3 -3
  19. data/lib/mongo/cursor/builder/get_more_command.rb +1 -4
  20. data/lib/mongo/cursor/builder/kill_cursors_command.rb +5 -23
  21. data/lib/mongo/cursor/builder/op_get_more.rb +2 -2
  22. data/lib/mongo/cursor/builder/op_kill_cursors.rb +5 -24
  23. data/lib/mongo/error.rb +1 -0
  24. data/lib/mongo/error/auth_error.rb +1 -1
  25. data/lib/mongo/error/connection_check_out_timeout.rb +7 -8
  26. data/lib/mongo/error/invalid_address.rb +24 -0
  27. data/lib/mongo/error/notable.rb +2 -2
  28. data/lib/mongo/error/operation_failure.rb +3 -3
  29. data/lib/mongo/error/pool_closed_error.rb +11 -4
  30. data/lib/mongo/event.rb +1 -1
  31. data/lib/mongo/grid/file.rb +0 -5
  32. data/lib/mongo/grid/file/chunk.rb +0 -2
  33. data/lib/mongo/grid/fs_bucket.rb +13 -15
  34. data/lib/mongo/grid/stream/write.rb +3 -9
  35. data/lib/mongo/loggable.rb +5 -1
  36. data/lib/mongo/monitoring.rb +1 -0
  37. data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +7 -0
  38. data/lib/mongo/monitoring/event/cmap/connection_checked_in.rb +11 -3
  39. data/lib/mongo/monitoring/event/cmap/connection_checked_out.rb +11 -3
  40. data/lib/mongo/monitoring/event/cmap/pool_closed.rb +11 -3
  41. data/lib/mongo/monitoring/event/cmap/pool_created.rb +12 -3
  42. data/lib/mongo/monitoring/unified_sdam_log_subscriber.rb +62 -0
  43. data/lib/mongo/operation/shared/executable.rb +5 -10
  44. data/lib/mongo/operation/shared/sessions_supported.rb +1 -5
  45. data/lib/mongo/protocol/get_more.rb +1 -2
  46. data/lib/mongo/protocol/kill_cursors.rb +13 -6
  47. data/lib/mongo/protocol/serializers.rb +4 -20
  48. data/lib/mongo/retryable.rb +9 -34
  49. data/lib/mongo/semaphore.rb +1 -1
  50. data/lib/mongo/server.rb +113 -42
  51. data/lib/mongo/server/connection.rb +12 -5
  52. data/lib/mongo/server/connection_pool.rb +250 -40
  53. data/lib/mongo/server/connection_pool/populator.rb +58 -0
  54. data/lib/mongo/server/description.rb +9 -2
  55. data/lib/mongo/server/monitor.rb +68 -93
  56. data/lib/mongo/server/monitor/connection.rb +2 -0
  57. data/lib/mongo/server_selector/selectable.rb +13 -5
  58. data/lib/mongo/session.rb +0 -13
  59. data/lib/mongo/srv.rb +17 -0
  60. data/lib/mongo/srv/monitor.rb +96 -0
  61. data/lib/mongo/srv/resolver.rb +130 -0
  62. data/lib/mongo/srv/result.rb +126 -0
  63. data/lib/mongo/srv/warning_result.rb +35 -0
  64. data/lib/mongo/uri.rb +45 -55
  65. data/lib/mongo/uri/srv_protocol.rb +89 -42
  66. data/lib/mongo/version.rb +1 -1
  67. data/mongo.gemspec +3 -4
  68. data/spec/README.md +6 -1
  69. data/spec/enterprise_auth/kerberos_spec.rb +7 -6
  70. data/spec/integration/change_stream_examples_spec.rb +0 -4
  71. data/spec/integration/client_construction_spec.rb +14 -2
  72. data/spec/integration/connect_single_rs_name_spec.rb +2 -2
  73. data/spec/integration/connection_pool_populator_spec.rb +296 -0
  74. data/spec/integration/connection_spec.rb +31 -22
  75. data/spec/integration/cursor_reaping_spec.rb +1 -2
  76. data/spec/integration/docs_examples_spec.rb +0 -4
  77. data/spec/integration/heartbeat_events_spec.rb +17 -15
  78. data/spec/integration/reconnect_spec.rb +144 -1
  79. data/spec/integration/retryable_writes_errors_spec.rb +0 -4
  80. data/spec/integration/retryable_writes_spec.rb +36 -36
  81. data/spec/integration/sdam_error_handling_spec.rb +31 -25
  82. data/spec/integration/sdam_events_spec.rb +2 -6
  83. data/spec/integration/server_monitor_spec.rb +28 -0
  84. data/spec/integration/server_selector_spec.rb +7 -5
  85. data/spec/integration/srv_monitoring_spec.rb +360 -0
  86. data/spec/integration/step_down_spec.rb +4 -6
  87. data/spec/lite_spec_helper.rb +22 -0
  88. data/spec/mongo/address/validator_spec.rb +51 -0
  89. data/spec/mongo/auth/cr_spec.rb +1 -29
  90. data/spec/mongo/auth/ldap_spec.rb +1 -29
  91. data/spec/mongo/auth/scram/conversation_spec.rb +0 -2
  92. data/spec/mongo/auth/scram/negotiation_spec.rb +1 -1
  93. data/spec/mongo/auth/scram_spec.rb +1 -29
  94. data/spec/mongo/auth/user/view_spec.rb +1 -36
  95. data/spec/mongo/auth/user_spec.rb +0 -12
  96. data/spec/mongo/auth/x509_spec.rb +1 -29
  97. data/spec/mongo/bulk_write_spec.rb +2 -2
  98. data/spec/mongo/client_construction_spec.rb +56 -15
  99. data/spec/mongo/client_spec.rb +31 -27
  100. data/spec/mongo/cluster/periodic_executor_spec.rb +16 -0
  101. data/spec/mongo/cluster/srv_monitor_spec.rb +214 -0
  102. data/spec/mongo/cluster/topology/replica_set_spec.rb +16 -11
  103. data/spec/mongo/cluster/topology/sharded_spec.rb +12 -9
  104. data/spec/mongo/cluster/topology/single_spec.rb +20 -11
  105. data/spec/mongo/cluster_spec.rb +45 -29
  106. data/spec/mongo/collection/view/map_reduce_spec.rb +14 -9
  107. data/spec/mongo/collection/view/readable_spec.rb +0 -16
  108. data/spec/mongo/collection_spec.rb +0 -44
  109. data/spec/mongo/cursor/builder/get_more_command_spec.rb +2 -4
  110. data/spec/mongo/cursor/builder/op_get_more_spec.rb +2 -4
  111. data/spec/mongo/cursor_spec.rb +27 -7
  112. data/spec/mongo/monitoring/event/cmap/connection_checked_in_spec.rb +10 -3
  113. data/spec/mongo/monitoring/event/cmap/connection_checked_out_spec.rb +10 -3
  114. data/spec/mongo/monitoring/event/cmap/pool_closed_spec.rb +10 -3
  115. data/spec/mongo/monitoring/event/cmap/pool_created_spec.rb +10 -3
  116. data/spec/mongo/operation/delete/op_msg_spec.rb +17 -8
  117. data/spec/mongo/operation/insert/op_msg_spec.rb +50 -35
  118. data/spec/mongo/operation/update/op_msg_spec.rb +14 -7
  119. data/spec/mongo/retryable_spec.rb +52 -31
  120. data/spec/mongo/server/app_metadata_spec.rb +0 -8
  121. data/spec/mongo/server/connection_auth_spec.rb +5 -2
  122. data/spec/mongo/server/connection_pool/populator_spec.rb +101 -0
  123. data/spec/mongo/server/connection_pool_spec.rb +256 -107
  124. data/spec/mongo/server/connection_spec.rb +22 -33
  125. data/spec/mongo/server/description_spec.rb +42 -4
  126. data/spec/mongo/server/monitor/connection_spec.rb +22 -11
  127. data/spec/mongo/server/monitor_spec.rb +66 -107
  128. data/spec/mongo/server_spec.rb +82 -60
  129. data/spec/mongo/session/session_pool_spec.rb +1 -5
  130. data/spec/mongo/session_spec.rb +0 -4
  131. data/spec/mongo/socket/ssl_spec.rb +2 -2
  132. data/spec/mongo/srv/monitor_spec.rb +211 -0
  133. data/spec/mongo/srv/result_spec.rb +54 -0
  134. data/spec/mongo/uri/srv_protocol_spec.rb +30 -15
  135. data/spec/mongo/uri_spec.rb +125 -4
  136. data/spec/spec_helper.rb +6 -0
  137. data/spec/spec_tests/auth_spec.rb +39 -0
  138. data/spec/spec_tests/cmap_spec.rb +55 -8
  139. data/spec/spec_tests/connection_string_spec.rb +6 -31
  140. data/spec/spec_tests/data/auth/connection-string.yml +297 -0
  141. data/spec/spec_tests/data/cmap/pool-checkout-error-closed.yml +4 -1
  142. data/spec/spec_tests/data/cmap/pool-create-with-options.yml +1 -0
  143. data/spec/spec_tests/data/command_monitoring/insertMany.yml +1 -1
  144. data/spec/spec_tests/data/connection_string/invalid-uris.yml +20 -0
  145. data/spec/spec_tests/data/connection_string/valid-auth.yml +16 -0
  146. data/spec/spec_tests/data/connection_string/valid-warnings.yml +26 -30
  147. data/spec/spec_tests/data/transactions/abort.yml +3 -3
  148. data/spec/spec_tests/data/transactions/error-labels.yml +3 -3
  149. data/spec/spec_tests/data/transactions_api/callback-retry.yml +3 -3
  150. data/spec/spec_tests/data/uri_options/auth-options.yml +1 -1
  151. data/spec/spec_tests/max_staleness_spec.rb +7 -2
  152. data/spec/spec_tests/retryable_reads_spec.rb +0 -31
  153. data/spec/spec_tests/sdam_monitoring_spec.rb +12 -12
  154. data/spec/spec_tests/sdam_spec.rb +4 -7
  155. data/spec/spec_tests/server_selection_spec.rb +6 -2
  156. data/spec/spec_tests/transactions_spec.rb +0 -2
  157. data/spec/spec_tests/uri_options_spec.rb +4 -2
  158. data/spec/stress/connection_pool_stress_spec.rb +203 -0
  159. data/spec/stress/connection_pool_timing_spec.rb +181 -0
  160. data/spec/support/auth.rb +113 -0
  161. data/spec/support/background_thread_registry.rb +63 -0
  162. data/spec/support/client_registry.rb +11 -2
  163. data/spec/support/cluster_config.rb +65 -46
  164. data/spec/support/cluster_tools.rb +2 -2
  165. data/spec/support/cmap.rb +13 -14
  166. data/spec/support/cmap/verifier.rb +4 -5
  167. data/spec/support/command_monitoring.rb +0 -5
  168. data/spec/support/common_shortcuts.rb +101 -1
  169. data/spec/support/constraints.rb +25 -0
  170. data/spec/support/dns.rb +13 -0
  171. data/spec/support/event_subscriber.rb +0 -7
  172. data/spec/support/json_ext_formatter.rb +5 -1
  173. data/spec/support/lite_constraints.rb +22 -6
  174. data/spec/support/local_resource_registry.rb +34 -0
  175. data/spec/support/sdam_monitoring.rb +115 -0
  176. data/spec/support/spec_config.rb +20 -6
  177. data/spec/support/spec_setup.rb +2 -2
  178. data/spec/support/transactions.rb +1 -1
  179. data/spec/support/transactions/test.rb +1 -1
  180. data/spec/support/utils.rb +1 -16
  181. metadata +685 -659
  182. metadata.gz.sig +0 -0
  183. data/lib/mongo/event/description_changed.rb +0 -52
  184. data/spec/integration/bson_symbol_spec.rb +0 -34
  185. data/spec/integration/crud_spec.rb +0 -45
  186. data/spec/integration/get_more_spec.rb +0 -32
  187. data/spec/integration/grid_fs_bucket_spec.rb +0 -48
  188. data/spec/integration/retryable_errors_spec.rb +0 -265
  189. data/spec/integration/size_limit_spec.rb~12e1e9c4f... RUBY-2242 Fix zlib compression (#2021) +0 -98
  190. data/spec/mongo/cursor/builder/op_kill_cursors_spec.rb +0 -56
  191. data/spec/runners/sdam/verifier.rb +0 -88
@@ -1,6 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Mongo::Server do
4
+ fails_on_jruby
4
5
 
5
6
  declare_topology_double
6
7
 
@@ -28,16 +29,28 @@ describe Mongo::Server do
28
29
  server.pool
29
30
  end
30
31
 
31
- describe '#==' do
32
+ let(:server_options) do
33
+ {}
34
+ end
32
35
 
33
- let(:server) do
34
- described_class.new(address, cluster, monitoring, listeners, SpecConfig.instance.test_options)
36
+ let(:server) do
37
+ register_server(
38
+ described_class.new(address, cluster, monitoring, listeners,
39
+ SpecConfig.instance.test_options.merge(monitoring_io: false).merge(server_options))
40
+ )
41
+ end
42
+
43
+ shared_context 'with monitoring io' do
44
+ let(:server_options) do
45
+ {monitoring_io: true}
35
46
  end
36
47
 
37
- after do
38
- expect(server).to receive(:pool).and_return(pool)
39
- server.disconnect!
48
+ before do
49
+ allow(cluster).to receive(:heartbeat_interval).and_return(1000)
40
50
  end
51
+ end
52
+
53
+ describe '#==' do
41
54
 
42
55
  context 'when the other is not a server' do
43
56
 
@@ -55,7 +68,10 @@ describe Mongo::Server do
55
68
  context 'when the addresses match' do
56
69
 
57
70
  let(:other) do
58
- described_class.new(address, cluster, monitoring, listeners, SpecConfig.instance.test_options)
71
+ register_server(
72
+ described_class.new(address, cluster, monitoring, listeners,
73
+ SpecConfig.instance.test_options.merge(monitoring_io: false))
74
+ )
59
75
  end
60
76
 
61
77
  it 'returns true' do
@@ -70,7 +86,10 @@ describe Mongo::Server do
70
86
  end
71
87
 
72
88
  let(:other) do
73
- described_class.new(other_address, cluster, monitoring, listeners, SpecConfig.instance.test_options)
89
+ register_server(
90
+ described_class.new(other_address, cluster, monitoring, listeners,
91
+ SpecConfig.instance.test_options.merge(monitoring_io: false))
92
+ )
74
93
  end
75
94
 
76
95
  it 'returns false' do
@@ -82,37 +101,35 @@ describe Mongo::Server do
82
101
 
83
102
  describe '#disconnect!' do
84
103
 
85
- let(:server) do
86
- described_class.new(address, cluster, monitoring, listeners, SpecConfig.instance.test_options)
87
- end
104
+ context 'with monitoring io' do
105
+ include_context 'with monitoring io'
88
106
 
89
- it 'stops the monitor instance' do
90
- expect(server.instance_variable_get(:@monitor)).to receive(:stop!).and_return(true)
91
- expect(server).to receive(:pool).and_return(pool)
92
- server.disconnect!
107
+ it 'stops the monitor instance' do
108
+ expect(server.instance_variable_get(:@monitor)).to receive(:stop!).and_call_original
109
+ server.disconnect!
110
+ end
93
111
  end
94
112
 
95
113
  it 'disconnects the connection pool' do
96
114
  expect(server.pool).to receive(:disconnect!).once.and_call_original
97
115
  server.disconnect!
98
116
  end
117
+
118
+ context 'when server reconnects' do
119
+ it 'keeps the same pool' do
120
+ pool = server.pool
121
+ server.disconnect!
122
+ server.reconnect!
123
+ expect(server.pool).to eq(pool)
124
+ end
125
+ end
99
126
  end
100
127
 
101
128
  describe '#initialize' do
129
+ include_context 'with monitoring io'
102
130
 
103
- let(:server) do
104
- described_class.new(
105
- address,
106
- cluster,
107
- monitoring,
108
- listeners,
109
- SpecConfig.instance.test_options.merge(:heartbeat_frequency => 5)
110
- )
111
- end
112
-
113
- after do
114
- expect(server).to receive(:pool).and_return(pool)
115
- server.disconnect!
131
+ before do
132
+ allow(cluster).to receive(:run_sdam_flow)
116
133
  end
117
134
 
118
135
  it 'sets the address host' do
@@ -124,7 +141,7 @@ describe Mongo::Server do
124
141
  end
125
142
 
126
143
  it 'sets the options' do
127
- expect(server.options).to eq(SpecConfig.instance.test_options.merge(:heartbeat_frequency => 5))
144
+ expect(server.options[:monitoring_io]).to be true
128
145
  end
129
146
 
130
147
  it 'creates monitor with monitoring app metadata' do
@@ -132,53 +149,54 @@ describe Mongo::Server do
132
149
  end
133
150
 
134
151
  context 'monitoring_io: false' do
135
- let(:server) do
136
- described_class.new(
137
- address,
138
- cluster,
139
- monitoring,
140
- listeners,
141
- SpecConfig.instance.test_options.merge(monitoring_io: false)
142
- )
152
+
153
+ let(:server_options) do
154
+ {monitoring_io: false}
143
155
  end
144
156
 
145
157
  it 'does not create monitoring thread' do
146
158
  expect(server.monitor.instance_variable_get('@thread')).to be nil
147
159
  end
148
160
  end
161
+
162
+ context 'monitoring_io: true' do
163
+ include_context 'with monitoring io'
164
+
165
+ it 'creates monitoring thread' do
166
+ expect(server.monitor.instance_variable_get('@thread')).to be_a(Thread)
167
+ end
168
+ end
149
169
  end
150
170
 
151
171
  describe '#scan!' do
172
+ clean_slate
152
173
 
153
- let(:server) do
154
- described_class.new(address, cluster, monitoring, listeners, SpecConfig.instance.test_options)
174
+ include_context 'with monitoring io'
175
+
176
+ before do
177
+ # We are invoking scan! on the monitor manually, stop the background
178
+ # thread to avoid it interfering with our assertions.
179
+ server.monitor.stop!
155
180
  end
156
181
 
157
- after do
158
- expect(server).to receive(:pool).and_return(pool)
159
- server.disconnect!
182
+ it 'delegates scan to the monitor' do
183
+ expect(server.monitor).to receive(:scan!)
184
+ server.scan!
160
185
  end
161
186
 
162
- it 'forces a scan on the monitor' do
163
- expect(server.scan!).to eq(server.description)
187
+ it 'invokes sdam flow eventually' do
188
+ expect(cluster).to receive(:run_sdam_flow)
189
+ server.scan!
164
190
  end
165
191
  end
166
192
 
167
193
  describe '#reconnect!' do
168
-
169
- let(:server) do
170
- described_class.new(address, cluster, monitoring, listeners, SpecConfig.instance.test_options)
171
- end
194
+ include_context 'with monitoring io'
172
195
 
173
196
  before do
174
197
  expect(server.monitor).to receive(:restart!).and_call_original
175
198
  end
176
199
 
177
- after do
178
- expect(server).to receive(:pool).and_return(pool)
179
- server.disconnect!
180
- end
181
-
182
200
  it 'restarts the monitor and returns true' do
183
201
  expect(server.reconnect!).to be(true)
184
202
  end
@@ -186,10 +204,6 @@ describe Mongo::Server do
186
204
 
187
205
  describe 'retry_writes?' do
188
206
 
189
- let(:server) do
190
- described_class.new(address, cluster, monitoring, listeners, SpecConfig.instance.test_options)
191
- end
192
-
193
207
  before do
194
208
  allow(server).to receive(:features).and_return(features)
195
209
  end
@@ -363,9 +377,9 @@ describe Mongo::Server do
363
377
  end
364
378
 
365
379
  context 'server is unknown' do
366
- let(:server) do
367
- described_class.new(address, cluster, monitoring, listeners,
368
- SpecConfig.instance.test_options.merge(monitoring_io: false))
380
+
381
+ let(:server_options) do
382
+ {monitoring_io: false}
369
383
  end
370
384
 
371
385
  before do
@@ -395,4 +409,12 @@ describe Mongo::Server do
395
409
  end
396
410
  end
397
411
  end
412
+
413
+ describe '#log_warn' do
414
+ it 'works' do
415
+ expect do
416
+ server.log_warn('test warning')
417
+ end.not_to raise_error
418
+ end
419
+ end
398
420
  end
@@ -10,7 +10,7 @@ describe Mongo::Session::SessionPool do
10
10
  # Cluster time assertions can fail if there are background operations
11
11
  # that cause cluster time to be updated. This also necessitates clean
12
12
  # state requirement.
13
- authorized_client.close(true)
13
+ authorized_client.close
14
14
  end
15
15
  end
16
16
 
@@ -161,10 +161,6 @@ describe Mongo::Session::SessionPool do
161
161
  subscribed_client
162
162
  end
163
163
 
164
- after do
165
- client.close(true)
166
- end
167
-
168
164
  context 'when the number of ids is not larger than 10,000' do
169
165
 
170
166
  before do
@@ -231,10 +231,6 @@ describe Mongo::Session do
231
231
  authorized_client.with(retry_writes: false)
232
232
  end
233
233
 
234
- after do
235
- client.close(true)
236
- end
237
-
238
234
  it 'returns false' do
239
235
  expect(client.start_session.retry_writes?).to be(false)
240
236
  end
@@ -591,7 +591,7 @@ describe Mongo::Socket::SSL, retry: 3 do
591
591
  context 'bundled with intermediate cert' do
592
592
 
593
593
  # https://github.com/jruby/jruby-openssl/issues/181
594
- fails_on_jruby
594
+ only_mri
595
595
 
596
596
  let(:options) do
597
597
  SpecConfig.instance.test_options.merge(
@@ -636,7 +636,7 @@ describe Mongo::Socket::SSL, retry: 3 do
636
636
  context 'bundled with intermediate cert' do
637
637
 
638
638
  # https://github.com/jruby/jruby-openssl/issues/181
639
- fails_on_jruby
639
+ only_mri
640
640
 
641
641
  let(:options) do
642
642
  SpecConfig.instance.test_options.merge(
@@ -0,0 +1,211 @@
1
+ require 'lite_spec_helper'
2
+
3
+ describe Mongo::SRV::Monitor do
4
+ describe '#scan!' do
5
+ let(:hostname) do
6
+ 'test1.test.build.10gen.cc.'
7
+ end
8
+
9
+ let(:hosts) do
10
+ [
11
+ 'localhost.test.build.10gen.cc.:27017',
12
+ 'localhost.test.build.10gen.cc.:27018',
13
+ ]
14
+ end
15
+
16
+ let(:records) do
17
+ double('records').tap do |records|
18
+ allow(records).to receive(:hostname).and_return(hostname)
19
+ allow(records).to receive(:hosts).and_return(hosts)
20
+ allow(records).to receive(:empty?).and_return(false)
21
+ allow(records).to receive(:min_ttl).and_return(nil)
22
+ end
23
+ end
24
+
25
+
26
+ let(:cluster) do
27
+ Mongo::Cluster.new(records.hosts, Mongo::Monitoring.new, { monitoring_io: false })
28
+ end
29
+
30
+ let(:monitoring) do
31
+ described_class.new(cluster, resolver, records)
32
+ end
33
+
34
+ before do
35
+ monitoring.scan!
36
+ end
37
+
38
+ context 'when a new DNS record is added' do
39
+ let(:new_hosts) do
40
+ hosts + ['test1.test.build.10gen.cc.:27019']
41
+ end
42
+
43
+ let(:new_records) do
44
+ double('records').tap do |records|
45
+ allow(records).to receive(:hostname).and_return(hostname)
46
+ allow(records).to receive(:hosts).and_return(new_hosts)
47
+ allow(records).to receive(:empty?).and_return(false)
48
+ allow(records).to receive(:min_ttl).and_return(nil)
49
+ end
50
+ end
51
+
52
+ let(:resolver) do
53
+ double('resolver').tap do |resolver|
54
+ allow(resolver).to receive(:get_records).and_return(new_records)
55
+ end
56
+ end
57
+
58
+ it 'adds the new host to the cluster' do
59
+ expect(cluster.addresses.map(&:to_s).sort).to eq(new_hosts.sort)
60
+ end
61
+ end
62
+
63
+ context 'when a DNS record is removed' do
64
+ let(:new_hosts) do
65
+ hosts - ['test1.test.build.10gen.cc.:27018']
66
+ end
67
+
68
+ let(:new_records) do
69
+ double('records').tap do |records|
70
+ allow(records).to receive(:hostname).and_return(hostname)
71
+ allow(records).to receive(:hosts).and_return(new_hosts)
72
+ allow(records).to receive(:empty?).and_return(false)
73
+ allow(records).to receive(:min_ttl).and_return(nil)
74
+ end
75
+ end
76
+
77
+ let(:resolver) do
78
+ double('resolver').tap do |resolver|
79
+ allow(resolver).to receive(:get_records).and_return(new_records)
80
+ end
81
+ end
82
+
83
+ it 'adds the new host to the cluster' do
84
+ expect(cluster.addresses.map(&:to_s).sort).to eq(new_hosts.sort)
85
+ end
86
+ end
87
+
88
+ context 'when a single DNS record is replaced' do
89
+ let(:new_hosts) do
90
+ hosts - ['test1.test.build.10gen.cc.:27018'] + ['test1.test.build.10gen.cc.:27019']
91
+ end
92
+
93
+ let(:new_records) do
94
+ double('records').tap do |records|
95
+ allow(records).to receive(:hostname).and_return(hostname)
96
+ allow(records).to receive(:hosts).and_return(new_hosts)
97
+ allow(records).to receive(:empty?).and_return(false)
98
+ allow(records).to receive(:min_ttl).and_return(nil)
99
+ end
100
+ end
101
+
102
+ let(:resolver) do
103
+ double('resolver').tap do |resolver|
104
+ allow(resolver).to receive(:get_records).and_return(new_records)
105
+ end
106
+ end
107
+
108
+ it 'adds the new host to the cluster' do
109
+ expect(cluster.addresses.map(&:to_s).sort).to eq(new_hosts.sort)
110
+ end
111
+ end
112
+
113
+ context 'when all DNS records are replaced with a single record' do
114
+ let(:new_hosts) do
115
+ ['test1.test.build.10gen.cc.:27019']
116
+ end
117
+
118
+ let(:new_records) do
119
+ double('records').tap do |records|
120
+ allow(records).to receive(:hostname).and_return(hostname)
121
+ allow(records).to receive(:hosts).and_return(new_hosts)
122
+ allow(records).to receive(:empty?).and_return(false)
123
+ allow(records).to receive(:min_ttl).and_return(nil)
124
+ end
125
+ end
126
+
127
+ let(:resolver) do
128
+ double('resolver').tap do |resolver|
129
+ allow(resolver).to receive(:get_records).and_return(new_records)
130
+ end
131
+ end
132
+
133
+ it 'adds the new host to the cluster' do
134
+ expect(cluster.addresses.map(&:to_s).sort).to eq(new_hosts.sort)
135
+ end
136
+ end
137
+
138
+ context 'when all DNS records are replaced with multiple records' do
139
+ let(:new_hosts) do
140
+ [
141
+ 'test1.test.build.10gen.cc.:27019',
142
+ 'test1.test.build.10gen.cc.:27020',
143
+ ]
144
+ end
145
+
146
+ let(:new_records) do
147
+ double('records').tap do |records|
148
+ allow(records).to receive(:hostname).and_return(hostname)
149
+ allow(records).to receive(:hosts).and_return(new_hosts)
150
+ allow(records).to receive(:empty?).and_return(false)
151
+ allow(records).to receive(:min_ttl).and_return(nil)
152
+ end
153
+ end
154
+
155
+ let(:resolver) do
156
+ double('resolver').tap do |resolver|
157
+ allow(resolver).to receive(:get_records).and_return(new_records)
158
+ end
159
+ end
160
+
161
+ it 'adds the new host to the cluster' do
162
+ expect(cluster.addresses.map(&:to_s).sort).to eq(new_hosts.sort)
163
+ end
164
+ end
165
+
166
+ context 'when the DNS lookup times out' do
167
+ let(:resolver) do
168
+ double('resolver').tap do |resolver|
169
+ allow(resolver).to receive(:get_records).and_raise(Resolv::ResolvTimeout)
170
+ end
171
+ end
172
+
173
+ it 'does not add or remove any hosts from the cluster' do
174
+ expect(cluster.addresses.map(&:to_s).sort).to eq(hosts.sort)
175
+ end
176
+ end
177
+
178
+ context 'when the DNS lookup is unable to resolve the hostname' do
179
+ let(:resolver) do
180
+ double('resolver').tap do |resolver|
181
+ allow(resolver).to receive(:get_records).and_raise(Resolv::ResolvError)
182
+ end
183
+ end
184
+
185
+ it 'does not add or remove any hosts from the cluster' do
186
+ expect(cluster.addresses.map(&:to_s).sort).to eq(hosts.sort)
187
+ end
188
+ end
189
+
190
+ context 'when no DNS records are returned' do
191
+ let(:new_records) do
192
+ double('records').tap do |records|
193
+ allow(records).to receive(:hostname).and_return(hostname)
194
+ allow(records).to receive(:hosts).and_return([])
195
+ allow(records).to receive(:empty?).and_return(true)
196
+ allow(records).to receive(:min_ttl).and_return(nil)
197
+ end
198
+ end
199
+
200
+ let(:resolver) do
201
+ double('resolver').tap do |resolver|
202
+ allow(resolver).to receive(:get_records).and_return(new_records)
203
+ end
204
+ end
205
+
206
+ it 'does not add or remove any hosts from the cluster' do
207
+ expect(cluster.addresses.map(&:to_s).sort).to eq(hosts.sort)
208
+ end
209
+ end
210
+ end
211
+ end