/* * Copyright 2013-2017 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 * * http://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.cassandra.support; import static org.assertj.core.api.Assertions.*; import static org.junit.Assume.*; import java.lang.reflect.Constructor; import java.net.InetSocketAddress; import java.util.Collections; import org.junit.Test; import org.springframework.cassandra.support.exception.*; import org.springframework.cassandra.support.exception.CassandraSchemaElementExistsException.ElementType; import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.dao.TransientDataAccessResourceException; import org.springframework.util.ClassUtils; import com.datastax.driver.core.ConsistencyLevel; import com.datastax.driver.core.DataType; import com.datastax.driver.core.ProtocolVersion; import com.datastax.driver.core.WriteType; import com.datastax.driver.core.exceptions.*; import com.google.common.reflect.TypeToken; /** * Unit tests for {@link CassandraExceptionTranslator} * * @author Matthew T. Adams * @author Mark Paluch */ public class CassandraExceptionTranslatorUnitTests { InetSocketAddress socketAddress = new InetSocketAddress("localhost", 42); CassandraExceptionTranslator sut = new CassandraExceptionTranslator(); @Test // DATACASS-402 public void shouldTranslateAuthenticationException() { DataAccessException result = sut .translateExceptionIfPossible(new AuthenticationException(socketAddress, "message")); assertThat(result).isInstanceOf(CassandraAuthenticationException.class) .hasMessageStartingWith("Authentication error on host").hasCauseInstanceOf(AuthenticationException.class); } @Test // DATACASS-402 public void shouldTranslateCassandraInternalException() { DataAccessException result = sut.translateExceptionIfPossible(new DriverInternalError("message")); assertThat(result).isInstanceOf(CassandraInternalException.class).hasMessageStartingWith("message") .hasCauseInstanceOf(DriverInternalError.class); } @Test // DATACASS-402 public void shouldTranslateTraceRetrievalException() { DataAccessException result = sut.translateExceptionIfPossible(new TraceRetrievalException("message")); assertThat(result).isInstanceOf(CassandraTraceRetrievalException.class).hasMessageStartingWith("message") .hasCauseInstanceOf(TraceRetrievalException.class); } @Test // DATACASS-402 public void shouldTranslateNoHostAvailableException() { DataAccessException result = sut.translateExceptionIfPossible( new NoHostAvailableException(Collections.singletonMap(socketAddress, new IllegalStateException()))); assertThat(result).isInstanceOf(CassandraConnectionFailureException.class) .hasMessageStartingWith("All host(s) tried").hasCauseInstanceOf(NoHostAvailableException.class); } @Test // DATACASS-402 public void shouldTranslateInvalidQueryException() { DataAccessException result = sut.translateExceptionIfPossible(new InvalidQueryException(socketAddress, "message")); assertThat(result).isInstanceOf(CassandraInvalidQueryException.class).hasMessageStartingWith("message") .hasCauseInstanceOf(InvalidQueryException.class); } @Test // DATACASS-402 public void shouldTranslateInvalidConfigurationInQueryException() { DataAccessException result = sut .translateExceptionIfPossible(new InvalidConfigurationInQueryException(socketAddress, "message")); assertThat(result).isInstanceOf(CassandraInvalidConfigurationInQueryException.class) .hasMessageStartingWith("message").hasCauseInstanceOf(InvalidConfigurationInQueryException.class); } @Test // DATACASS-402 public void shouldTranslateUnauthorizedException() { DataAccessException result = sut.translateExceptionIfPossible(new UnauthorizedException(socketAddress, "message")); assertThat(result).isInstanceOf(CassandraUnauthorizedException.class).hasMessageStartingWith("message") .hasCauseInstanceOf(UnauthorizedException.class); } @Test // DATACASS-402 public void shouldTranslateSyntaxError() { DataAccessException result = sut.translateExceptionIfPossible(new SyntaxError(socketAddress, "message")); assertThat(result).isInstanceOf(CassandraQuerySyntaxException.class).hasMessageStartingWith("message") .hasCauseInstanceOf(SyntaxError.class); } @Test // DATACASS-402 public void shouldTranslateKeyspaceExistsException() { AlreadyExistsException cx = new AlreadyExistsException("keyspace", ""); DataAccessException result = sut.translateExceptionIfPossible(cx); assertThat(result).isInstanceOf(CassandraKeyspaceExistsException.class) .hasMessageStartingWith("Keyspace keyspace already exists").hasCauseInstanceOf(AlreadyExistsException.class); CassandraSchemaElementExistsException exception = (CassandraSchemaElementExistsException) result; assertThat(exception.getElementName()).isEqualTo("keyspace"); assertThat(exception.getElementType()).isEqualTo(ElementType.KEYSPACE); } @Test // DATACASS-402 public void shouldTranslateTableExistsException() { AlreadyExistsException cx = new AlreadyExistsException("keyspace", "table"); DataAccessException result = sut.translateExceptionIfPossible(cx); assertThat(result).isInstanceOf(CassandraTableExistsException.class) .hasMessageStartingWith("Table keyspace.table already exists").hasCauseInstanceOf(AlreadyExistsException.class); CassandraSchemaElementExistsException exception = (CassandraSchemaElementExistsException) result; assertThat(exception.getElementName()).isEqualTo("table"); assertThat(exception.getElementType()).isEqualTo(ElementType.TABLE); } @Test // DATACASS-402 public void shouldTranslateInvalidTypeException() { DataAccessException result = sut.translateExceptionIfPossible(new InvalidTypeException("message")); assertThat(result).isInstanceOf(CassandraTypeMismatchException.class).hasMessageStartingWith("message") .hasCauseInstanceOf(InvalidTypeException.class); } @Test // DATACASS-402 public void shouldTranslateUnavailableException() { DataAccessException result = sut.translateExceptionIfPossible(new UnavailableException(ConsistencyLevel.ALL, 5, 1)); assertThat(result).isInstanceOf(CassandraInsufficientReplicasAvailableException.class) .hasMessageStartingWith("Not enough replicas available").hasCauseInstanceOf(UnavailableException.class); } @Test // DATACASS-402 public void shouldTranslateBootstrappingException() { DataAccessException result = sut.translateExceptionIfPossible(new BootstrappingException(socketAddress, "message")); assertThat(result).isInstanceOf(TransientDataAccessResourceException.class).hasMessageStartingWith("Queried host") .hasCauseInstanceOf(BootstrappingException.class); } @Test // DATACASS-402 public void shouldTranslateOverloadedException() { DataAccessException result = sut.translateExceptionIfPossible(new OverloadedException(socketAddress, "message")); assertThat(result).isInstanceOf(TransientDataAccessResourceException.class).hasMessageStartingWith("Queried host") .hasCauseInstanceOf(OverloadedException.class); } @Test // DATACASS-402 public void shouldTranslateTruncateException() { DataAccessException result = sut.translateExceptionIfPossible(new TruncateException(socketAddress, "message")); assertThat(result).isInstanceOf(CassandraTruncateException.class).hasMessageStartingWith("message") .hasCauseInstanceOf(TruncateException.class); } @Test // DATACASS-402 public void shouldTranslateWriteFailureException() { DataAccessException result = sut.translateExceptionIfPossible( new WriteFailureException(ConsistencyLevel.ALL, WriteType.BATCH, 1, 5, 1, Collections.emptyMap())); assertThat(result).isInstanceOf(DataAccessResourceFailureException.class) .hasMessageStartingWith("Cassandra failure during").hasCauseInstanceOf(WriteFailureException.class); } @Test // DATACASS-402 public void shouldTranslateReadFailureException() { DataAccessException result = sut.translateExceptionIfPossible( new ReadFailureException(ConsistencyLevel.ALL, 1, 5, 1, Collections.emptyMap(), true)); assertThat(result).isInstanceOf(DataAccessResourceFailureException.class) .hasMessageStartingWith("Cassandra failure during").hasCauseInstanceOf(ReadFailureException.class); } @Test // DATACASS-402 public void shouldTranslateWriteTimeoutException() { DataAccessException result = sut .translateExceptionIfPossible(new WriteTimeoutException(ConsistencyLevel.ALL, WriteType.BATCH, 1, 5)); assertThat(result).isInstanceOf(CassandraWriteTimeoutException.class) .hasMessageStartingWith("Cassandra timeout during").hasCauseInstanceOf(WriteTimeoutException.class); } @Test // DATACASS-402 public void shouldTranslateReadTimeoutException() { DataAccessException result = sut .translateExceptionIfPossible(new ReadTimeoutException(ConsistencyLevel.ALL, 1, 5, true)); assertThat(result).isInstanceOf(CassandraReadTimeoutException.class) .hasMessageStartingWith("Cassandra timeout during").hasCauseInstanceOf(ReadTimeoutException.class); } @Test // DATACASS-402 public void shouldTranslateFunctionExecutionException() { DataAccessException result = sut .translateExceptionIfPossible(new FunctionExecutionException(socketAddress, "message")); assertThat(result).isInstanceOf(DataAccessResourceFailureException.class).hasMessageStartingWith("message") .hasCauseInstanceOf(FunctionExecutionException.class); } @Test // DATACASS-402 @SuppressWarnings("unchecked") public void shouldTranslateBusyPoolException() throws Exception { assumeTrue( ClassUtils.isPresent("com.datastax.driver.core.exceptions.BusyPoolException", getClass().getClassLoader())); DriverException exception = createInstance("com.datastax.driver.core.exceptions.BusyPoolException", new Class[] { InetSocketAddress.class, Integer.TYPE }, socketAddress, 5); DataAccessException result = sut.translateExceptionIfPossible(exception); assertThat(result).isInstanceOf(CassandraConnectionFailureException.class).hasMessageContaining("Pool is busy") .hasCauseInstanceOf(exception.getClass()); } @Test // DATACASS-402 public void shouldTranslateConnectionException() { DataAccessException result = sut.translateExceptionIfPossible(new ConnectionException(socketAddress, "message")); assertThat(result).isInstanceOf(CassandraConnectionFailureException.class).hasMessageContaining("] message") .hasCauseInstanceOf(ConnectionException.class); } @Test // DATACASS-402 public void shouldTranslateBusyConnectionException() { DataAccessException result = sut.translateExceptionIfPossible(new BusyConnectionException(socketAddress)); assertThat(result).isInstanceOf(CassandraConnectionFailureException.class) .hasMessageContaining("Connection has run out of stream").hasCauseInstanceOf(BusyConnectionException.class); } @Test // DATACASS-402 @SuppressWarnings("unchecked") public void shouldTranslateFrameTooLongException() throws Exception { assumeTrue( ClassUtils.isPresent("com.datastax.driver.core.exceptions.FrameTooLongException", getClass().getClassLoader())); DriverException exception = createInstance("com.datastax.driver.core.exceptions.FrameTooLongException", new Class[] { Integer.TYPE }, 5); DataAccessException result = sut.translateExceptionIfPossible(exception); assertThat(result).isInstanceOf(CassandraUncategorizedException.class).hasCauseInstanceOf(exception.getClass()); } @Test // DATACASS-402 public void shouldTranslateToUncategorized() { assertThat(sut.translateExceptionIfPossible( new CodecNotFoundException("message", DataType.ascii(), TypeToken.of(Class.class)))) .isInstanceOf(CassandraUncategorizedException.class); assertThat(sut.translateExceptionIfPossible( new UnsupportedProtocolVersionException(socketAddress, ProtocolVersion.NEWEST_SUPPORTED, ProtocolVersion.V1))) .isInstanceOf(CassandraUncategorizedException.class); assertThat(sut.translateExceptionIfPossible(new UnpreparedException(socketAddress, "message"))) .isInstanceOf(CassandraUncategorizedException.class); assertThat(sut.translateExceptionIfPossible(new PagingStateException("message"))) .isInstanceOf(CassandraUncategorizedException.class); assertThat(sut.translateExceptionIfPossible(new UnresolvedUserTypeException("keyspace", "message"))) .isInstanceOf(CassandraUncategorizedException.class); assertThat( sut.translateExceptionIfPossible(new UnsupportedFeatureException(ProtocolVersion.NEWEST_SUPPORTED, "message"))) .isInstanceOf(CassandraUncategorizedException.class); assertThat(sut.translateExceptionIfPossible(new UnresolvedUserTypeException("keyspace", "message"))) .isInstanceOf(CassandraUncategorizedException.class); } @Test // DATACASS-335 public void shouldTranslateWithCqlMessage() { InvalidQueryException cx = new InvalidConfigurationInQueryException(null, "err"); DataAccessException dax = sut.translate("Query", "SELECT * FROM person", cx); assertThat(dax).hasRootCauseInstanceOf(InvalidQueryException.class).hasMessage( "Query; CQL [SELECT * FROM person]; err; nested exception is com.datastax.driver.core.exceptions.InvalidConfigurationInQueryException: err"); } @SuppressWarnings("unchecked") public <T> T createInstance(String className, Class<?> argTypes[], Object... args) throws ReflectiveOperationException { Class<T> exceptionClass = (Class) ClassUtils.forName(className, getClass().getClassLoader()); Constructor<T> constructor = exceptionClass.getDeclaredConstructor(argTypes); return constructor.newInstance(args); } }