/* * Copyright (c) 2016 NTT DATA Corporation * * 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 jp.terasoluna.fw.batch.executor; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import javax.annotation.Resource; import org.aopalliance.intercept.MethodInvocation; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.dao.DataAccessException; import org.springframework.dao.RecoverableDataAccessException; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.transaction.TransactionException; import org.springframework.transaction.TransactionSystemException; import uk.org.lidalia.slf4jext.Level; import uk.org.lidalia.slf4jtest.TestLogger; import uk.org.lidalia.slf4jtest.TestLoggerFactory; /** * {@code AdminConnectionRetryInterceptor}のテストケース。<br> * @since 3.6 */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:beansDef/AdminConnectionRetryInterceptor.xml") public class AdminConnectionRetryInterceptorTest { @Resource protected AdminConnectionRetryInterceptor adminConnectionRetryInterceptor; private TestLogger logger = TestLoggerFactory.getTestLogger( AdminConnectionRetryInterceptor.class); private long maxRetryCount; private long retryInterval; private long retryReset; /** * テスト前処理:インスタンスのフィールド初期値を退避。 */ @Before public void setUp() { maxRetryCount = (long) ReflectionTestUtils.getField( adminConnectionRetryInterceptor, "maxRetryCount"); retryInterval = (long) ReflectionTestUtils.getField( adminConnectionRetryInterceptor, "retryInterval"); retryReset = (long) ReflectionTestUtils.getField( adminConnectionRetryInterceptor, "retryReset"); } /** * テスト後処理:インスタンスのフィールド値を元に戻し、ロガーのクリアを行なう。 */ @After public void tearDown() { ReflectionTestUtils.setField(adminConnectionRetryInterceptor, "maxRetryCount", maxRetryCount); ReflectionTestUtils.setField(adminConnectionRetryInterceptor, "retryInterval", retryInterval); ReflectionTestUtils.setField(adminConnectionRetryInterceptor, "retryReset", retryReset); logger.clear(); } /** * invoke()メソッドのテスト 【正常系】 * * <pre> * 事前条件 * ・とくになし * 確認項目 * ・例外が発生せずにメソッドが終了すること * </pre> * * @throws Throwable 予期せぬ例外 */ @Test public void testInvoke01() throws Throwable { // テスト準備 MethodInvocation mockMethodInvocation = mock(MethodInvocation.class); when(mockMethodInvocation.proceed()).thenReturn(null); // テスト実行 // 検証 assertNull(adminConnectionRetryInterceptor.invoke( mockMethodInvocation)); } /** * invoke()メソッドのテスト 【異常系】 * * <pre> * 事前条件 * ・DataAccessExceptionの派生クラス(RecoverableDataAccessException)をスローすること * ・最大試行回数 0 * 確認項目 * ・DataAccessExceptionの派生クラスがスローされること * ・EAL025031のログが出力されること * </pre> * * @throws Throwable 予期せぬ例外 */ @Test public void testInvoke02() throws Throwable { // テスト準備 MethodInvocation mockMethodInvocation = mock(MethodInvocation.class); RecoverableDataAccessException recoverableDataAccessException = new RecoverableDataAccessException(null); // テスト実行 // 検証 try { when(mockMethodInvocation.proceed()).thenThrow( recoverableDataAccessException); adminConnectionRetryInterceptor.invoke(mockMethodInvocation); fail(); } catch (DataAccessException e) { assertSame(recoverableDataAccessException, e); } assertEquals(Level.ERROR, logger.getLoggingEvents().get(0).getLevel()); assertEquals( "[EAL025063] Connection retry count exceeded limit. maxRetryCount:0", logger.getLoggingEvents().get(0).getMessage()); } /** * invoke()メソッドのテスト 【異常系】 * * <pre> * 事前条件 * ・TransactionExceptionの派生クラス(TransactionSystemException)をスローすること * ・最大試行回数 0 * 確認項目 * ・TransactionExceptionの派生クラスがスローされること * ・EAL025031のログが出力されること * </pre> * * @throws Throwable 予期せぬ例外 */ @Test public void testInvoke03() throws Throwable { // テスト準備 MethodInvocation mockMethodInvocation = mock(MethodInvocation.class); TransactionException transactionSystemException = new TransactionSystemException("test exception"); // テスト実行 // 検証 try { when(mockMethodInvocation.proceed()).thenThrow( transactionSystemException); adminConnectionRetryInterceptor.invoke(mockMethodInvocation); fail(); } catch (TransactionException e) { assertSame(transactionSystemException, e); } assertEquals(Level.ERROR, logger.getLoggingEvents().get(0).getLevel()); assertEquals( "[EAL025063] Connection retry count exceeded limit. maxRetryCount:0", logger.getLoggingEvents().get(0).getMessage()); } /** * invoke()メソッドのテスト 【異常系】 * * <pre> * 事前条件 * ・最大試行回数内で処理が成功すること * ・最大試行回数 3、RecoverableDataAccessException例外スロー回数 2 * 確認項目 * ・例外がスローされないこと * ・リトライ処理(MethodInvocation#proceed()が3回呼び出されること) * ・リトライ2回分のログが出力されること * </pre> * * @throws Throwable 予期せぬ例外 */ @Test public void testInvoke05() throws Throwable { // テスト準備 MethodInvocation mockMethodInvocation = mock(MethodInvocation.class); ReflectionTestUtils.setField(adminConnectionRetryInterceptor, "retryInterval", 500); ReflectionTestUtils.setField(adminConnectionRetryInterceptor, "maxRetryCount", 3); when(mockMethodInvocation.proceed()).thenThrow( new RecoverableDataAccessException(null)).thenThrow( new RecoverableDataAccessException(null)).thenReturn( null); // テスト実行 // 検証 assertNull(adminConnectionRetryInterceptor.invoke( mockMethodInvocation)); verify(mockMethodInvocation, times(3)).proceed(); assertEquals(Level.INFO, logger.getLoggingEvents().get(0).getLevel()); assertEquals( "[IAL025017] RetryDetails. currentRetryCount:1, retryMaxCount:3, retryReset:600,000 ms, retryInterval:500 ms", logger.getLoggingEvents().get(0).getMessage()); assertEquals(Level.INFO, logger.getLoggingEvents().get(1).getLevel()); assertEquals( "[IAL025017] RetryDetails. currentRetryCount:2, retryMaxCount:3, retryReset:600,000 ms, retryInterval:500 ms", logger.getLoggingEvents().get(1).getMessage()); } /** * invoke()メソッドのテスト 【異常系】 * * <pre> * 事前条件 * ・最大試行回数内で処理が成功すること * ・最大試行回数 3、TransactionSystemException例外スロー回数 2 * 確認項目 * ・例外がスローされないこと * ・リトライ処理(MethodInvocation#proceed()が3回呼び出されること) * ・リトライ2回分のログが出力されること * </pre> * * @throws Throwable 予期せぬ例外 */ @Test public void testInvoke06() throws Throwable { // テスト準備 MethodInvocation mockMethodInvocation = mock(MethodInvocation.class); ReflectionTestUtils.setField(adminConnectionRetryInterceptor, "retryInterval", 500); ReflectionTestUtils.setField(adminConnectionRetryInterceptor, "maxRetryCount", 3); when(mockMethodInvocation.proceed()).thenThrow( new TransactionSystemException("test exception")).thenThrow( new TransactionSystemException("test exception")) .thenReturn(null); // テスト実行 // 検証 assertNull(adminConnectionRetryInterceptor.invoke( mockMethodInvocation)); verify(mockMethodInvocation, times(3)).proceed(); assertEquals(Level.INFO, logger.getLoggingEvents().get(0).getLevel()); assertEquals( "[IAL025017] RetryDetails. currentRetryCount:1, retryMaxCount:3, retryReset:600,000 ms, retryInterval:500 ms", logger.getLoggingEvents().get(0).getMessage()); assertEquals(Level.INFO, logger.getLoggingEvents().get(1).getLevel()); assertEquals( "[IAL025017] RetryDetails. currentRetryCount:2, retryMaxCount:3, retryReset:600,000 ms, retryInterval:500 ms", logger.getLoggingEvents().get(1).getMessage()); } /** * invoke()メソッドのテスト 【異常系】 * * <pre> * 事前条件 * ・最大試行回数を超えること * ・最大試行回数 3、RecoverableDataAccessException例外スロー回数 4 * 確認項目 * ・DataAccessException例外の派生クラスがスローされること * ・リトライ処理(MethodInvocation#proceed()が4回呼び出されること) * ・リトライ3回分、リトライ失敗のログが出力されること * </pre> * * @throws Throwable 予期せぬ例外 */ @Test public void testInvoke08() throws Throwable { // テスト準備 MethodInvocation mockMethodInvocation = mock(MethodInvocation.class); RecoverableDataAccessException recoverableDataAccessException = new RecoverableDataAccessException(null); ReflectionTestUtils.setField(adminConnectionRetryInterceptor, "retryInterval", 500); ReflectionTestUtils.setField(adminConnectionRetryInterceptor, "maxRetryCount", 3); // テスト実行 // 検証 try { when(mockMethodInvocation.proceed()).thenThrow( new RecoverableDataAccessException(null)).thenThrow( new RecoverableDataAccessException(null)).thenThrow( new RecoverableDataAccessException(null)) .thenThrow(recoverableDataAccessException).thenReturn(null); adminConnectionRetryInterceptor.invoke(mockMethodInvocation); fail(); } catch (DataAccessException e) { assertSame(recoverableDataAccessException, e); } verify(mockMethodInvocation, times(4)).proceed(); assertEquals(Level.INFO, logger.getLoggingEvents().get(0).getLevel()); assertEquals( "[IAL025017] RetryDetails. currentRetryCount:1, retryMaxCount:3, retryReset:600,000 ms, retryInterval:500 ms", logger.getLoggingEvents().get(0).getMessage()); assertEquals(Level.INFO, logger.getLoggingEvents().get(1).getLevel()); assertEquals( "[IAL025017] RetryDetails. currentRetryCount:2, retryMaxCount:3, retryReset:600,000 ms, retryInterval:500 ms", logger.getLoggingEvents().get(1).getMessage()); assertEquals(Level.INFO, logger.getLoggingEvents().get(2).getLevel()); assertEquals( "[IAL025017] RetryDetails. currentRetryCount:3, retryMaxCount:3, retryReset:600,000 ms, retryInterval:500 ms", logger.getLoggingEvents().get(2).getMessage()); assertEquals(Level.ERROR, logger.getLoggingEvents().get(3).getLevel()); assertEquals( "[EAL025063] Connection retry count exceeded limit. maxRetryCount:3", logger.getLoggingEvents().get(3).getMessage()); } /** * invoke()メソッドのテスト 【異常系】 * * <pre> * 事前条件 * ・最大試行回数を超えること * ・最大試行回数 3、TransactionSystemException例外スロー回数 4 * 確認項目 * ・TransactionException例外の派生クラスがスローされること * ・リトライ処理(MethodInvocation#proceed()が4回呼び出されること) * ・リトライ3回分のログ、リトライ失敗のログが出力されること * </pre> * * @throws Throwable 予期せぬ例外 */ @Test public void testInvoke09() throws Throwable { // テスト準備 MethodInvocation mockMethodInvocation = mock(MethodInvocation.class); TransactionException transactionException = new TransactionSystemException("test exception"); ReflectionTestUtils.setField(adminConnectionRetryInterceptor, "retryInterval", 500); ReflectionTestUtils.setField(adminConnectionRetryInterceptor, "maxRetryCount", 3); // テスト実行 // 検証 try { when(mockMethodInvocation.proceed()).thenThrow( new TransactionSystemException("test exception 1")) .thenThrow( new TransactionSystemException("test exception 2")) .thenThrow( new TransactionSystemException("test exception 3")) .thenThrow(transactionException).thenReturn(null); adminConnectionRetryInterceptor.invoke(mockMethodInvocation); fail(); } catch (TransactionException e) { assertSame(transactionException, e); } verify(mockMethodInvocation, times(4)).proceed(); assertEquals(Level.INFO, logger.getLoggingEvents().get(0).getLevel()); assertEquals( "[IAL025017] RetryDetails. currentRetryCount:1, retryMaxCount:3, retryReset:600,000 ms, retryInterval:500 ms", logger.getLoggingEvents().get(0).getMessage()); assertEquals(Level.INFO, logger.getLoggingEvents().get(1).getLevel()); assertEquals( "[IAL025017] RetryDetails. currentRetryCount:2, retryMaxCount:3, retryReset:600,000 ms, retryInterval:500 ms", logger.getLoggingEvents().get(1).getMessage()); assertEquals(Level.INFO, logger.getLoggingEvents().get(2).getLevel()); assertEquals( "[IAL025017] RetryDetails. currentRetryCount:3, retryMaxCount:3, retryReset:600,000 ms, retryInterval:500 ms", logger.getLoggingEvents().get(2).getMessage()); assertEquals(Level.ERROR, logger.getLoggingEvents().get(3).getLevel()); assertEquals( "[EAL025063] Connection retry count exceeded limit. maxRetryCount:3", logger.getLoggingEvents().get(3).getMessage()); } /** * invoke()メソッドのテスト 【異常系】 * * <pre> * 事前条件 * ・正常終了するまで、最大試行回数を超えてリトライを繰り返す(retryInterval > retryResetなので、リトライ回数が都度リセットされる)こと * 確認項目 * ・例外がスローされないこと * ・リトライ処理(MethodInvocation#proceed()が5回呼び出されること) * ・リトライ4回分のログが出力されること * </pre> * * @throws Throwable 予期せぬ例外 */ @Test public void testInvoke11() throws Throwable { // テスト準備 MethodInvocation mockMethodInvocation = mock(MethodInvocation.class); ReflectionTestUtils.setField(adminConnectionRetryInterceptor, "retryInterval", 500); ReflectionTestUtils.setField(adminConnectionRetryInterceptor, "maxRetryCount", 3); ReflectionTestUtils.setField(adminConnectionRetryInterceptor, "retryReset", 300); // テスト実行 // 検証 when(mockMethodInvocation.proceed()).thenThrow( new RecoverableDataAccessException(null)).thenThrow( new RecoverableDataAccessException(null)).thenThrow( new RecoverableDataAccessException(null)) .thenThrow(new RecoverableDataAccessException(null)).thenReturn( null); assertNull(adminConnectionRetryInterceptor.invoke( mockMethodInvocation)); verify(mockMethodInvocation, times(5)).proceed(); assertEquals(Level.INFO, logger.getLoggingEvents().get(0).getLevel()); assertEquals( "[IAL025017] RetryDetails. currentRetryCount:1, retryMaxCount:3, retryReset:300 ms, retryInterval:500 ms", logger.getLoggingEvents().get(0).getMessage()); assertEquals(Level.INFO, logger.getLoggingEvents().get(1).getLevel()); assertEquals( "[IAL025017] RetryDetails. currentRetryCount:1, retryMaxCount:3, retryReset:300 ms, retryInterval:500 ms", logger.getLoggingEvents().get(1).getMessage()); assertEquals(Level.INFO, logger.getLoggingEvents().get(2).getLevel()); assertEquals( "[IAL025017] RetryDetails. currentRetryCount:1, retryMaxCount:3, retryReset:300 ms, retryInterval:500 ms", logger.getLoggingEvents().get(2).getMessage()); assertEquals(Level.INFO, logger.getLoggingEvents().get(3).getLevel()); assertEquals( "[IAL025017] RetryDetails. currentRetryCount:1, retryMaxCount:3, retryReset:300 ms, retryInterval:500 ms", logger.getLoggingEvents().get(3).getMessage()); } }