/* * 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.config.spring.factories; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.not; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.withSettings; import static org.mule.runtime.core.api.lifecycle.LifecycleUtils.setMuleContextIfNeeded; import org.mule.runtime.api.exception.MuleException; import org.mule.runtime.api.exception.MuleRuntimeException; import org.mule.runtime.core.api.Event; import org.mule.runtime.core.api.MuleContext; import org.mule.runtime.core.api.construct.Flow; import org.mule.runtime.core.api.construct.FlowConstruct; import org.mule.runtime.core.api.construct.FlowConstructAware; import org.mule.runtime.core.api.context.MuleContextAware; import org.mule.runtime.core.api.el.ExtendedExpressionManager; import org.mule.runtime.api.lifecycle.Disposable; import org.mule.runtime.api.lifecycle.Initialisable; import org.mule.runtime.api.lifecycle.InitialisationException; import org.mule.runtime.core.api.processor.MessageProcessorChain; import org.mule.runtime.core.api.processor.Processor; import org.mule.runtime.core.exception.MessagingException; import org.mule.runtime.core.processor.chain.SubFlowMessageProcessor; import org.mule.tck.junit4.AbstractMuleContextTestCase; import org.mule.tck.size.SmallTest; import java.util.Arrays; import org.junit.Before; import org.junit.Test; import org.mockito.MockSettings; import org.springframework.context.ApplicationContext; @SmallTest public class FlowRefFactoryBeanTestCase extends AbstractMuleContextTestCase { private static final MockSettings INITIALIZABLE_MESSAGE_PROCESSOR = withSettings().extraInterfaces(Processor.class, Initialisable.class, Disposable.class); private static final String STATIC_REFERENCED_FLOW = "staticReferencedFlow"; private static final String DYNAMIC_REFERENCED_FLOW = "dynamicReferencedFlow"; private static final String PARSED_DYNAMIC_REFERENCED_FLOW = "parsedDynamicReferencedFlow"; private static final String DYNAMIC_NON_EXISTANT = "#[mel:'nonExistant']"; private static final String NON_EXISTANT = "nonExistant"; private Event result = testEvent(); private Flow targetFlow = mock(Flow.class, INITIALIZABLE_MESSAGE_PROCESSOR); private Processor targetSubFlow = mock(SubFlowMessageProcessor.class, INITIALIZABLE_MESSAGE_PROCESSOR); private ApplicationContext applicationContext = mock(ApplicationContext.class); private ExtendedExpressionManager expressionManager; private MuleContext mockMuleContext; public FlowRefFactoryBeanTestCase() throws MuleException {} @Before public void setup() throws MuleException { expressionManager = spy(muleContext.getExpressionManager()); mockMuleContext = spy(muleContext); doReturn(expressionManager).when(mockMuleContext).getExpressionManager(); doReturn(true).when(expressionManager).isExpression(anyString()); when(((Processor) targetFlow).process(any(Event.class))).thenReturn(result); when(targetSubFlow.process(any(Event.class))).thenReturn(result); } @Test public void staticFlowRefFlow() throws Exception { // Flow is wrapped to prevent lifecycle propagation FlowRefFactoryBean flowRefFactoryBean = createStaticFlowRefFactoryBean((Processor) targetFlow); assertNotSame(targetFlow, getFlowRefProcessor(flowRefFactoryBean)); assertNotSame(targetFlow, getFlowRefProcessor(flowRefFactoryBean)); verifyProcess(flowRefFactoryBean, (Processor) targetFlow, 0); } @Test public void dynamicFlowRefFlow() throws Exception { // Inner MessageProcessor is used to resolve MP in runtime FlowRefFactoryBean flowRefFactoryBean = createDynamicFlowRefFactoryBean((Processor) targetFlow); assertNotSame(targetFlow, getFlowRefProcessor(flowRefFactoryBean)); assertNotSame(targetFlow, getFlowRefProcessor(flowRefFactoryBean)); verifyProcess(flowRefFactoryBean, (Processor) targetFlow, 0); } @Test public void staticFlowRefSubFlow() throws Exception { FlowRefFactoryBean flowRefFactoryBean = createStaticFlowRefFactoryBean(targetSubFlow); // Processor is wrapped by factory bean implementation assertThat(targetSubFlow, not(equalTo(getFlowRefProcessor(flowRefFactoryBean)))); assertThat(targetSubFlow, not(equalTo(getFlowRefProcessor(flowRefFactoryBean)))); verifyProcess(flowRefFactoryBean, targetSubFlow, 0); } @Test public void dynamicFlowRefSubFlow() throws Exception { FlowRefFactoryBean flowRefFactoryBean = createDynamicFlowRefFactoryBean(targetSubFlow); // Inner MessageProcessor is used to resolve MP in runtime assertNotSame(targetSubFlow, getFlowRefProcessor(flowRefFactoryBean)); assertNotSame(targetSubFlow, getFlowRefProcessor(flowRefFactoryBean)); verifyProcess(flowRefFactoryBean, targetSubFlow, 1); } @Test public void dynamicFlowRefSubFlowConstructAware() throws Exception { FlowConstruct flowConstruct = mock(FlowConstruct.class); Event event = testEvent(); FlowConstructAware targetSubFlowConstructAware = mock(FlowConstructAware.class, INITIALIZABLE_MESSAGE_PROCESSOR); when(((Processor) targetSubFlowConstructAware).process(any(Event.class))).thenReturn(result); FlowRefFactoryBean flowRefFactoryBean = createDynamicFlowRefFactoryBean((Processor) targetSubFlowConstructAware); final Processor flowRefProcessor = getFlowRefProcessor(flowRefFactoryBean); ((FlowConstructAware) flowRefProcessor).setFlowConstruct(flowConstruct); assertSame(result.getMessage(), flowRefProcessor.process(event).getMessage()); verify(targetSubFlowConstructAware).setFlowConstruct(flowConstruct); } @Test public void dynamicFlowRefSubContextAware() throws Exception { Event event = testEvent(); MuleContextAware targetMuleContextAwareAware = mock(MuleContextAware.class, INITIALIZABLE_MESSAGE_PROCESSOR); when(((Processor) targetMuleContextAwareAware).process(any(Event.class))).thenReturn(result); FlowRefFactoryBean flowRefFactoryBean = createDynamicFlowRefFactoryBean((Processor) targetMuleContextAwareAware); assertSame(result.getMessage(), getFlowRefProcessor(flowRefFactoryBean).process(event).getMessage()); verify(targetMuleContextAwareAware).setMuleContext(mockMuleContext); } @Test public void dynamicFlowRefSubFlowMessageProcessorChain() throws Exception { FlowConstruct flowConstruct = mock(FlowConstruct.class); Event event = testEvent(); Processor targetSubFlowConstructAware = (Processor) mock(FlowConstructAware.class, INITIALIZABLE_MESSAGE_PROCESSOR); when(targetSubFlowConstructAware.process(any(Event.class))).thenReturn(result); Processor targetMuleContextAwareAware = (Processor) mock(MuleContextAware.class, INITIALIZABLE_MESSAGE_PROCESSOR); when(targetMuleContextAwareAware.process(any(Event.class))).thenReturn(result); MessageProcessorChain targetSubFlowChain = mock(MessageProcessorChain.class, INITIALIZABLE_MESSAGE_PROCESSOR); when(targetSubFlowChain.process(any(Event.class))).thenReturn(result); when(targetSubFlowChain.getMessageProcessors()) .thenReturn(Arrays.asList(targetSubFlowConstructAware, targetMuleContextAwareAware)); FlowRefFactoryBean flowRefFactoryBean = createDynamicFlowRefFactoryBean(targetSubFlowChain); final Processor flowRefProcessor = getFlowRefProcessor(flowRefFactoryBean); ((FlowConstructAware) flowRefProcessor).setFlowConstruct(flowConstruct); flowRefProcessor.process(event); verify((FlowConstructAware) targetSubFlowConstructAware).setFlowConstruct(flowConstruct); verify((MuleContextAware) targetMuleContextAwareAware).setMuleContext(mockMuleContext); } @Test(expected = MuleRuntimeException.class) public void staticFlowRefDoesNotExist() throws Exception { doReturn(false).when(expressionManager).isExpression(anyString()); getFlowRefProcessor(createFlowRefFactoryBean(NON_EXISTANT)); } private Processor getFlowRefProcessor(FlowRefFactoryBean factoryBean) throws Exception { Processor processor = factoryBean.getObject(); setMuleContextIfNeeded(processor, mockMuleContext); return processor; } @Test(expected = MessagingException.class) public void dynamicFlowRefDoesNotExist() throws Exception { doReturn(true).when(expressionManager).isExpression(anyString()); doReturn("other").when(expressionManager).parse(eq(DYNAMIC_NON_EXISTANT), any(Event.class), any(FlowConstruct.class)); getFlowRefProcessor(createFlowRefFactoryBean(DYNAMIC_NON_EXISTANT)).process(testEvent()); } private FlowRefFactoryBean createFlowRefFactoryBean(String name) throws InitialisationException { FlowRefFactoryBean flowRefFactoryBean = new FlowRefFactoryBean(); flowRefFactoryBean.setName(name); flowRefFactoryBean.setApplicationContext(applicationContext); flowRefFactoryBean.setMuleContext(mockMuleContext); flowRefFactoryBean.initialise(); return flowRefFactoryBean; } private FlowRefFactoryBean createStaticFlowRefFactoryBean(Processor target) throws InitialisationException { doReturn(false).when(expressionManager).isExpression(anyString()); when(applicationContext.getBean(eq(STATIC_REFERENCED_FLOW))).thenReturn(target); return createFlowRefFactoryBean(STATIC_REFERENCED_FLOW); } private FlowRefFactoryBean createDynamicFlowRefFactoryBean(Processor target) throws InitialisationException { doReturn(true).when(expressionManager).isExpression(anyString()); doReturn(PARSED_DYNAMIC_REFERENCED_FLOW).when(expressionManager).parse(eq(DYNAMIC_REFERENCED_FLOW), any(Event.class), any(FlowConstruct.class)); when(applicationContext.getBean(eq(PARSED_DYNAMIC_REFERENCED_FLOW))).thenReturn(target); return createFlowRefFactoryBean(DYNAMIC_REFERENCED_FLOW); } private void verifyProcess(FlowRefFactoryBean flowRefFactoryBean, Processor target, int lifecycleRounds) throws Exception { assertSame(result.getMessage(), getFlowRefProcessor(flowRefFactoryBean).process(testEvent()).getMessage()); assertSame(result.getMessage(), getFlowRefProcessor(flowRefFactoryBean).process(testEvent()).getMessage()); verify(applicationContext).getBean(anyString()); verify(target, times(2)).process(any(Event.class)); verify((Initialisable) target, times(lifecycleRounds)).initialise(); flowRefFactoryBean.dispose(); verify((Disposable) target, times(lifecycleRounds)).dispose(); } }