PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/src/MongoDB.Driver.Core.Tests/Core/Clusters/MultiServerClusterTests.cs

http://github.com/mongodb/mongo-csharp-driver
C# | 422 lines | 321 code | 87 blank | 14 comment | 0 complexity | 11e20dd893b19c6f94578a32c34326ee MD5 | raw file
Possible License(s): Apache-2.0
  1. /* Copyright 2013-2014 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. using System;
  16. using System.Collections.Generic;
  17. using System.Linq;
  18. using System.Net;
  19. using System.Threading;
  20. using FluentAssertions;
  21. using MongoDB.Driver.Core.Clusters;
  22. using MongoDB.Driver.Core.Configuration;
  23. using MongoDB.Driver.Core.Events;
  24. using MongoDB.Driver.Core.Misc;
  25. using MongoDB.Driver.Core.Servers;
  26. using MongoDB.Driver.Core.Helpers;
  27. using NSubstitute;
  28. using NUnit.Framework;
  29. namespace MongoDB.Driver.Core.Clusters
  30. {
  31. [TestFixture]
  32. public class MultiServerClusterTests
  33. {
  34. private IClusterListener _clusterListener;
  35. private MockClusterableServerFactory _serverFactory;
  36. private ClusterSettings _settings;
  37. private EndPoint _firstEndPoint = new DnsEndPoint("localhost", 27017);
  38. private EndPoint _secondEndPoint = new DnsEndPoint("localhost", 27018);
  39. private EndPoint _thirdEndPoint = new DnsEndPoint("localhost", 27019);
  40. [SetUp]
  41. public void Setup()
  42. {
  43. _settings = new ClusterSettings();
  44. _serverFactory = new MockClusterableServerFactory();
  45. _clusterListener = Substitute.For<IClusterListener>();
  46. }
  47. [Test]
  48. public void Constructor_should_throw_if_no_endpoints_are_specified()
  49. {
  50. var settings = new ClusterSettings(endPoints: new EndPoint[0]);
  51. Action act = () => new MultiServerCluster(settings, _serverFactory, _clusterListener);
  52. act.ShouldThrow<ArgumentOutOfRangeException>();
  53. }
  54. [Test]
  55. [TestCase(ClusterConnectionMode.Direct)]
  56. [TestCase(ClusterConnectionMode.Standalone)]
  57. public void Constructor_should_throw_if_cluster_connection_mode_is_not_supported(ClusterConnectionMode mode)
  58. {
  59. var settings = new ClusterSettings(
  60. endPoints: new[] { new DnsEndPoint("localhost", 27017) },
  61. connectionMode: mode);
  62. Action act = () => new MultiServerCluster(settings, _serverFactory, _clusterListener);
  63. act.ShouldThrow<ArgumentException>();
  64. }
  65. [Test]
  66. public void Description_should_be_correct_after_initialization()
  67. {
  68. _settings = _settings.With(endPoints: new [] { _firstEndPoint });
  69. var subject = CreateSubject();
  70. subject.Initialize();
  71. var description = subject.Description;
  72. description.State.Should().Be(ClusterState.Disconnected);
  73. description.Type.Should().Be(ClusterType.Unknown);
  74. description.Servers.Should().BeEquivalentTo(GetDescriptions(_firstEndPoint));
  75. }
  76. [Test]
  77. public void Initialize_should_throw_when_already_disposed()
  78. {
  79. _settings = _settings.With(endPoints: new [] { _firstEndPoint });
  80. var subject = CreateSubject();
  81. subject.Dispose();
  82. Action act = () => subject.Initialize();
  83. act.ShouldThrow<ObjectDisposedException>();
  84. }
  85. [Test]
  86. public void Should_discover_all_servers_in_the_cluster_reported_by_the_primary()
  87. {
  88. _settings = _settings.With(endPoints: new[] { _firstEndPoint });
  89. var subject = CreateSubject();
  90. subject.Initialize();
  91. PublishDescription(_firstEndPoint, ServerType.ReplicaSetPrimary);
  92. var description = subject.Description;
  93. description.State.Should().Be(ClusterState.Connected);
  94. description.Type.Should().Be(ClusterType.ReplicaSet);
  95. description.Servers.Should().BeEquivalentTo(GetDescriptions(_firstEndPoint, _secondEndPoint, _thirdEndPoint));
  96. }
  97. [Test]
  98. public void Should_discover_all_servers_in_the_cluster_when_notified_by_a_secondary()
  99. {
  100. _settings = _settings.With(endPoints: new[] { _firstEndPoint });
  101. var subject = CreateSubject();
  102. subject.Initialize();
  103. PublishDescription(_firstEndPoint, ServerType.ReplicaSetSecondary);
  104. var description = subject.Description;
  105. description.State.Should().Be(ClusterState.Connected);
  106. description.Type.Should().Be(ClusterType.ReplicaSet);
  107. description.Servers.Should().BeEquivalentTo(GetDescriptions(_firstEndPoint, _secondEndPoint, _thirdEndPoint));
  108. }
  109. [Test]
  110. public void Should_remove_a_server_that_is_no_longer_in_the_primary_host_list()
  111. {
  112. _settings = _settings.With(endPoints: new[] { _firstEndPoint, _secondEndPoint, _thirdEndPoint });
  113. var subject = CreateSubject();
  114. subject.Initialize();
  115. PublishDescription(_firstEndPoint, ServerType.ReplicaSetPrimary,
  116. hosts: new [] { _firstEndPoint, _secondEndPoint });
  117. var description = subject.Description;
  118. description.State.Should().Be(ClusterState.Connected);
  119. description.Type.Should().Be(ClusterType.ReplicaSet);
  120. description.Servers.Should().BeEquivalentTo(GetDescriptions(_firstEndPoint, _secondEndPoint));
  121. }
  122. [Test]
  123. public void Should_not_remove_a_server_that_is_no_longer_in_a_secondaries_host_list()
  124. {
  125. _settings = _settings.With(endPoints: new[] { _firstEndPoint, _secondEndPoint, _thirdEndPoint });
  126. var subject = CreateSubject();
  127. subject.Initialize();
  128. PublishDescription(_firstEndPoint, ServerType.ReplicaSetSecondary,
  129. hosts: new[] { _firstEndPoint, _secondEndPoint });
  130. var description = subject.Description;
  131. description.State.Should().Be(ClusterState.Connected);
  132. description.Type.Should().Be(ClusterType.ReplicaSet);
  133. description.Servers.Should().BeEquivalentTo(GetDescriptions(_firstEndPoint, _secondEndPoint, _thirdEndPoint));
  134. }
  135. [Test]
  136. public void Should_not_remove_a_server_that_is_disconnected()
  137. {
  138. _settings = _settings.With(endPoints: new[] { _firstEndPoint, _secondEndPoint, _thirdEndPoint });
  139. var subject = CreateSubject();
  140. subject.Initialize();
  141. PublishDescription(_firstEndPoint, ServerType.ReplicaSetPrimary);
  142. PublishDisconnectedDescription(_secondEndPoint);
  143. var description = subject.Description;
  144. description.State.Should().Be(ClusterState.Connected);
  145. description.Type.Should().Be(ClusterType.ReplicaSet);
  146. description.Servers.Should().BeEquivalentTo(GetDescriptions(_firstEndPoint, _secondEndPoint, _thirdEndPoint));
  147. }
  148. [Test]
  149. public void Should_not_add_a_new_server_from_a_secondary_when_a_primary_exists()
  150. {
  151. _settings = _settings.With(endPoints: new[] { _firstEndPoint, _secondEndPoint });
  152. var subject = CreateSubject();
  153. subject.Initialize();
  154. PublishDescription(_firstEndPoint, ServerType.ReplicaSetPrimary,
  155. hosts: new[] { _firstEndPoint, _secondEndPoint });
  156. PublishDescription(_secondEndPoint, ServerType.ReplicaSetSecondary,
  157. hosts: new[] { _firstEndPoint, _secondEndPoint, _thirdEndPoint });
  158. var description = subject.Description;
  159. description.State.Should().Be(ClusterState.Connected);
  160. description.Type.Should().Be(ClusterType.ReplicaSet);
  161. description.Servers.Should().BeEquivalentTo(GetDescriptions(_firstEndPoint, _secondEndPoint));
  162. }
  163. [Test]
  164. [TestCase(ClusterConnectionMode.ReplicaSet, ServerType.ShardRouter)]
  165. [TestCase(ClusterConnectionMode.ReplicaSet, ServerType.Standalone)]
  166. [TestCase(ClusterConnectionMode.Sharded, ServerType.ReplicaSetArbiter)]
  167. [TestCase(ClusterConnectionMode.Sharded, ServerType.ReplicaSetGhost)]
  168. [TestCase(ClusterConnectionMode.Sharded, ServerType.ReplicaSetOther)]
  169. [TestCase(ClusterConnectionMode.Sharded, ServerType.ReplicaSetPassive)]
  170. [TestCase(ClusterConnectionMode.Sharded, ServerType.ReplicaSetPrimary)]
  171. [TestCase(ClusterConnectionMode.Sharded, ServerType.ReplicaSetSecondary)]
  172. [TestCase(ClusterConnectionMode.Sharded, ServerType.Standalone)]
  173. public void Should_remove_server_of_the_wrong_type(ClusterConnectionMode connectionMode, ServerType wrongType)
  174. {
  175. _settings = _settings.With(
  176. endPoints: new[] { _firstEndPoint, _secondEndPoint, _thirdEndPoint },
  177. connectionMode: connectionMode);
  178. var subject = CreateSubject();
  179. subject.Initialize();
  180. PublishDescription(_secondEndPoint, wrongType);
  181. var description = subject.Description;
  182. description.Servers.Should().BeEquivalentTo(GetDescriptions(_firstEndPoint, _thirdEndPoint));
  183. }
  184. [TestCase(ServerType.ShardRouter)]
  185. [TestCase(ServerType.Standalone)]
  186. public void Should_remove_a_discovered_server_of_the_wrong_type(ServerType wrongType)
  187. {
  188. _settings = _settings.With(endPoints: new[] { _firstEndPoint });
  189. var subject = CreateSubject();
  190. subject.Initialize();
  191. PublishDescription(_firstEndPoint, ServerType.ReplicaSetPrimary);
  192. PublishDescription(_secondEndPoint, wrongType);
  193. var description = subject.Description;
  194. description.Servers.Should().BeEquivalentTo(GetDescriptions(_firstEndPoint, _thirdEndPoint));
  195. }
  196. [Test]
  197. public void Should_ignore_changes_from_a_ReplicaSetGhost()
  198. {
  199. _settings = _settings.With(endPoints: new[] { _firstEndPoint });
  200. var subject = CreateSubject();
  201. subject.Initialize();
  202. PublishDescription(_firstEndPoint, ServerType.ReplicaSetGhost,
  203. hosts: new [] { _firstEndPoint, _secondEndPoint, _thirdEndPoint });
  204. var description = subject.Description;
  205. description.Servers.Should().BeEquivalentTo(GetDescriptions(_firstEndPoint));
  206. }
  207. [Test]
  208. public void Should_remove_a_server_reporting_the_wrong_set_name()
  209. {
  210. _settings = _settings.With(
  211. endPoints: new[] { _firstEndPoint, _secondEndPoint },
  212. replicaSetName: "test");
  213. var subject = CreateSubject();
  214. subject.Initialize();
  215. PublishDescription(_firstEndPoint, ServerType.ReplicaSetSecondary,
  216. hosts: new[] { _firstEndPoint, _secondEndPoint, _thirdEndPoint },
  217. setName: "funny");
  218. var description = subject.Description;
  219. description.Servers.Should().BeEquivalentTo(GetDescriptions(_secondEndPoint));
  220. }
  221. [Test]
  222. public void Should_remove_server_from_the_seed_list_that_is_not_in_the_hosts_lists()
  223. {
  224. var alternateEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 27017);
  225. _settings = _settings.With(endPoints: new[] { alternateEndPoint });
  226. var subject = CreateSubject();
  227. subject.Initialize();
  228. PublishDescription(alternateEndPoint, ServerType.ReplicaSetPrimary);
  229. var description = subject.Description;
  230. description.Servers.Should().BeEquivalentTo(GetDescriptions(_firstEndPoint, _secondEndPoint, _thirdEndPoint));
  231. }
  232. [Test]
  233. public void Should_invalidate_existing_primary_when_a_new_primary_shows_up()
  234. {
  235. _settings = _settings.With(endPoints: new[] { _firstEndPoint, _secondEndPoint, _thirdEndPoint });
  236. var subject = CreateSubject();
  237. subject.Initialize();
  238. PublishDescription(_firstEndPoint, ServerType.ReplicaSetPrimary);
  239. PublishDescription(_secondEndPoint, ServerType.ReplicaSetPrimary);
  240. var description = subject.Description;
  241. description.Servers.Should().BeEquivalentTo(
  242. new[] { GetDisconnectedDescription(_firstEndPoint) }
  243. .Concat(GetDescriptions(_secondEndPoint, _thirdEndPoint)));
  244. }
  245. [Test]
  246. public void Should_ignore_a_notification_from_a_server_which_has_been_removed()
  247. {
  248. _settings = _settings.With(endPoints: new[] { _firstEndPoint, _secondEndPoint, _thirdEndPoint });
  249. var subject = CreateSubject();
  250. subject.Initialize();
  251. PublishDescription(_firstEndPoint, ServerType.ReplicaSetPrimary,
  252. hosts: new [] { _firstEndPoint, _secondEndPoint });
  253. PublishDescription(_thirdEndPoint, ServerType.ReplicaSetPrimary);
  254. var description = subject.Description;
  255. description.State.Should().Be(ClusterState.Connected);
  256. description.Type.Should().Be(ClusterType.ReplicaSet);
  257. description.Servers.Should().BeEquivalentTo(GetDescriptions(_firstEndPoint, _secondEndPoint));
  258. }
  259. [Test]
  260. public void Should_call_initialize_on_all_servers()
  261. {
  262. _settings = _settings.With(endPoints: new[] { _firstEndPoint, _secondEndPoint });
  263. var subject = CreateSubject();
  264. subject.Initialize();
  265. PublishDescription(_firstEndPoint, ServerType.ReplicaSetPrimary,
  266. hosts: new[] { _firstEndPoint, _secondEndPoint, _thirdEndPoint });
  267. foreach(var endPoint in new [] { _firstEndPoint, _secondEndPoint, _thirdEndPoint })
  268. {
  269. var server = _serverFactory.GetServer(endPoint);
  270. server.Received().Initialize();
  271. }
  272. }
  273. [Test]
  274. public void Should_call_dispose_on_servers_when_they_are_removed()
  275. {
  276. _settings = _settings.With(endPoints: new[] { _firstEndPoint, _secondEndPoint, _thirdEndPoint });
  277. var subject = CreateSubject();
  278. subject.Initialize();
  279. PublishDescription(_firstEndPoint, ServerType.ReplicaSetPrimary,
  280. hosts: new[] { _firstEndPoint, _secondEndPoint });
  281. var server = _serverFactory.GetServer(_thirdEndPoint);
  282. server.Received().Dispose();
  283. }
  284. [Test]
  285. public void Should_call_dispose_on_servers_when_the_cluster_is_disposed()
  286. {
  287. _settings = _settings.With(endPoints: new[] { _firstEndPoint, _secondEndPoint, _thirdEndPoint });
  288. var subject = CreateSubject();
  289. subject.Initialize();
  290. subject.Dispose();
  291. foreach (var endPoint in new[] { _firstEndPoint, _secondEndPoint, _thirdEndPoint })
  292. {
  293. var server = _serverFactory.GetServer(endPoint);
  294. server.Received().Dispose();
  295. }
  296. }
  297. private MultiServerCluster CreateSubject()
  298. {
  299. return new MultiServerCluster(_settings, _serverFactory, _clusterListener);
  300. }
  301. private IEnumerable<ServerDescription> GetDescriptions(params EndPoint[] endPoints)
  302. {
  303. return endPoints.Select(x => _serverFactory.GetServerDescription(x));
  304. }
  305. private ServerDescription GetDisconnectedDescription(EndPoint endPoint)
  306. {
  307. var desc = _serverFactory.GetServerDescription(endPoint);
  308. return new ServerDescription(desc.ServerId, endPoint);
  309. }
  310. private void PublishDisconnectedDescription(EndPoint endPoint)
  311. {
  312. var current = _serverFactory.GetServerDescription(endPoint);
  313. var description = new ServerDescription(current.ServerId, endPoint);
  314. _serverFactory.PublishDescription(description);
  315. }
  316. private void PublishDescription(EndPoint endPoint, ServerType serverType, IEnumerable<EndPoint> hosts = null, string setName = null, EndPoint primary = null)
  317. {
  318. var current = _serverFactory.GetServerDescription(endPoint);
  319. var config = new ReplicaSetConfig(
  320. hosts ?? new[] { _firstEndPoint, _secondEndPoint, _thirdEndPoint },
  321. setName ?? "test",
  322. primary,
  323. null);
  324. var description = current.With(
  325. averageRoundTripTime: TimeSpan.FromMilliseconds(10),
  326. replicaSetConfig: serverType.IsReplicaSetMember() ? config : null,
  327. state: ServerState.Connected,
  328. tags: null,
  329. type: serverType,
  330. version: new SemanticVersion(2, 6, 3),
  331. wireVersionRange: new Range<int>(0, int.MaxValue));
  332. _serverFactory.PublishDescription(description);
  333. }
  334. }
  335. }