/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.runtime.core.exception; import static org.mule.runtime.core.exception.ErrorTypeRepository.CRITICAL_ERROR_TYPE; import static org.mule.test.allure.AllureConstants.ErrorHandlingFeature.ERROR_HANDLING; import static org.mule.test.allure.AllureConstants.ErrorHandlingFeature.ErrorHandlingStory.ERROR_HANDLER; import static java.util.Arrays.asList; import static java.util.Optional.of; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.internal.verification.VerificationModeFactory.times; import static reactor.core.publisher.Mono.just; import org.mule.runtime.api.exception.MuleException; import org.mule.runtime.api.exception.MuleRuntimeException; import org.mule.runtime.api.message.Error; import org.mule.runtime.api.message.ErrorType; import org.mule.runtime.api.message.Message; import org.mule.runtime.core.api.Event; import org.mule.runtime.core.api.MuleContext; import org.mule.runtime.core.api.exception.MessagingExceptionHandlerAcceptor; import org.mule.tck.junit4.AbstractMuleTestCase; import org.mule.tck.size.SmallTest; import java.util.ArrayList; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import ru.yandex.qatools.allure.annotations.Features; import ru.yandex.qatools.allure.annotations.Stories; @SmallTest @Features(ERROR_HANDLING) @Stories(ERROR_HANDLER) @RunWith(MockitoJUnitRunner.class) public class ErrorHandlerTestCase extends AbstractMuleTestCase { @Mock private MessagingExceptionHandlerAcceptor mockTestExceptionStrategy1; @Mock private MessagingExceptionHandlerAcceptor mockTestExceptionStrategy2; private DefaultMessagingExceptionHandlerAcceptor defaultMessagingExceptionHandler = spy(new DefaultMessagingExceptionHandlerAcceptor()); @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Event mockMuleEvent; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private MuleContext mockMuleContext; @Mock private ErrorType mockErrorType; private MessagingException mockException; @Before public void before() throws MuleException { when(mockMuleEvent.getMessage()).thenReturn(Message.of("")); when(mockMuleEvent.getMuleContext()).thenReturn(mockMuleContext); Error mockError = mock(Error.class); when(mockError.getErrorType()).thenReturn(mockErrorType); when(mockMuleEvent.getError()).thenReturn(of(mockError)); mockException = new MessagingException(mockMuleEvent, new Exception()); Event handledEvent = testEvent(); when(mockTestExceptionStrategy1.accept(any(Event.class))).thenReturn(true); when(mockTestExceptionStrategy1.apply(any(MessagingException.class))).thenReturn(just(handledEvent)); when(mockTestExceptionStrategy2.accept(any(Event.class))).thenReturn(true); when(mockTestExceptionStrategy2.apply(any(MessagingException.class))).thenReturn(just(handledEvent)); } @Test public void nonMatchThenCallDefault() throws Exception { ErrorHandler errorHandler = new ErrorHandler(); when(mockMuleContext.getDefaultErrorHandler()).thenReturn(defaultMessagingExceptionHandler); errorHandler.setExceptionListeners(new ArrayList<>(asList(mockTestExceptionStrategy1, mockTestExceptionStrategy2))); errorHandler.setMuleContext(mockMuleContext); errorHandler.initialise(); when(mockTestExceptionStrategy1.accept(any(Event.class))).thenReturn(false); when(mockTestExceptionStrategy2.accept(any(Event.class))).thenReturn(false); errorHandler.handleException(mockException, mockMuleEvent); verify(mockTestExceptionStrategy1, times(0)).apply(any(MessagingException.class)); verify(mockTestExceptionStrategy2, times(0)).apply(any(MessagingException.class)); verify(defaultMessagingExceptionHandler, times(1)).handleException(eq(mockException), any(Event.class)); } @Test public void secondMatches() throws Exception { ErrorHandler errorHandler = new ErrorHandler(); errorHandler.setExceptionListeners(new ArrayList<>(asList(mockTestExceptionStrategy1, mockTestExceptionStrategy2))); when(mockMuleContext.getDefaultErrorHandler()).thenReturn(defaultMessagingExceptionHandler); errorHandler.setMuleContext(mockMuleContext); errorHandler.initialise(); when(mockTestExceptionStrategy1.accept(any(Event.class))).thenReturn(false); errorHandler.handleException(mockException, mockMuleEvent); verify(mockTestExceptionStrategy1, times(0)).apply(any(MessagingException.class)); verify(defaultMessagingExceptionHandler, times(0)).apply(any(MessagingException.class)); verify(mockTestExceptionStrategy2, times(1)).handleException(eq(mockException), any(Event.class)); } @Test(expected = MuleRuntimeException.class) public void firstAcceptsAllMatches() throws Exception { ErrorHandler errorHandler = new ErrorHandler(); errorHandler.setExceptionListeners(new ArrayList<>(asList(mockTestExceptionStrategy1, mockTestExceptionStrategy2))); errorHandler.setMuleContext(mockMuleContext); when(mockMuleContext.getDefaultErrorHandler()).thenReturn(defaultMessagingExceptionHandler); when(mockTestExceptionStrategy1.acceptsAll()).thenReturn(true); when(mockTestExceptionStrategy2.acceptsAll()).thenReturn(false); errorHandler.initialise(); } @Test public void criticalIsNotHandled() throws Exception { when(mockErrorType.getParentErrorType()).thenReturn(CRITICAL_ERROR_TYPE); ErrorHandler errorHandler = new ErrorHandler(); when(mockMuleContext.getDefaultErrorHandler()).thenReturn(defaultMessagingExceptionHandler); errorHandler.setExceptionListeners(new ArrayList<>(asList(mockTestExceptionStrategy1))); errorHandler.setMuleContext(mockMuleContext); errorHandler.initialise(); errorHandler.handleException(mockException, mockMuleEvent); verify(mockTestExceptionStrategy1, times(0)).apply(any(MessagingException.class)); verify(defaultMessagingExceptionHandler, times(0)).apply(any(MessagingException.class)); } class DefaultMessagingExceptionHandlerAcceptor implements MessagingExceptionHandlerAcceptor { @Override public boolean accept(Event event) { return true; } @Override public boolean acceptsAll() { return true; } @Override public Event handleException(MessagingException exception, Event event) { exception.setHandled(true); return event; } } }