Refine exception translation for client session exceptions.
Closes #3148 See #2939 Original Pull Request: #604
This commit is contained in:
committed by
Mark Paluch
parent
d04e76faaf
commit
dced760d9f
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb;
|
||||
|
||||
import org.springframework.dao.TransientDataAccessException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link TransientDataAccessException} specific to MongoDB {@link com.mongodb.session.ClientSession} related data
|
||||
* access failures such as reading data using an already closed session.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 3.3
|
||||
*/
|
||||
public class TransientClientSessionException extends TransientMongoDbException {
|
||||
|
||||
/**
|
||||
* Constructor for {@link TransientClientSessionException}.
|
||||
*
|
||||
* @param msg the detail message. Can be {@literal null}.
|
||||
* @param cause the root cause. Can be {@literal null}.
|
||||
*/
|
||||
public TransientClientSessionException(@Nullable String msg, @Nullable Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb;
|
||||
|
||||
import org.springframework.dao.TransientDataAccessException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Root of the hierarchy of MongoDB specific data access exceptions that are considered transient such as
|
||||
* {@link com.mongodb.MongoException MongoExceptions} carrying {@link com.mongodb.MongoException#hasErrorLabel(String)
|
||||
* specific labels}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 3.3
|
||||
*/
|
||||
public class TransientMongoDbException extends TransientDataAccessException {
|
||||
|
||||
/**
|
||||
* Constructor for {@link TransientMongoDbException}.
|
||||
*
|
||||
* @param msg the detail message. Can be {@literal null}.
|
||||
* @param cause the root cause. Can be {@literal null}.
|
||||
*/
|
||||
public TransientMongoDbException(String msg, @Nullable Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
}
|
||||
@@ -25,9 +25,11 @@ import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
import org.springframework.dao.PermissionDeniedDataAccessException;
|
||||
import org.springframework.dao.TransientDataAccessException;
|
||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||
import org.springframework.data.mongodb.ClientSessionException;
|
||||
import org.springframework.data.mongodb.MongoTransactionException;
|
||||
import org.springframework.data.mongodb.TransientClientSessionException;
|
||||
import org.springframework.data.mongodb.TransientMongoDbException;
|
||||
import org.springframework.data.mongodb.UncategorizedMongoDbException;
|
||||
import org.springframework.data.mongodb.util.MongoDbErrorCodes;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -65,9 +67,26 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
|
||||
|
||||
private static final Set<String> SECURITY_EXCEPTIONS = Set.of("MongoCryptException");
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
|
||||
|
||||
DataAccessException translatedException = doTranslateException(ex);
|
||||
if (translatedException == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Translated exceptions that per se are not be recoverable (eg. WriteConflicts), might still be transient inside a
|
||||
// transaction. Let's wrap those.
|
||||
return (isTransientFailure(ex) && !(translatedException instanceof TransientDataAccessException))
|
||||
? new TransientMongoDbException(ex.getMessage(), translatedException)
|
||||
: translatedException;
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
DataAccessException doTranslateException(RuntimeException ex) {
|
||||
|
||||
// Check for well-known MongoException subclasses.
|
||||
|
||||
if (ex instanceof BsonInvalidOperationException) {
|
||||
@@ -94,13 +113,13 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
|
||||
|
||||
if (DATA_INTEGRITY_EXCEPTIONS.contains(exception)) {
|
||||
|
||||
if (ex instanceof MongoServerException mse) {
|
||||
if (mse.getCode() == 11000) {
|
||||
if (ex instanceof MongoServerException) {
|
||||
if (MongoDbErrorCodes.isDataDuplicateKeyError(ex)) {
|
||||
return new DuplicateKeyException(ex.getMessage(), ex);
|
||||
}
|
||||
if (ex instanceof MongoBulkWriteException bulkException) {
|
||||
for (BulkWriteError x : bulkException.getWriteErrors()) {
|
||||
if (x.getCode() == 11000) {
|
||||
for (BulkWriteError writeError : bulkException.getWriteErrors()) {
|
||||
if (MongoDbErrorCodes.isDuplicateKeyCode(writeError.getCode())) {
|
||||
return new DuplicateKeyException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
@@ -115,20 +134,27 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
|
||||
|
||||
int code = mongoException.getCode();
|
||||
|
||||
if (MongoDbErrorCodes.isDuplicateKeyCode(code)) {
|
||||
if (MongoDbErrorCodes.isDuplicateKeyError(mongoException)) {
|
||||
return new DuplicateKeyException(ex.getMessage(), ex);
|
||||
} else if (MongoDbErrorCodes.isDataAccessResourceFailureCode(code)) {
|
||||
}
|
||||
if (MongoDbErrorCodes.isDataAccessResourceError(mongoException)) {
|
||||
return new DataAccessResourceFailureException(ex.getMessage(), ex);
|
||||
} else if (MongoDbErrorCodes.isInvalidDataAccessApiUsageCode(code) || code == 10003 || code == 12001
|
||||
|| code == 12010 || code == 12011 || code == 12012) {
|
||||
}
|
||||
if (MongoDbErrorCodes.isInvalidDataAccessApiUsageError(mongoException) || code == 12001 || code == 12010
|
||||
|| code == 12011 || code == 12012) {
|
||||
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
|
||||
} else if (MongoDbErrorCodes.isPermissionDeniedCode(code)) {
|
||||
}
|
||||
if (MongoDbErrorCodes.isPermissionDeniedError(mongoException)) {
|
||||
return new PermissionDeniedDataAccessException(ex.getMessage(), ex);
|
||||
} else if (MongoDbErrorCodes.isClientSessionFailureCode(code)) {
|
||||
return new ClientSessionException(ex.getMessage(), ex);
|
||||
} else if (MongoDbErrorCodes.isTransactionFailureCode(code)) {
|
||||
return new MongoTransactionException(ex.getMessage(), ex);
|
||||
} else if(ex.getCause() != null && SECURITY_EXCEPTIONS.contains(ClassUtils.getShortName(ex.getCause().getClass()))) {
|
||||
}
|
||||
if (MongoDbErrorCodes.isDataIntegrityViolationError(mongoException)) {
|
||||
return new DataIntegrityViolationException(mongoException.getMessage(), mongoException);
|
||||
}
|
||||
if (MongoDbErrorCodes.isClientSessionFailure(mongoException)) {
|
||||
return isTransientFailure(mongoException) ? new TransientClientSessionException(ex.getMessage(), ex)
|
||||
: new ClientSessionException(ex.getMessage(), ex);
|
||||
}
|
||||
if (ex.getCause() != null && SECURITY_EXCEPTIONS.contains(ClassUtils.getShortName(ex.getCause().getClass()))) {
|
||||
return new PermissionDeniedDataAccessException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
@@ -150,4 +176,25 @@ public class MongoExceptionTranslator implements PersistenceExceptionTranslator
|
||||
// that translation should not occur.
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given exception holds an error label indicating a transient failure.
|
||||
*
|
||||
* @param e
|
||||
* @return {@literal true} if the given {@link Exception} is a {@link MongoException} holding one of the transient
|
||||
* exception error labels.
|
||||
* @see MongoException#hasErrorLabel(String)
|
||||
* @since 3.3
|
||||
*/
|
||||
public static boolean isTransientFailure(Exception e) {
|
||||
|
||||
if (!(e instanceof MongoException)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MongoException mongoException = (MongoException) e;
|
||||
|
||||
return mongoException.hasErrorLabel(MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL)
|
||||
|| mongoException.hasErrorLabel(MongoException.UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.context.MappingContextEvent;
|
||||
import org.springframework.data.mongodb.MongoDatabaseFactory;
|
||||
import org.springframework.data.mongodb.UncategorizedMongoDbException;
|
||||
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.IndexDefinitionHolder;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
@@ -152,7 +151,7 @@ public class MongoPersistentEntityIndexCreator implements ApplicationListener<Ma
|
||||
IndexOperations indexOperations = indexOperationsProvider.indexOps(indexDefinition.getCollection());
|
||||
indexOperations.ensureIndex(indexDefinition);
|
||||
|
||||
} catch (UncategorizedMongoDbException ex) {
|
||||
} catch (DataIntegrityViolationException ex) {
|
||||
|
||||
if (ex.getCause() instanceof MongoException mongoException
|
||||
&& MongoDbErrorCodes.isDataIntegrityViolationCode(mongoException.getCode())) {
|
||||
|
||||
@@ -21,10 +21,10 @@ import java.util.Set;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.domain.Sort.Order;
|
||||
import org.springframework.data.mongodb.UncategorizedMongoDbException;
|
||||
import org.springframework.data.mongodb.core.MongoOperations;
|
||||
import org.springframework.data.mongodb.core.index.Index;
|
||||
import org.springframework.data.mongodb.core.index.IndexOperationsProvider;
|
||||
@@ -111,7 +111,7 @@ class IndexEnsuringQueryCreationListener implements QueryCreationListener<PartTr
|
||||
MongoEntityMetadata<?> metadata = query.getQueryMethod().getEntityInformation();
|
||||
try {
|
||||
indexOperationsProvider.indexOps(metadata.getCollectionName(), metadata.getJavaType()).ensureIndex(index);
|
||||
} catch (UncategorizedMongoDbException e) {
|
||||
} catch (DataIntegrityViolationException e) {
|
||||
|
||||
if (e.getCause() instanceof MongoException mongoException) {
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ import java.util.HashMap;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import com.mongodb.MongoException;
|
||||
|
||||
/**
|
||||
* {@link MongoDbErrorCodes} holds MongoDB specific error codes outlined in {@literal mongo/base/error_codes.yml}.
|
||||
*
|
||||
@@ -97,6 +99,7 @@ public final class MongoDbErrorCodes {
|
||||
invalidDataAccessApiUsageException.put(72, "InvalidOptions");
|
||||
invalidDataAccessApiUsageException.put(115, "CommandNotSupported");
|
||||
invalidDataAccessApiUsageException.put(116, "DocTooLargeForCapped");
|
||||
invalidDataAccessApiUsageException.put(10003, "CannotGrowDocumentInCappedNamespace");
|
||||
invalidDataAccessApiUsageException.put(130, "SymbolNotFound");
|
||||
invalidDataAccessApiUsageException.put(17280, "KeyTooLong");
|
||||
invalidDataAccessApiUsageException.put(13334, "ShardKeyTooBig");
|
||||
@@ -114,19 +117,17 @@ public final class MongoDbErrorCodes {
|
||||
clientSessionCodes = new HashMap<>(4, 1f);
|
||||
clientSessionCodes.put(206, "NoSuchSession");
|
||||
clientSessionCodes.put(213, "DuplicateSession");
|
||||
clientSessionCodes.put(217, "IncompleteTransactionHistory");
|
||||
clientSessionCodes.put(225, "TransactionTooOld");
|
||||
clientSessionCodes.put(228, "SessionTransferIncomplete");
|
||||
clientSessionCodes.put(244, "TransactionAborted");
|
||||
clientSessionCodes.put(251, "NoSuchTransaction");
|
||||
clientSessionCodes.put(256, "TransactionCommitted");
|
||||
clientSessionCodes.put(257, "TransactionToLarge");
|
||||
clientSessionCodes.put(261, "TooManyLogicalSessions");
|
||||
clientSessionCodes.put(263, "OperationNotSupportedInTransaction");
|
||||
clientSessionCodes.put(264, "TooManyLogicalSessions");
|
||||
|
||||
transactionCodes = new HashMap<>(8, 1f);
|
||||
transactionCodes.put(217, "IncompleteTransactionHistory");
|
||||
transactionCodes.put(225, "TransactionTooOld");
|
||||
transactionCodes.put(244, "TransactionAborted");
|
||||
transactionCodes.put(251, "NoSuchTransaction");
|
||||
transactionCodes.put(256, "TransactionCommitted");
|
||||
transactionCodes.put(257, "TransactionToLarge");
|
||||
transactionCodes.put(263, "OperationNotSupportedInTransaction");
|
||||
transactionCodes.put(267, "PreparedTransactionInProgress");
|
||||
|
||||
errorCodes = new HashMap<>();
|
||||
errorCodes.putAll(dataAccessResourceFailureCodes);
|
||||
errorCodes.putAll(dataIntegrityViolationCodes);
|
||||
@@ -136,29 +137,107 @@ public final class MongoDbErrorCodes {
|
||||
errorCodes.putAll(clientSessionCodes);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getErrorDescription(@Nullable Integer errorCode) {
|
||||
return errorCode == null ? null : errorCodes.get(errorCode);
|
||||
}
|
||||
|
||||
public static boolean isDataIntegrityViolationCode(@Nullable Integer errorCode) {
|
||||
return errorCode != null && dataIntegrityViolationCodes.containsKey(errorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param exception can be {@literal null}.
|
||||
* @return
|
||||
* @since 3.3
|
||||
*/
|
||||
public static boolean isDataIntegrityViolationError(@Nullable Exception exception) {
|
||||
|
||||
if(exception instanceof MongoException) {
|
||||
return isDataIntegrityViolationCode(((MongoException) exception).getCode());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isDataAccessResourceFailureCode(@Nullable Integer errorCode) {
|
||||
return errorCode != null && dataAccessResourceFailureCodes.containsKey(errorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param exception can be {@literal null}.
|
||||
* @return
|
||||
* @since 3.3
|
||||
*/
|
||||
public static boolean isDataAccessResourceError(@Nullable Exception exception) {
|
||||
|
||||
if(exception instanceof MongoException) {
|
||||
return isDataAccessResourceFailureCode(((MongoException) exception).getCode());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isDuplicateKeyCode(@Nullable Integer errorCode) {
|
||||
return errorCode != null && duplicateKeyCodes.containsKey(errorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param exception can be {@literal null}.
|
||||
* @return
|
||||
* @since 3.3
|
||||
*/
|
||||
public static boolean isDuplicateKeyError(@Nullable Exception exception) {
|
||||
|
||||
if(exception instanceof MongoException) {
|
||||
return isDuplicateKeyCode(((MongoException) exception).getCode());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param exception can be {@literal null}.
|
||||
* @return
|
||||
* @since 3.3
|
||||
*/
|
||||
public static boolean isDataDuplicateKeyError(@Nullable Exception exception) {
|
||||
|
||||
if(exception instanceof MongoException) {
|
||||
return isDuplicateKeyCode(((MongoException) exception).getCode());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isPermissionDeniedCode(@Nullable Integer errorCode) {
|
||||
return errorCode != null && permissionDeniedCodes.containsKey(errorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param exception can be {@literal null}.
|
||||
* @return
|
||||
* @since 3.3
|
||||
*/
|
||||
public static boolean isPermissionDeniedError(@Nullable Exception exception) {
|
||||
|
||||
if(exception instanceof MongoException) {
|
||||
return isPermissionDeniedCode(((MongoException) exception).getCode());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isInvalidDataAccessApiUsageCode(@Nullable Integer errorCode) {
|
||||
return errorCode != null && invalidDataAccessApiUsageException.containsKey(errorCode);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getErrorDescription(@Nullable Integer errorCode) {
|
||||
return errorCode == null ? null : errorCodes.get(errorCode);
|
||||
/**
|
||||
* @param exception can be {@literal null}.
|
||||
* @return
|
||||
* @since 3.3
|
||||
*/
|
||||
public static boolean isInvalidDataAccessApiUsageError(@Nullable Exception exception) {
|
||||
|
||||
if(exception instanceof MongoException) {
|
||||
return isInvalidDataAccessApiUsageCode(((MongoException) exception).getCode());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,4 +261,17 @@ public final class MongoDbErrorCodes {
|
||||
public static boolean isTransactionFailureCode(@Nullable Integer errorCode) {
|
||||
return errorCode != null && transactionCodes.containsKey(errorCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param exception can be {@literal null}.
|
||||
* @return
|
||||
* @since 3.3
|
||||
*/
|
||||
public static boolean isClientSessionFailure(@Nullable Exception exception) {
|
||||
|
||||
if(exception instanceof MongoException) {
|
||||
return isClientSessionFailureCode(((MongoException) exception).getCode());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,13 @@ import org.mockito.Mockito;
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
import org.springframework.data.mongodb.ClientSessionException;
|
||||
import org.springframework.data.mongodb.MongoTransactionException;
|
||||
import org.springframework.data.mongodb.TransientMongoDbException;
|
||||
import org.springframework.data.mongodb.UncategorizedMongoDbException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
@@ -39,7 +41,9 @@ import com.mongodb.MongoInternalException;
|
||||
import com.mongodb.MongoSocketException;
|
||||
import com.mongodb.MongoSocketReadTimeoutException;
|
||||
import com.mongodb.MongoSocketWriteException;
|
||||
import com.mongodb.MongoWriteException;
|
||||
import com.mongodb.ServerAddress;
|
||||
import com.mongodb.WriteError;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link MongoExceptionTranslator}.
|
||||
@@ -80,15 +84,13 @@ class MongoExceptionTranslatorUnitTests {
|
||||
void translateSocketExceptionSubclasses() {
|
||||
|
||||
expectExceptionWithCauseMessage(
|
||||
translator.translateExceptionIfPossible(
|
||||
new MongoSocketWriteException("intermediate message", new ServerAddress(), new Exception(EXCEPTION_MESSAGE))
|
||||
),
|
||||
translator.translateExceptionIfPossible(new MongoSocketWriteException("intermediate message",
|
||||
new ServerAddress(), new Exception(EXCEPTION_MESSAGE))),
|
||||
DataAccessResourceFailureException.class, EXCEPTION_MESSAGE);
|
||||
|
||||
expectExceptionWithCauseMessage(
|
||||
translator.translateExceptionIfPossible(
|
||||
new MongoSocketReadTimeoutException("intermediate message", new ServerAddress(), new Exception(EXCEPTION_MESSAGE))
|
||||
),
|
||||
translator.translateExceptionIfPossible(new MongoSocketReadTimeoutException("intermediate message",
|
||||
new ServerAddress(), new Exception(EXCEPTION_MESSAGE))),
|
||||
DataAccessResourceFailureException.class, EXCEPTION_MESSAGE);
|
||||
|
||||
}
|
||||
@@ -172,6 +174,38 @@ class MongoExceptionTranslatorUnitTests {
|
||||
checkTranslatedMongoException(MongoTransactionException.class, 267);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2073
|
||||
public void translateTransientTransactionExceptions() {
|
||||
|
||||
MongoException source = new MongoException(267, "PreparedTransactionInProgress");
|
||||
source.addLabel(MongoException.TRANSIENT_TRANSACTION_ERROR_LABEL);
|
||||
|
||||
expectExceptionWithCauseMessage(translator.translateExceptionIfPossible(source), TransientMongoDbException.class,
|
||||
"PreparedTransactionInProgress");
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2073
|
||||
public void translateMongoExceptionWithTransientLabelToTransientMongoDbException() {
|
||||
|
||||
MongoException exception = new MongoException(0, "");
|
||||
exception.addLabel(MongoException.UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL);
|
||||
DataAccessException translatedException = translator.translateExceptionIfPossible(exception);
|
||||
|
||||
expectExceptionWithCauseMessage(translatedException, TransientMongoDbException.class);
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2073
|
||||
public void wrapsTranslatedExceptionsWhenTransientLabelPresent() {
|
||||
|
||||
MongoException exception = new MongoWriteException(new WriteError(112, "WriteConflict", new BsonDocument()), null);
|
||||
exception.addLabel(MongoException.UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL);
|
||||
|
||||
DataAccessException translatedException = translator.translateExceptionIfPossible(exception);
|
||||
|
||||
assertThat(translatedException).isInstanceOf(TransientMongoDbException.class);
|
||||
assertThat(translatedException.getCause()).isInstanceOf(DataIntegrityViolationException.class);
|
||||
}
|
||||
|
||||
private void checkTranslatedMongoException(Class<? extends Exception> clazz, int code) {
|
||||
|
||||
DataAccessException translated = translator.translateExceptionIfPossible(new MongoException(code, ""));
|
||||
|
||||
Reference in New Issue
Block a user