/* * Copyright 2006-2007 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.batch.repeat.exception; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.junit.Before; import org.junit.Test; import org.springframework.batch.repeat.context.RepeatContextSupport; /** * Unit tests for {@link SimpleLimitExceptionHandler} * * @author Robert Kasanicky * @author Dave Syer */ public class SimpleLimitExceptionHandlerTests { // object under test private SimpleLimitExceptionHandler handler = new SimpleLimitExceptionHandler(); @Before public void initializeHandler() throws Exception { handler.afterPropertiesSet(); } @Test public void testInitializeWithNullContext() throws Throwable { try { handler.handleException(null, new RuntimeException("foo")); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { // expected } } @Test public void testInitializeWithNullContextAndNullException() throws Throwable { try { handler.handleException(null, null); } catch (IllegalArgumentException e) { // expected; } } @Test public void testDefaultBehaviour() throws Throwable { Throwable throwable = new RuntimeException("foo"); try { handler.handleException(new RepeatContextSupport(null), throwable); fail("Exception was swallowed."); } catch (RuntimeException expected) { assertTrue("Exception is rethrown, ignoring the exception limit", true); assertSame(expected, throwable); } } /** * Other than nominated exception type should be rethrown, ignoring the * exception limit. * * @throws Exception */ @Test public void testNormalExceptionThrown() throws Throwable { Throwable throwable = new RuntimeException("foo"); final int MORE_THAN_ZERO = 1; handler.setLimit(MORE_THAN_ZERO); handler.setExceptionClasses(Collections.<Class<? extends Throwable>> singleton(IllegalArgumentException.class)); handler.afterPropertiesSet(); try { handler.handleException(new RepeatContextSupport(null), throwable); fail("Exception was swallowed."); } catch (RuntimeException expected) { assertTrue("Exception is rethrown, ignoring the exception limit", true); assertSame(expected, throwable); } } /** * TransactionInvalidException should only be rethrown below the exception * limit. * * @throws Exception */ @Test public void testLimitedExceptionTypeNotThrown() throws Throwable { final int MORE_THAN_ZERO = 1; handler.setLimit(MORE_THAN_ZERO); handler.setExceptionClasses(Collections.<Class<? extends Throwable>> singleton(RuntimeException.class)); handler.afterPropertiesSet(); try { handler.handleException(new RepeatContextSupport(null), new RuntimeException("foo")); } catch (RuntimeException expected) { fail("Unexpected exception."); } } /** * TransactionInvalidException should only be rethrown below the exception * limit. * * @throws Exception */ @Test public void testLimitedExceptionNotThrownFromSiblings() throws Throwable { Throwable throwable = new RuntimeException("foo"); final int MORE_THAN_ZERO = 1; handler.setLimit(MORE_THAN_ZERO); handler.setExceptionClasses(Collections.<Class<? extends Throwable>> singleton(RuntimeException.class)); handler.afterPropertiesSet(); RepeatContextSupport parent = new RepeatContextSupport(null); try { RepeatContextSupport context = new RepeatContextSupport(parent); handler.handleException(context, throwable); context = new RepeatContextSupport(parent); handler.handleException(context, throwable); } catch (RuntimeException expected) { fail("Unexpected exception."); } } /** * TransactionInvalidException should only be rethrown below the exception * limit. * * @throws Exception */ @Test public void testLimitedExceptionThrownFromSiblingsWhenUsingParent() throws Throwable { Throwable throwable = new RuntimeException("foo"); final int MORE_THAN_ZERO = 1; handler.setLimit(MORE_THAN_ZERO); handler.setExceptionClasses(Collections.<Class<? extends Throwable>> singleton(RuntimeException.class)); handler.setUseParent(true); handler.afterPropertiesSet(); RepeatContextSupport parent = new RepeatContextSupport(null); try { RepeatContextSupport context = new RepeatContextSupport(parent); handler.handleException(context, throwable); context = new RepeatContextSupport(parent); handler.handleException(context, throwable); fail("Expected exception."); } catch (RuntimeException expected) { assertSame(throwable, expected); } } /** * Exceptions are swallowed until the exception limit is exceeded. After the * limit is exceeded exceptions are rethrown */ @Test public void testExceptionNotThrownBelowLimit() throws Throwable { final int EXCEPTION_LIMIT = 3; handler.setLimit(EXCEPTION_LIMIT); handler.afterPropertiesSet(); @SuppressWarnings("serial") List<Throwable> throwables = new ArrayList<Throwable>() { { for (int i = 0; i < (EXCEPTION_LIMIT); i++) { add(new RuntimeException("below exception limit")); } } }; RepeatContextSupport context = new RepeatContextSupport(null); try { for (Throwable throwable : throwables) { handler.handleException(context, throwable); assertTrue("exceptions up to limit are swallowed", true); } } catch (RuntimeException unexpected) { fail("exception rethrown although exception limit was not exceeded"); } } /** * TransactionInvalidExceptions are swallowed until the exception limit is * exceeded. After the limit is exceeded exceptions are rethrown as * BatchCriticalExceptions */ @Test public void testExceptionThrownAboveLimit() throws Throwable { final int EXCEPTION_LIMIT = 3; handler.setLimit(EXCEPTION_LIMIT); handler.afterPropertiesSet(); @SuppressWarnings("serial") List<Throwable> throwables = new ArrayList<Throwable>() { { for (int i = 0; i < (EXCEPTION_LIMIT); i++) { add(new RuntimeException("below exception limit")); } } }; throwables.add(new RuntimeException("above exception limit")); RepeatContextSupport context = new RepeatContextSupport(null); try { for (Throwable throwable : throwables) { handler.handleException(context, throwable); assertTrue("exceptions up to limit are swallowed", true); } } catch (RuntimeException expected) { assertEquals("above exception limit", expected.getMessage()); } // after reaching the limit, behaviour should be idempotent try { handler.handleException(context, new RuntimeException("foo")); assertTrue("exceptions up to limit are swallowed", true); } catch (RuntimeException expected) { assertEquals("foo", expected.getMessage()); } } }