private WriteConcernResult ProcessReply(ConnectionId connectionId, BsonDocument getLastErrorCommand, ReplyMessage <BsonDocument> reply) { if (reply.NumberReturned == 0) { throw new MongoCommandException(connectionId, "GetLastError reply had no documents.", getLastErrorCommand); } if (reply.NumberReturned > 1) { throw new MongoCommandException(connectionId, "GetLastError reply had more than one document.", getLastErrorCommand); } if (reply.QueryFailure) { throw new MongoCommandException(connectionId, "GetLastError reply had QueryFailure flag set.", getLastErrorCommand, reply.QueryFailureDocument); } var response = reply.Documents.Single(); var notPrimaryOrNodeIsRecoveringException = ExceptionMapper.MapNotPrimaryOrNodeIsRecovering(connectionId, response, "err"); if (notPrimaryOrNodeIsRecoveringException != null) { throw notPrimaryOrNodeIsRecoveringException; } var writeConcernResult = new WriteConcernResult(response); var mappedException = ExceptionMapper.Map(connectionId, writeConcernResult); if (mappedException != null) { throw mappedException; } return(writeConcernResult); }
internal void IsStateChangeException_should_return_expected_result(ServerErrorCode?code, bool expectedResult) { _subject.Initialize(); var mappedException = ExceptionMapper.MapNotPrimaryOrNodeIsRecovering(_connectionId, new BsonDocument(), new BsonDocument("code", code), "dummy"); var result = _subject.IsStateChangeException(mappedException); result.Should().Be(expectedResult); }
internal void IsRecovering_should_return_expected_result_for_code_with_conflicting_message() { var code = (ServerErrorCode)1; var message = "not master or secondary"; var commandResult = new BsonDocument { { "ok", 0 }, { "code", code }, // code takes precedence over errmsg { "errmsg", message } }; var exception = ExceptionMapper.MapNotPrimaryOrNodeIsRecovering(_connectionId, new BsonDocument(), commandResult, "errmsg"); exception.Should().BeNull(); }
internal void IsNotWritablePrimary_should_return_expected_result_for_code_with_conflicting_message() { var code = (ServerErrorCode)1; var message = OppressiveLanguageConstants.LegacyNotPrimaryErrorMessage; var commandResult = new BsonDocument { { "ok", 0 }, { "code", code }, // code takes precedence over errmsg { "errmsg", message } }; var exception = ExceptionMapper.MapNotPrimaryOrNodeIsRecovering(_connectionId, new BsonDocument(), commandResult, "errmsg"); exception.Should().BeNull(); }
internal void IsRecovering_should_return_expected_result_for_message(string message, bool expectedResult) { var commandResult = new BsonDocument { { "ok", 0 }, { "errmsg", message, message != null } }; var exception = ExceptionMapper.MapNotPrimaryOrNodeIsRecovering(_connectionId, new BsonDocument(), commandResult, "errmsg"); if (expectedResult) { exception.Should().BeOfType <MongoNodeIsRecoveringException>(); } else { exception.Should().BeNull(); } }
internal void IsNotWritablePrimary_should_return_expected_result_for_code(ServerErrorCode?code, bool expectedResult, Type expectedExceptionType) { var commandResult = new BsonDocument { { "ok", 0 }, { "code", code, code != null } }; var exception = ExceptionMapper.MapNotPrimaryOrNodeIsRecovering(_connectionId, new BsonDocument(), commandResult, "errmsg"); if (expectedExceptionType != null) { exception.Should().BeOfType(expectedExceptionType); } else { exception.Should().BeNull(); } }
internal void ShouldInvalidateServer_should_return_expected_result_for_MongoCommandException(ServerErrorCode?code, string message, bool expectedResult) { _subject.Initialize(); var clusterId = new ClusterId(1); var serverId = new ServerId(clusterId, new DnsEndPoint("localhost", 27017)); var connectionId = new ConnectionId(serverId); var command = new BsonDocument("command", 1); var commandResult = new BsonDocument { { "ok", 0 }, { "code", () => (int)code.Value, code.HasValue }, { "errmsg", message, message != null } }; var exception = ExceptionMapper.MapNotPrimaryOrNodeIsRecovering(connectionId, command, commandResult, "errmsg") ?? new MongoCommandException(connectionId, "message", command, commandResult); // this needs for cases when we have just a random exception var result = _subject.ShouldInvalidateServer(Mock.Of <IConnection>(), exception, new ServerDescription(_subject.ServerId, _subject.EndPoint), out _); result.Should().Be(expectedResult); }
private CursorBatch <TDocument> ProcessReply(ConnectionId connectionId, ReplyMessage <TDocument> reply) { if (reply.QueryFailure) { var response = reply.QueryFailureDocument; var notPrimaryOrNodeIsRecoveringException = ExceptionMapper.MapNotPrimaryOrNodeIsRecovering(connectionId, response, "$err"); if (notPrimaryOrNodeIsRecoveringException != null) { throw notPrimaryOrNodeIsRecoveringException; } var mappedException = ExceptionMapper.Map(connectionId, response); if (mappedException != null) { throw mappedException; } var message = string.Format("QueryFailure flag was true (response was {0}).", response.ToJson()); throw new MongoQueryException(connectionId, message, _query, response); } return(new CursorBatch <TDocument>(reply.CursorId, reply.Documents)); }
private TCommandResult ProcessReply(ConnectionId connectionId, ReplyMessage <RawBsonDocument> reply) { if (reply.NumberReturned == 0) { throw new MongoCommandException(connectionId, "Command returned no documents.", _command); } if (reply.NumberReturned > 1) { throw new MongoCommandException(connectionId, "Command returned multiple documents.", _command); } if (reply.QueryFailure) { var failureDocument = reply.QueryFailureDocument; throw ExceptionMapper.Map(connectionId, failureDocument) ?? new MongoCommandException(connectionId, "Command failed.", _command, failureDocument); } using (var rawDocument = reply.Documents[0]) { if (!rawDocument.GetValue("ok", false).ToBoolean()) { var binaryReaderSettings = new BsonBinaryReaderSettings(); if (_messageEncoderSettings != null) { binaryReaderSettings.Encoding = _messageEncoderSettings.GetOrDefault <UTF8Encoding>(MessageEncoderSettingsName.ReadEncoding, Utf8Encodings.Strict); binaryReaderSettings.GuidRepresentation = _messageEncoderSettings.GetOrDefault <GuidRepresentation>(MessageEncoderSettingsName.GuidRepresentation, GuidRepresentation.CSharpLegacy); } ; var materializedDocument = rawDocument.Materialize(binaryReaderSettings); var commandName = _command.GetElement(0).Name; if (commandName == "$query") { commandName = _command["$query"].AsBsonDocument.GetElement(0).Name; } var notPrimaryOrNodeIsRecoveringException = ExceptionMapper.MapNotPrimaryOrNodeIsRecovering(connectionId, materializedDocument, "errmsg"); if (notPrimaryOrNodeIsRecoveringException != null) { throw notPrimaryOrNodeIsRecoveringException; } string message; BsonValue errmsgBsonValue; if (materializedDocument.TryGetValue("errmsg", out errmsgBsonValue) && errmsgBsonValue.IsString) { var errmsg = errmsgBsonValue.ToString(); message = string.Format("Command {0} failed: {1}.", commandName, errmsg); } else { message = string.Format("Command {0} failed.", commandName); } var mappedException = ExceptionMapper.Map(connectionId, materializedDocument); if (mappedException != null) { throw mappedException; } throw new MongoCommandException(connectionId, message, _command, materializedDocument); } using (var stream = new ByteBufferStream(rawDocument.Slice, ownsBuffer: false)) { var encoderFactory = new BinaryMessageEncoderFactory(stream, _messageEncoderSettings); var encoder = (ReplyMessageBinaryEncoder <TCommandResult>)encoderFactory.GetReplyMessageEncoder <TCommandResult>(_resultSerializer); using (var reader = encoder.CreateBinaryReader()) { var context = BsonDeserializationContext.CreateRoot(reader); return(_resultSerializer.Deserialize(context)); } } } }
private void ApplyApplicationError(BsonDocument applicationError) { var expectedKeys = new[] { "address", "generation", // optional "maxWireVersion", "when", "type", "response" // optional }; JsonDrivenHelper.EnsureAllFieldsAreValid(applicationError, expectedKeys); var address = applicationError["address"].AsString; var endPoint = EndPointHelper.Parse(address); var server = (Server)_serverFactory.GetServer(endPoint); var connectionId = new ConnectionId(server.ServerId); var type = applicationError["type"].AsString; var maxWireVersion = applicationError["maxWireVersion"].AsInt32; Exception simulatedException = null; switch (type) { case "command": var response = applicationError["response"].AsBsonDocument; var command = new BsonDocument("Link", "start!"); simulatedException = ExceptionMapper.MapNotPrimaryOrNodeIsRecovering(connectionId, command, response, "errmsg"); Ensure.IsNotNull(simulatedException, nameof(simulatedException)); break; case "network": { var innerException = CoreExceptionHelper.CreateException("IOExceptionWithNetworkUnreachableSocketException"); simulatedException = new MongoConnectionException(connectionId, "Ignorance, yet knowledge.", innerException); break; } case "timeout": { var innerException = CoreExceptionHelper.CreateException("IOExceptionWithTimedOutSocketException"); simulatedException = new MongoConnectionException(connectionId, "Chaos, yet harmony.", innerException); break; } default: throw new ArgumentException($"Unsupported value of {type} for type"); } var mockConnection = new Mock <IConnectionHandle>(); var isMasterResult = new IsMasterResult(new BsonDocument { { "compressors", new BsonArray() } }); var serverVersion = WireVersionHelper.MapWireVersionToServerVersion(maxWireVersion); var buildInfoResult = new BuildInfoResult(new BsonDocument { { "version", serverVersion } }); mockConnection.SetupGet(c => c.Description) .Returns(new ConnectionDescription(connectionId, isMasterResult, buildInfoResult)); var generation = applicationError.Contains("generation") ? applicationError["generation"].AsInt32 : 0; mockConnection.SetupGet(c => c.Generation).Returns(generation); var when = applicationError["when"].AsString; switch (when) { case "beforeHandshakeCompletes": server.HandleBeforeHandshakeCompletesException(mockConnection.Object, simulatedException); break; case "afterHandshakeCompletes": server.HandleChannelException(mockConnection.Object, simulatedException); break; default: throw new ArgumentException($"Unsupported value of {when} for when."); } }
private TCommandResult ProcessResponse(ConnectionId connectionId, CommandMessage responseMessage) { using (new CommandMessageDisposer(responseMessage)) { var rawDocument = responseMessage.Sections.OfType <Type0CommandMessageSection <RawBsonDocument> >().Single().Document; var binaryReaderSettings = new BsonBinaryReaderSettings(); if (_messageEncoderSettings != null) { binaryReaderSettings.Encoding = _messageEncoderSettings.GetOrDefault <UTF8Encoding>(MessageEncoderSettingsName.ReadEncoding, Utf8Encodings.Strict); binaryReaderSettings.GuidRepresentation = _messageEncoderSettings.GetOrDefault <GuidRepresentation>(MessageEncoderSettingsName.GuidRepresentation, GuidRepresentation.CSharpLegacy); } ; BsonValue clusterTime; if (rawDocument.TryGetValue("$clusterTime", out clusterTime)) { // note: we are assuming that _session is an instance of ClusterClockAdvancingClusterTime // and that calling _session.AdvanceClusterTime will have the side effect of advancing the cluster's ClusterTime also var materializedClusterTime = ((RawBsonDocument)clusterTime).Materialize(binaryReaderSettings); _session.AdvanceClusterTime(materializedClusterTime); } BsonValue operationTime; if (rawDocument.TryGetValue("operationTime", out operationTime)) { _session.AdvanceOperationTime(operationTime.AsBsonTimestamp); } if (!rawDocument.GetValue("ok", false).ToBoolean()) { var materializedDocument = rawDocument.Materialize(binaryReaderSettings); var commandName = _command.GetElement(0).Name; if (commandName == "$query") { commandName = _command["$query"].AsBsonDocument.GetElement(0).Name; } var notPrimaryOrNodeIsRecoveringException = ExceptionMapper.MapNotPrimaryOrNodeIsRecovering(connectionId, materializedDocument, "errmsg"); if (notPrimaryOrNodeIsRecoveringException != null) { throw notPrimaryOrNodeIsRecoveringException; } var mappedException = ExceptionMapper.Map(connectionId, materializedDocument); if (mappedException != null) { throw mappedException; } string message; BsonValue errmsgBsonValue; if (materializedDocument.TryGetValue("errmsg", out errmsgBsonValue) && errmsgBsonValue.IsString) { var errmsg = errmsgBsonValue.ToString(); message = string.Format("Command {0} failed: {1}.", commandName, errmsg); } else { message = string.Format("Command {0} failed.", commandName); } throw new MongoCommandException(connectionId, message, _command, materializedDocument); } using (var stream = new ByteBufferStream(rawDocument.Slice, ownsBuffer: false)) { using (var reader = new BsonBinaryReader(stream, binaryReaderSettings)) { var context = BsonDeserializationContext.CreateRoot(reader); return(_resultSerializer.Deserialize(context)); } } } }
private TCommandResult ProcessResponse(ConnectionId connectionId, CommandMessage responseMessage) { using (new CommandMessageDisposer(responseMessage)) { var rawDocument = responseMessage.Sections.OfType <Type0CommandMessageSection <RawBsonDocument> >().Single().Document; var binaryReaderSettings = new BsonBinaryReaderSettings(); if (_messageEncoderSettings != null) { binaryReaderSettings.Encoding = _messageEncoderSettings.GetOrDefault <UTF8Encoding>(MessageEncoderSettingsName.ReadEncoding, Utf8Encodings.Strict); #pragma warning disable 618 if (BsonDefaults.GuidRepresentationMode == GuidRepresentationMode.V2) { binaryReaderSettings.GuidRepresentation = _messageEncoderSettings.GetOrDefault <GuidRepresentation>(MessageEncoderSettingsName.GuidRepresentation, GuidRepresentation.CSharpLegacy); } #pragma warning restore 618 } ; BsonValue clusterTime; if (rawDocument.TryGetValue("$clusterTime", out clusterTime)) { // note: we are assuming that _session is an instance of ClusterClockAdvancingClusterTime // and that calling _session.AdvanceClusterTime will have the side effect of advancing the cluster's ClusterTime also var materializedClusterTime = ((RawBsonDocument)clusterTime).Materialize(binaryReaderSettings); _session.AdvanceClusterTime(materializedClusterTime); } BsonValue operationTime; if (rawDocument.TryGetValue("operationTime", out operationTime)) { _session.AdvanceOperationTime(operationTime.AsBsonTimestamp); } if (rawDocument.GetValue("ok", false).ToBoolean()) { if (rawDocument.TryGetValue("recoveryToken", out var rawRecoveryToken)) { var recoveryToken = ((RawBsonDocument)rawRecoveryToken).Materialize(binaryReaderSettings); _session.CurrentTransaction.RecoveryToken = recoveryToken; } } else { var materializedDocument = rawDocument.Materialize(binaryReaderSettings); var commandName = _command.GetElement(0).Name; if (commandName == "$query") { commandName = _command["$query"].AsBsonDocument.GetElement(0).Name; } var notPrimaryOrNodeIsRecoveringException = ExceptionMapper.MapNotPrimaryOrNodeIsRecovering(connectionId, _command, materializedDocument, "errmsg"); if (notPrimaryOrNodeIsRecoveringException != null) { throw notPrimaryOrNodeIsRecoveringException; } var mappedException = ExceptionMapper.Map(connectionId, materializedDocument); if (mappedException != null) { throw mappedException; } string message; BsonValue errmsgBsonValue; if (materializedDocument.TryGetValue("errmsg", out errmsgBsonValue) && errmsgBsonValue.IsString) { var errmsg = errmsgBsonValue.ToString(); message = string.Format("Command {0} failed: {1}.", commandName, errmsg); } else { message = string.Format("Command {0} failed.", commandName); } var exception = new MongoCommandException(connectionId, message, _command, materializedDocument); // https://jira.mongodb.org/browse/CSHARP-2678 if (IsRetryableWriteExceptionAndDeploymentDoesNotSupportRetryableWrites(exception)) { throw WrapNotSupportedRetryableWriteException(exception); } else { throw exception; } } if (rawDocument.Contains("writeConcernError")) { var materializedDocument = rawDocument.Materialize(binaryReaderSettings); var writeConcernError = materializedDocument["writeConcernError"].AsBsonDocument; var message = writeConcernError.AsBsonDocument.GetValue("errmsg", null)?.AsString; var writeConcernResult = new WriteConcernResult(materializedDocument); throw new MongoWriteConcernException(connectionId, message, writeConcernResult); } using (var stream = new ByteBufferStream(rawDocument.Slice, ownsBuffer: false)) { using (var reader = new BsonBinaryReader(stream, binaryReaderSettings)) { var context = BsonDeserializationContext.CreateRoot(reader); return(_resultSerializer.Deserialize(context)); } } } }
private TCommandResult ProcessReply(ConnectionId connectionId, ReplyMessage <RawBsonDocument> reply) { if (reply.NumberReturned == 0) { throw new MongoCommandException(connectionId, "Command returned no documents.", _command); } if (reply.NumberReturned > 1) { throw new MongoCommandException(connectionId, "Command returned multiple documents.", _command); } if (reply.QueryFailure) { var failureDocument = reply.QueryFailureDocument; throw ExceptionMapper.Map(connectionId, failureDocument) ?? new MongoCommandException(connectionId, "Command failed.", _command, failureDocument); } using (var rawDocument = reply.Documents[0]) { var binaryReaderSettings = new BsonBinaryReaderSettings(); if (_messageEncoderSettings != null) { binaryReaderSettings.Encoding = _messageEncoderSettings.GetOrDefault <UTF8Encoding>(MessageEncoderSettingsName.ReadEncoding, Utf8Encodings.Strict); #pragma warning disable 618 if (BsonDefaults.GuidRepresentationMode == GuidRepresentationMode.V2) { binaryReaderSettings.GuidRepresentation = _messageEncoderSettings.GetOrDefault <GuidRepresentation>(MessageEncoderSettingsName.GuidRepresentation, GuidRepresentation.CSharpLegacy); } #pragma warning restore 618 } ; BsonValue clusterTime; if (rawDocument.TryGetValue("$clusterTime", out clusterTime)) { // note: we are assuming that _session is an instance of ClusterClockAdvancingClusterTime // and that calling _session.AdvanceClusterTime will have the side effect of advancing the cluster's ClusterTime also var materializedClusterTime = ((RawBsonDocument)clusterTime).Materialize(binaryReaderSettings); _session.AdvanceClusterTime(materializedClusterTime); } BsonValue operationTime; if (rawDocument.TryGetValue("operationTime", out operationTime)) { _session.AdvanceOperationTime(operationTime.AsBsonTimestamp); } if (!rawDocument.GetValue("ok", false).ToBoolean()) { var materializedDocument = rawDocument.Materialize(binaryReaderSettings); var commandName = _command.GetElement(0).Name; if (commandName == "$query") { commandName = _command["$query"].AsBsonDocument.GetElement(0).Name; } var notPrimaryOrNodeIsRecoveringException = ExceptionMapper.MapNotPrimaryOrNodeIsRecovering(connectionId, _command, materializedDocument, "errmsg"); if (notPrimaryOrNodeIsRecoveringException != null) { throw notPrimaryOrNodeIsRecoveringException; } string message; BsonValue errmsgBsonValue; if (materializedDocument.TryGetValue("errmsg", out errmsgBsonValue) && errmsgBsonValue.IsString) { var errmsg = errmsgBsonValue.ToString(); message = string.Format("Command {0} failed: {1}.", commandName, errmsg); } else { message = string.Format("Command {0} failed.", commandName); } var mappedException = ExceptionMapper.Map(connectionId, materializedDocument); if (mappedException != null) { throw mappedException; } throw new MongoCommandException(connectionId, message, _command, materializedDocument); } if (rawDocument.Contains("writeConcernError")) { var materializedDocument = rawDocument.Materialize(binaryReaderSettings); var writeConcernError = materializedDocument["writeConcernError"].AsBsonDocument; var message = writeConcernError.AsBsonDocument.GetValue("errmsg", null)?.AsString; var writeConcernResult = new WriteConcernResult(materializedDocument); throw new MongoWriteConcernException(connectionId, message, writeConcernResult); } using (var stream = new ByteBufferStream(rawDocument.Slice, ownsBuffer: false)) { var encoderFactory = new BinaryMessageEncoderFactory(stream, _messageEncoderSettings); var encoder = (ReplyMessageBinaryEncoder <TCommandResult>)encoderFactory.GetReplyMessageEncoder <TCommandResult>(_resultSerializer); using (var reader = encoder.CreateBinaryReader()) { var context = BsonDeserializationContext.CreateRoot(reader); return(_resultSerializer.Deserialize(context)); } } } }