PageRenderTime 54ms CodeModel.GetById 6ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/MongoDB.Driver.Core.Tests/Core/Servers/ServerTests.cs

http://github.com/mongodb/mongo-csharp-driver
C# | 622 lines | 525 code | 81 blank | 16 comment | 13 complexity | 51653a18bd92eb65b96efa5e66898ff2 MD5 | raw file
Possible License(s): Apache-2.0
  1. /* Copyright 2013-present 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.IO;
  17. using System.Net;
  18. using System.Net.Sockets;
  19. using System.Reflection;
  20. using System.Threading;
  21. using System.Threading.Tasks;
  22. using FluentAssertions;
  23. using MongoDB.Bson;
  24. using MongoDB.Bson.IO;
  25. using MongoDB.Bson.Serialization.Serializers;
  26. using MongoDB.Bson.TestHelpers.XunitExtensions;
  27. using MongoDB.Driver.Core.Bindings;
  28. using MongoDB.Driver.Core.Clusters;
  29. using MongoDB.Driver.Core.Clusters.ServerSelectors;
  30. using MongoDB.Driver.Core.Configuration;
  31. using MongoDB.Driver.Core.ConnectionPools;
  32. using MongoDB.Driver.Core.Connections;
  33. using MongoDB.Driver.Core.Events;
  34. using MongoDB.Driver.Core.TestHelpers.XunitExtensions;
  35. using MongoDB.Driver.Core.WireProtocol;
  36. using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
  37. using Moq;
  38. using Xunit;
  39. namespace MongoDB.Driver.Core.Servers
  40. {
  41. public class ServerTests
  42. {
  43. private IClusterClock _clusterClock;
  44. private ClusterId _clusterId;
  45. private ClusterConnectionMode _clusterConnectionMode;
  46. private Mock<IConnectionPool> _mockConnectionPool;
  47. private Mock<IConnectionPoolFactory> _mockConnectionPoolFactory;
  48. private EndPoint _endPoint;
  49. private EventCapturer _capturedEvents;
  50. private Mock<IServerMonitor> _mockServerMonitor;
  51. private Mock<IServerMonitorFactory> _mockServerMonitorFactory;
  52. private ServerSettings _settings;
  53. private Server _subject;
  54. public ServerTests()
  55. {
  56. _clusterId = new ClusterId();
  57. _endPoint = new DnsEndPoint("localhost", 27017);
  58. _clusterClock = new Mock<IClusterClock>().Object;
  59. _clusterConnectionMode = ClusterConnectionMode.Standalone;
  60. _mockConnectionPool = new Mock<IConnectionPool>();
  61. _mockConnectionPool.Setup(p => p.AcquireConnection(It.IsAny<CancellationToken>())).Returns(new Mock<IConnectionHandle>().Object);
  62. _mockConnectionPool.Setup(p => p.AcquireConnectionAsync(It.IsAny<CancellationToken>())).Returns(Task.FromResult(new Mock<IConnectionHandle>().Object));
  63. _mockConnectionPoolFactory = new Mock<IConnectionPoolFactory>();
  64. _mockConnectionPoolFactory
  65. .Setup(f => f.CreateConnectionPool(It.IsAny<ServerId>(), _endPoint))
  66. .Returns(_mockConnectionPool.Object);
  67. _mockServerMonitor = new Mock<IServerMonitor>();
  68. _mockServerMonitorFactory = new Mock<IServerMonitorFactory>();
  69. _mockServerMonitorFactory.Setup(f => f.Create(It.IsAny<ServerId>(), _endPoint)).Returns(_mockServerMonitor.Object);
  70. _capturedEvents = new EventCapturer();
  71. _settings = new ServerSettings(heartbeatInterval: Timeout.InfiniteTimeSpan);
  72. _subject = new Server(_clusterId, _clusterClock, _clusterConnectionMode, _settings, _endPoint, _mockConnectionPoolFactory.Object, _mockServerMonitorFactory.Object, _capturedEvents);
  73. }
  74. [Fact]
  75. public void Constructor_should_throw_when_settings_is_null()
  76. {
  77. Action act = () => new Server(_clusterId, _clusterClock, _clusterConnectionMode, null, _endPoint, _mockConnectionPoolFactory.Object, _mockServerMonitorFactory.Object, _capturedEvents);
  78. act.ShouldThrow<ArgumentNullException>();
  79. }
  80. [Fact]
  81. public void Constructor_should_throw_when_clusterId_is_null()
  82. {
  83. Action act = () => new Server(null, _clusterClock, _clusterConnectionMode, _settings, _endPoint, _mockConnectionPoolFactory.Object, _mockServerMonitorFactory.Object, _capturedEvents);
  84. act.ShouldThrow<ArgumentNullException>();
  85. }
  86. [Fact]
  87. public void Constructor_should_throw_when_clusterClock_is_null()
  88. {
  89. Action act = () => new Server(_clusterId, null, _clusterConnectionMode, _settings, _endPoint, _mockConnectionPoolFactory.Object, _mockServerMonitorFactory.Object, _capturedEvents);
  90. act.ShouldThrow<ArgumentNullException>();
  91. }
  92. [Fact]
  93. public void Constructor_should_throw_when_endPoint_is_null()
  94. {
  95. Action act = () => new Server(_clusterId, _clusterClock, _clusterConnectionMode, _settings, null, _mockConnectionPoolFactory.Object, _mockServerMonitorFactory.Object, _capturedEvents);
  96. act.ShouldThrow<ArgumentNullException>();
  97. }
  98. [Fact]
  99. public void Constructor_should_throw_when_connectionPoolFactory_is_null()
  100. {
  101. Action act = () => new Server(_clusterId, _clusterClock, _clusterConnectionMode, _settings, _endPoint, null, _mockServerMonitorFactory.Object, _capturedEvents);
  102. act.ShouldThrow<ArgumentNullException>();
  103. }
  104. [Fact]
  105. public void Constructor_should_throw_when_serverMonitorFactory_is_null()
  106. {
  107. Action act = () => new Server(_clusterId, _clusterClock, _clusterConnectionMode, _settings, _endPoint, _mockConnectionPoolFactory.Object, null, _capturedEvents);
  108. act.ShouldThrow<ArgumentNullException>();
  109. }
  110. [Fact]
  111. public void Constructor_should_throw_when_eventSubscriber_is_null()
  112. {
  113. Action act = () => new Server(_clusterId, _clusterClock, _clusterConnectionMode, _settings, _endPoint, _mockConnectionPoolFactory.Object, _mockServerMonitorFactory.Object, null);
  114. act.ShouldThrow<ArgumentNullException>();
  115. }
  116. [Fact]
  117. public void Dispose_should_dispose_the_server()
  118. {
  119. _subject.Initialize();
  120. _capturedEvents.Clear();
  121. _subject.Dispose();
  122. _mockConnectionPool.Verify(p => p.Dispose(), Times.Once);
  123. _mockServerMonitor.Verify(m => m.Dispose(), Times.Once);
  124. _capturedEvents.Next().Should().BeOfType<ServerClosingEvent>();
  125. _capturedEvents.Next().Should().BeOfType<ServerClosedEvent>();
  126. _capturedEvents.Any().Should().BeFalse();
  127. }
  128. [Theory]
  129. [ParameterAttributeData]
  130. public void GetChannel_should_clear_connection_pool_when_opening_connection_throws_MongoAuthenticationException(
  131. [Values(false, true)] bool async)
  132. {
  133. var connectionId = new ConnectionId(new ServerId(_clusterId, _endPoint));
  134. var mockConnectionHandle = new Mock<IConnectionHandle>();
  135. mockConnectionHandle
  136. .Setup(c => c.Open(It.IsAny<CancellationToken>()))
  137. .Throws(new MongoAuthenticationException(connectionId, "Invalid login."));
  138. mockConnectionHandle
  139. .Setup(c => c.OpenAsync(It.IsAny<CancellationToken>()))
  140. .Throws(new MongoAuthenticationException(connectionId, "Invalid login."));
  141. var mockConnectionPool = new Mock<IConnectionPool>();
  142. mockConnectionPool
  143. .Setup(p => p.AcquireConnection(It.IsAny<CancellationToken>()))
  144. .Returns(mockConnectionHandle.Object);
  145. mockConnectionPool
  146. .Setup(p => p.AcquireConnectionAsync(It.IsAny<CancellationToken>()))
  147. .Returns(Task.FromResult(mockConnectionHandle.Object));
  148. mockConnectionPool.Setup(p => p.Clear());
  149. var mockConnectionPoolFactory = new Mock<IConnectionPoolFactory>();
  150. mockConnectionPoolFactory
  151. .Setup(f => f.CreateConnectionPool(It.IsAny<ServerId>(), _endPoint))
  152. .Returns(mockConnectionPool.Object);
  153. var server = new Server(
  154. _clusterId,
  155. _clusterClock,
  156. _clusterConnectionMode,
  157. _settings,
  158. _endPoint,
  159. mockConnectionPoolFactory.Object,
  160. _mockServerMonitorFactory.Object,
  161. _capturedEvents);
  162. server.Initialize();
  163. var exception = Record.Exception(() =>
  164. {
  165. if (async)
  166. {
  167. server.GetChannelAsync(CancellationToken.None).GetAwaiter().GetResult();
  168. }
  169. else
  170. {
  171. server.GetChannel(CancellationToken.None);
  172. }
  173. });
  174. exception.Should().BeOfType<MongoAuthenticationException>();
  175. mockConnectionPool.Verify(p => p.Clear(), Times.Once());
  176. }
  177. [Theory]
  178. [ParameterAttributeData]
  179. public void GetChannel_should_throw_when_not_initialized(
  180. [Values(false, true)]
  181. bool async)
  182. {
  183. Action act;
  184. if (async)
  185. {
  186. act = () => _subject.GetChannelAsync(CancellationToken.None).GetAwaiter().GetResult();
  187. }
  188. else
  189. {
  190. act = () => _subject.GetChannel(CancellationToken.None);
  191. }
  192. act.ShouldThrow<InvalidOperationException>();
  193. }
  194. [Theory]
  195. [ParameterAttributeData]
  196. public void GetChannel_should_throw_when_disposed(
  197. [Values(false, true)]
  198. bool async)
  199. {
  200. _subject.Dispose();
  201. Action act;
  202. if (async)
  203. {
  204. act = () => _subject.GetChannelAsync(CancellationToken.None).GetAwaiter().GetResult();
  205. }
  206. else
  207. {
  208. act = () => _subject.GetChannel(CancellationToken.None);
  209. }
  210. act.ShouldThrow<ObjectDisposedException>();
  211. }
  212. [Theory]
  213. [ParameterAttributeData]
  214. public void GetChannel_should_get_a_connection(
  215. [Values(false, true)]
  216. bool async)
  217. {
  218. _subject.Initialize();
  219. IChannelHandle channel;
  220. if (async)
  221. {
  222. channel = _subject.GetChannelAsync(CancellationToken.None).GetAwaiter().GetResult();
  223. }
  224. else
  225. {
  226. channel = _subject.GetChannel(CancellationToken.None);
  227. }
  228. channel.Should().NotBeNull();
  229. }
  230. [Fact]
  231. public void Initialize_should_initialize_the_server()
  232. {
  233. _subject.Initialize();
  234. _mockConnectionPool.Verify(p => p.Initialize(), Times.Once);
  235. _mockServerMonitor.Verify(m => m.Initialize(), Times.Once);
  236. _capturedEvents.Next().Should().BeOfType<ServerOpeningEvent>();
  237. _capturedEvents.Next().Should().BeOfType<ServerOpenedEvent>();
  238. _capturedEvents.Any().Should().BeFalse();
  239. }
  240. [Fact]
  241. public void Invalidate_should_tell_the_monitor_to_invalidate_and_clear_the_connection_pool()
  242. {
  243. _subject.Initialize();
  244. _capturedEvents.Clear();
  245. _subject.Invalidate("Test");
  246. _mockConnectionPool.Verify(p => p.Clear(), Times.Once);
  247. _mockServerMonitor.Verify(m => m.Invalidate("Test"), Times.Once);
  248. }
  249. [Fact]
  250. public void RequestHeartbeat_should_tell_the_monitor_to_request_a_heartbeat()
  251. {
  252. _subject.Initialize();
  253. _capturedEvents.Clear();
  254. _subject.RequestHeartbeat();
  255. _mockServerMonitor.Verify(m => m.RequestHeartbeat(), Times.Once);
  256. _capturedEvents.Any().Should().BeFalse();
  257. }
  258. [Fact]
  259. public void A_description_changed_event_with_a_heartbeat_exception_should_clear_the_connection_pool()
  260. {
  261. _subject.Initialize();
  262. var description = new ServerDescription(_subject.ServerId, _subject.EndPoint)
  263. .With(heartbeatException: new Exception("ughhh"));
  264. _mockServerMonitor.Raise(m => m.DescriptionChanged += null, new ServerDescriptionChangedEventArgs(description, description));
  265. _mockConnectionPool.Verify(p => p.Clear(), Times.Once);
  266. }
  267. [Theory]
  268. [InlineData((ServerErrorCode)(-1), false)]
  269. [InlineData(ServerErrorCode.NotMaster, true)]
  270. [InlineData(ServerErrorCode.NotMasterNoSlaveOk, true)]
  271. [InlineData(ServerErrorCode.NotMasterOrSecondary, false)]
  272. internal void IsNotMaster_should_return_expected_result_for_code(ServerErrorCode code, bool expectedResult)
  273. {
  274. _subject.Initialize();
  275. var result = _subject.IsNotMaster(code, null);
  276. result.Should().Be(expectedResult);
  277. if (result)
  278. {
  279. _subject.IsRecovering(code, null).Should().BeFalse();
  280. }
  281. }
  282. [Theory]
  283. [InlineData(null, false)]
  284. [InlineData("abc", false)]
  285. [InlineData("not master", true)]
  286. [InlineData("not master or secondary", false)]
  287. internal void IsNotMaster_should_return_expected_result_for_message(string message, bool expectedResult)
  288. {
  289. _subject.Initialize();
  290. var result = _subject.IsNotMaster((ServerErrorCode)(-1), message);
  291. result.Should().Be(expectedResult);
  292. if (result)
  293. {
  294. _subject.IsRecovering((ServerErrorCode)(-1), message).Should().BeFalse();
  295. }
  296. }
  297. [Theory]
  298. [InlineData((ServerErrorCode)(-1), false)]
  299. [InlineData(ServerErrorCode.NotMaster, true)]
  300. [InlineData(ServerErrorCode.InterruptedAtShutdown, true)]
  301. internal void IsNotMasterOrRecovering_should_return_expected_result(ServerErrorCode code, bool expectedResult)
  302. {
  303. _subject.Initialize();
  304. var result = _subject.IsNotMasterOrRecovering(code, null);
  305. result.Should().Be(expectedResult);
  306. }
  307. [Theory]
  308. [InlineData((ServerErrorCode)(-1), false)]
  309. [InlineData(ServerErrorCode.InterruptedAtShutdown, true)]
  310. [InlineData(ServerErrorCode.InterruptedDueToReplStateChange, true)]
  311. [InlineData(ServerErrorCode.NotMasterOrSecondary, true)]
  312. [InlineData(ServerErrorCode.PrimarySteppedDown, true)]
  313. [InlineData(ServerErrorCode.ShutdownInProgress, true)]
  314. internal void IsRecovering_should_return_expected_result_for_code(ServerErrorCode code, bool expectedResult)
  315. {
  316. _subject.Initialize();
  317. var result = _subject.IsRecovering(code, null);
  318. result.Should().Be(expectedResult);
  319. if (result)
  320. {
  321. _subject.IsNotMaster(code, null).Should().BeFalse();
  322. }
  323. }
  324. [Theory]
  325. [InlineData(null, false)]
  326. [InlineData("abc", false)]
  327. [InlineData("node is recovering", true)]
  328. [InlineData("not master or secondary", true)]
  329. internal void IsRecovering_should_return_expected_result_for_message(string message, bool expectedResult)
  330. {
  331. _subject.Initialize();
  332. var result = _subject.IsRecovering((ServerErrorCode)(-1), message);
  333. result.Should().Be(expectedResult);
  334. if (result)
  335. {
  336. _subject.IsNotMaster((ServerErrorCode)(-1), message).Should().BeFalse();
  337. }
  338. }
  339. [Theory]
  340. [InlineData(nameof(EndOfStreamException), true)]
  341. [InlineData(nameof(Exception), false)]
  342. [InlineData(nameof(IOException), true)]
  343. [InlineData(nameof(MongoConnectionException), true)]
  344. [InlineData(nameof(MongoNodeIsRecoveringException), true)]
  345. [InlineData(nameof(MongoNotPrimaryException), true)]
  346. [InlineData(nameof(SocketException), true)]
  347. [InlineData(nameof(TimeoutException), false)]
  348. [InlineData(nameof(MongoExecutionTimeoutException), false)]
  349. internal void ShouldInvalidateServer_should_return_expected_result_for_exceptionType(string exceptionTypeName, bool expectedResult)
  350. {
  351. _subject.Initialize();
  352. Exception exception;
  353. var clusterId = new ClusterId(1);
  354. var serverId = new ServerId(clusterId, new DnsEndPoint("localhost", 27017));
  355. var connectionId = new ConnectionId(serverId);
  356. var command = new BsonDocument("command", 1);
  357. var commandResult = new BsonDocument("ok", 1);
  358. switch (exceptionTypeName)
  359. {
  360. case nameof(EndOfStreamException): exception = new EndOfStreamException(); break;
  361. case nameof(Exception): exception = new Exception(); break;
  362. case nameof(IOException): exception = new IOException(); break;
  363. case nameof(MongoConnectionException): exception = new MongoConnectionException(connectionId, "message"); break;
  364. case nameof(MongoNodeIsRecoveringException): exception = new MongoNodeIsRecoveringException(connectionId, command, commandResult); break;
  365. case nameof(MongoNotPrimaryException): exception = new MongoNotPrimaryException(connectionId, command, commandResult); break;
  366. case nameof(SocketException): exception = new SocketException(); break;
  367. case nameof(TimeoutException): exception = new TimeoutException(); break;
  368. case nameof(MongoExecutionTimeoutException): exception = new MongoExecutionTimeoutException(connectionId, "message"); break;
  369. default: throw new Exception($"Invalid exceptionTypeName: {exceptionTypeName}.");
  370. }
  371. var result = _subject.ShouldInvalidateServer(exception);
  372. result.Should().Be(expectedResult);
  373. }
  374. [Theory]
  375. [InlineData(null, null, false)]
  376. [InlineData((ServerErrorCode)(-1), null, false)]
  377. [InlineData(ServerErrorCode.NotMaster, null, true)]
  378. [InlineData(ServerErrorCode.InterruptedAtShutdown, null, true)]
  379. [InlineData(null, "abc", false)]
  380. [InlineData(null, "not master", true)]
  381. [InlineData(null, "not master or secondary", true)]
  382. [InlineData(null, "node is recovering", true)]
  383. internal void ShouldInvalidateServer_should_return_expected_result_for_MongoCommandException(ServerErrorCode? code, string message, bool expectedResult)
  384. {
  385. _subject.Initialize();
  386. var clusterId = new ClusterId(1);
  387. var serverId = new ServerId(clusterId, new DnsEndPoint("localhost", 27017));
  388. var connectionId = new ConnectionId(serverId);
  389. var command = new BsonDocument("command", 1);
  390. var commandResult = new BsonDocument
  391. {
  392. { "ok", 0 },
  393. { "code", () => (int)code.Value, code.HasValue },
  394. { "errmsg", message, message != null }
  395. };
  396. var exception = new MongoCommandException(connectionId, "message", command, commandResult);
  397. var result = _subject.ShouldInvalidateServer(exception);
  398. result.Should().Be(expectedResult);
  399. }
  400. [Theory]
  401. [InlineData(null, null, false)]
  402. [InlineData((ServerErrorCode)(-1), null, false)]
  403. [InlineData(ServerErrorCode.NotMaster, null, true)]
  404. [InlineData(ServerErrorCode.InterruptedAtShutdown, null, true)]
  405. [InlineData(null, "abc", false)]
  406. [InlineData(null, "not master", true)]
  407. [InlineData(null, "not master or secondary", true)]
  408. [InlineData(null, "node is recovering", true)]
  409. internal void ShouldInvalidateServer_should_return_expected_result_for_MongoWriteConcernException(ServerErrorCode? code, string message, bool expectedResult)
  410. {
  411. _subject.Initialize();
  412. var clusterId = new ClusterId(1);
  413. var serverId = new ServerId(clusterId, new DnsEndPoint("localhost", 27017));
  414. var connectionId = new ConnectionId(serverId);
  415. var command = new BsonDocument("command", 1);
  416. var commandResult = new BsonDocument
  417. {
  418. { "ok", 1 },
  419. { "writeConcernError", new BsonDocument
  420. {
  421. { "code", () => (int)code.Value, code.HasValue },
  422. { "errmsg", message, message != null }
  423. }
  424. }
  425. };
  426. var writeConcernResult = new WriteConcernResult(commandResult);
  427. var exception = new MongoWriteConcernException(connectionId, "message", writeConcernResult);
  428. var result = _subject.ShouldInvalidateServer(exception);
  429. result.Should().Be(expectedResult);
  430. }
  431. }
  432. public class ServerChannelTests
  433. {
  434. [SkippableTheory]
  435. [InlineData(1, 2, 2)]
  436. [InlineData(2, 1, 2)]
  437. public void Command_should_send_the_greater_of_the_session_and_cluster_cluster_times(long sessionTimestamp, long clusterTimestamp, long expectedTimestamp)
  438. {
  439. RequireServer.Check().VersionGreaterThanOrEqualTo("3.6").ClusterTypes(ClusterType.ReplicaSet, ClusterType.Sharded);
  440. var sessionClusterTime = new BsonDocument("clusterTime", new BsonTimestamp(sessionTimestamp));
  441. var clusterClusterTime = new BsonDocument("clusterTime", new BsonTimestamp(clusterTimestamp));
  442. var expectedClusterTime = new BsonDocument("clusterTime", new BsonTimestamp(expectedTimestamp));
  443. var eventCapturer = new EventCapturer().Capture<CommandStartedEvent>(e => e.CommandName == "ping");
  444. using (var cluster = CoreTestConfiguration.CreateCluster(b => b.Subscribe(eventCapturer)))
  445. using (var session = cluster.StartSession())
  446. {
  447. var cancellationToken = CancellationToken.None;
  448. var server = (Server)cluster.SelectServer(WritableServerSelector.Instance, cancellationToken);
  449. using (var channel = server.GetChannel(cancellationToken))
  450. {
  451. session.AdvanceClusterTime(sessionClusterTime);
  452. server.ClusterClock.AdvanceClusterTime(clusterClusterTime);
  453. var command = BsonDocument.Parse("{ ping : 1 }");
  454. try
  455. {
  456. channel.Command<BsonDocument>(
  457. session,
  458. ReadPreference.Primary,
  459. DatabaseNamespace.Admin,
  460. command,
  461. null, // payloads
  462. NoOpElementNameValidator.Instance,
  463. null, // additionalOptions
  464. null, // postWriteAction
  465. CommandResponseHandling.Return,
  466. BsonDocumentSerializer.Instance,
  467. new MessageEncoderSettings(),
  468. cancellationToken);
  469. }
  470. catch (MongoCommandException ex)
  471. {
  472. // we're expecting the command to fail because the $clusterTime we sent is not properly signed
  473. // the point of this test is just to assert that the driver sent the higher of the session and cluster clusterTimes
  474. ex.Message.Should().Contain("Missing expected field \"signature\"");
  475. }
  476. }
  477. }
  478. var commandStartedEvent = eventCapturer.Next().Should().BeOfType<CommandStartedEvent>().Subject;
  479. var actualCommand = commandStartedEvent.Command;
  480. var actualClusterTime = actualCommand["$clusterTime"].AsBsonDocument;
  481. actualClusterTime.Should().Be(expectedClusterTime);
  482. }
  483. [SkippableFact]
  484. public void Command_should_update_the_session_and_cluster_cluster_times()
  485. {
  486. RequireServer.Check().VersionGreaterThanOrEqualTo("3.6").ClusterTypes(ClusterType.ReplicaSet, ClusterType.Sharded);
  487. var eventCapturer = new EventCapturer().Capture<CommandSucceededEvent>(e => e.CommandName == "ping");
  488. using (var cluster = CoreTestConfiguration.CreateCluster(b => b.Subscribe(eventCapturer)))
  489. using (var session = cluster.StartSession())
  490. {
  491. var cancellationToken = CancellationToken.None;
  492. var server = (Server)cluster.SelectServer(WritableServerSelector.Instance, cancellationToken);
  493. using (var channel = server.GetChannel(cancellationToken))
  494. {
  495. var command = BsonDocument.Parse("{ ping : 1 }");
  496. channel.Command<BsonDocument>(
  497. session,
  498. ReadPreference.Primary,
  499. DatabaseNamespace.Admin,
  500. command,
  501. null, // payloads
  502. NoOpElementNameValidator.Instance,
  503. null, // additionalOptions
  504. null, // postWriteAction
  505. CommandResponseHandling.Return,
  506. BsonDocumentSerializer.Instance,
  507. new MessageEncoderSettings(),
  508. cancellationToken);
  509. }
  510. var commandSucceededEvent = eventCapturer.Next().Should().BeOfType<CommandSucceededEvent>().Subject;
  511. var actualReply = commandSucceededEvent.Reply;
  512. var actualClusterTime = actualReply["$clusterTime"].AsBsonDocument;
  513. session.ClusterTime.Should().Be(actualClusterTime);
  514. server.ClusterClock.ClusterTime.Should().Be(actualClusterTime);
  515. }
  516. }
  517. }
  518. internal static class ServerReflector
  519. {
  520. public static bool IsNotMaster(this Server server, ServerErrorCode code, string message)
  521. {
  522. var methodInfo = typeof(Server).GetMethod(nameof(IsNotMaster), BindingFlags.NonPublic | BindingFlags.Instance);
  523. return (bool)methodInfo.Invoke(server, new object[] { code, message });
  524. }
  525. public static bool IsNotMasterOrRecovering(this Server server, ServerErrorCode code, string message)
  526. {
  527. var methodInfo = typeof(Server).GetMethod(nameof(IsNotMasterOrRecovering), BindingFlags.NonPublic | BindingFlags.Instance);
  528. return (bool)methodInfo.Invoke(server, new object[] { code, message });
  529. }
  530. public static bool IsRecovering(this Server server, ServerErrorCode code, string message)
  531. {
  532. var methodInfo = typeof(Server).GetMethod(nameof(IsRecovering), BindingFlags.NonPublic | BindingFlags.Instance);
  533. return (bool)methodInfo.Invoke(server, new object[] { code, message });
  534. }
  535. public static bool ShouldInvalidateServer(this Server server, Exception exception)
  536. {
  537. var methodInfo = typeof(Server).GetMethod(nameof(ShouldInvalidateServer), BindingFlags.NonPublic | BindingFlags.Instance);
  538. return (bool)methodInfo.Invoke(server, new object[] { exception });
  539. }
  540. }
  541. }