View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.endpoint.outbound;
8   
9   import static edu.emory.mathcs.backport.java.util.concurrent.TimeUnit.MILLISECONDS;
10  import static org.junit.Assert.assertEquals;
11  import static org.junit.Assert.assertNotNull;
12  import static org.junit.Assert.assertNotSame;
13  import static org.junit.Assert.assertNull;
14  import static org.junit.Assert.assertTrue;
15  import static org.mockito.Mockito.mock;
16  import static org.mockito.Mockito.times;
17  import static org.mockito.Mockito.verify;
18  import static org.mockito.Mockito.when;
19  import org.mule.MessageExchangePattern;
20  import org.mule.api.MuleEvent;
21  import org.mule.api.MuleException;
22  import org.mule.api.MuleMessage;
23  import org.mule.api.config.MuleProperties;
24  import org.mule.api.endpoint.EndpointBuilder;
25  import org.mule.api.endpoint.OutboundEndpoint;
26  import org.mule.api.registry.ServiceException;
27  import org.mule.api.registry.ServiceType;
28  import org.mule.api.routing.filter.Filter;
29  import org.mule.api.security.SecurityFilter;
30  import org.mule.api.transaction.TransactionConfig;
31  import org.mule.api.transformer.Transformer;
32  import org.mule.api.transport.MessageDispatcher;
33  import org.mule.context.notification.EndpointMessageNotification;
34  import org.mule.context.notification.SecurityNotification;
35  import org.mule.endpoint.AbstractMessageProcessorTestCase;
36  import org.mule.endpoint.DynamicOutboundEndpoint;
37  import org.mule.tck.probe.PollingProber;
38  import org.mule.tck.probe.Probe;
39  import org.mule.tck.probe.Prober;
40  import org.mule.tck.security.TestSecurityFilter;
41  import org.mule.tck.testmodels.mule.TestMessageDispatcher;
42  import org.mule.tck.testmodels.mule.TestMessageDispatcherFactory;
43  import org.mule.transformer.simple.OutboundAppendTransformer;
44  import org.mule.transformer.simple.ResponseAppendTransformer;
45  import org.mule.transport.service.DefaultTransportServiceDescriptor;
46  
47  import java.util.Properties;
48  
49  import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
50  import org.junit.Before;
51  import org.junit.Test;
52  
53  /**
54   * Tests flow of messages from {@link org.mule.endpoint.DynamicOutboundEndpoint#process(org.mule.api.MuleEvent)} down to
55   * {@link org.mule.transport.AbstractMessageDispatcher} and the chain of MessageProcessor's that
56   * implement the outbound endpoint processing.
57   */
58  public class DynamicOutboundEndpointTestCase extends AbstractMessageProcessorTestCase
59  {
60  
61      private MuleEvent testOutboundEvent;
62  
63      @Before
64      public void setCurrentTestInstance() throws ServiceException
65      {
66          overrideDispatcherInServiceDescriptor();
67          MyMessageDispatcherFactory.dispatcher = null;
68      }
69  
70      @Test
71      public void testDefaultFlowRequestResponse() throws Exception
72      {
73          OutboundEndpoint endpoint = createOutboundEndpoint(null, null, null, null, MessageExchangePattern.REQUEST_RESPONSE, null);
74          testOutboundEvent = createTestOutboundEvent(endpoint);
75  
76          MuleEvent result = endpoint.process(testOutboundEvent);
77  
78          assertEventSent();
79  
80          // Response message is not the same because we rewrite the response event and
81          // this change the properties
82          // (See: OutboundRewriteResponseEventMessageProcessor)
83          assertNotSame(responseMessage, result.getMessage());
84  
85          // Everything else about the message apart from addition of encoding property
86          // is the same though
87          assertMessageEqualEncodingPropertyAdded(responseMessage, result.getMessage());
88      }
89  
90      @Test
91      public void testDefaultFlowOneWay() throws Exception
92      {
93          OutboundEndpoint endpoint = createOutboundEndpoint(null, null, null, null, MessageExchangePattern.ONE_WAY, null);
94          assertTrue(endpoint instanceof DynamicOutboundEndpoint);
95  
96          testOutboundEvent = createTestOutboundEvent(endpoint);
97  
98          MuleEvent result = endpoint.process(testOutboundEvent);
99  
100         assertEventDispatched();
101         assertNull(result);
102         assertMessageSentEqual(MyMessageDispatcherFactory.dispatcher.sensedDispatchEvent);
103     }
104 
105     @Test
106     public void testSecurityFilterAccept() throws Exception
107     {
108         OutboundEndpoint endpoint = createOutboundEndpoint(null, new TestSecurityFilter(true), null, null, MessageExchangePattern.REQUEST_RESPONSE, null);
109         testOutboundEvent = createTestOutboundEvent(endpoint);
110 
111         MuleEvent result = endpoint.process(testOutboundEvent);
112 
113         assertEventSent();
114         assertMessageSentEqual(MyMessageDispatcherFactory.dispatcher.sensedSendEvent);
115 
116         // Response message is not the same because we rewrite the response event and
117         // this change the properties
118         // (See: OutboundRewriteResponseEventMessageProcessor)
119         assertNotSame(responseMessage, result.getMessage());
120 
121         // Everything else about the message apart from addition of encoding property
122         // is the same though
123         assertMessageEqualEncodingPropertyAdded(responseMessage, result.getMessage());
124     }
125 
126     @Test
127     public void testSecurityFilterNotAccept() throws Exception
128     {
129         TestSecurityNotificationListener securityNotificationListener = new TestSecurityNotificationListener();
130         muleContext.registerListener(securityNotificationListener);
131 
132         OutboundEndpoint endpoint = createOutboundEndpoint(null, new TestSecurityFilter(false), null, null, MessageExchangePattern.REQUEST_RESPONSE, null);
133         testOutboundEvent = createTestOutboundEvent(endpoint);
134 
135         MuleEvent result = endpoint.process(testOutboundEvent);
136 
137         assertNull(MyMessageDispatcherFactory.dispatcher);
138         assertNotNull(result);
139         assertEquals(TestSecurityFilter.SECURITY_EXCEPTION_MESSAGE, result.getMessage().getPayloadAsString());
140         assertNotNull(result.getMessage().getExceptionPayload());
141         assertTrue(result.getMessage().getExceptionPayload().getException() instanceof TestSecurityFilter.StaticMessageUnauthorisedException);
142 
143         assertTrue(securityNotificationListener.latch.await(RECEIVE_TIMEOUT, MILLISECONDS));
144         assertEquals(SecurityNotification.SECURITY_AUTHENTICATION_FAILED,
145                      securityNotificationListener.securityNotification.getAction());
146         assertEquals(securityNotificationListener.securityNotification.getResourceIdentifier(),
147                      TestSecurityFilter.StaticMessageUnauthorisedException.class.getName());
148     }
149 
150     @Test
151     public void testSendNotification() throws Exception
152     {
153         TestEndpointMessageNotificationListener listener = new TestEndpointMessageNotificationListener();
154         muleContext.registerListener(listener);
155 
156         OutboundEndpoint endpoint = createOutboundEndpoint(null, null, null, null, MessageExchangePattern.REQUEST_RESPONSE, null);
157         MuleEvent outboundEvent = createTestOutboundEvent(endpoint);
158 
159         endpoint.process(outboundEvent);
160 
161         assertEventSent();
162         assertTrue(listener.latch.await(RECEIVE_TIMEOUT, TimeUnit.MILLISECONDS));
163         assertEquals(EndpointMessageNotification.MESSAGE_SENT, listener.messageNotification.getAction());
164         assertTrue(listener.messageNotification.getSource() instanceof MuleMessage);
165         assertEquals(outboundEvent.getMessage().getPayload(), listener.messageNotification.getSource().getPayload());
166     }
167 
168     @Test
169     public void testDispatchNotification() throws Exception
170     {
171         TestEndpointMessageNotificationListener listener = new TestEndpointMessageNotificationListener();
172         muleContext.registerListener(listener);
173 
174         OutboundEndpoint endpoint = createOutboundEndpoint(null, null, null, null, MessageExchangePattern.ONE_WAY, null);
175         MuleEvent outboundEvent = createTestOutboundEvent(endpoint);
176 
177         endpoint.process(outboundEvent);
178 
179         assertEventDispatched();
180         assertTrue(listener.latch.await(RECEIVE_TIMEOUT, TimeUnit.MILLISECONDS));
181         assertEquals(EndpointMessageNotification.MESSAGE_DISPATCHED, listener.messageNotification.getAction());
182         assertTrue(listener.messageNotification.getSource() instanceof MuleMessage);
183         assertEquals(outboundEvent.getMessage().getPayload(), listener.messageNotification.getSource().getPayload());
184     }
185 
186     @Test
187     public void testTransformers() throws Exception
188     {
189         OutboundEndpoint endpoint = createOutboundEndpoint(null, null, new OutboundAppendTransformer(),
190                                                            new ResponseAppendTransformer(), MessageExchangePattern.REQUEST_RESPONSE, null);
191 
192         testOutboundEvent = createTestOutboundEvent(endpoint);
193 
194         MuleEvent result = endpoint.process(testOutboundEvent);
195 
196         assertNotNull(result);
197         assertEquals(TEST_MESSAGE + OutboundAppendTransformer.APPEND_STRING, MyMessageDispatcherFactory.dispatcher.sensedSendEvent.getMessageAsString());
198         assertEquals(RESPONSE_MESSAGE + ResponseAppendTransformer.APPEND_STRING, result.getMessageAsString());
199     }
200 
201     @Test(expected = UnsupportedOperationException.class)
202     public void testConnectorNotAvailableOnDynamicEndpoint() throws Exception
203     {
204         OutboundEndpoint endpoint = createOutboundEndpoint(null, null, null, null, MessageExchangePattern.REQUEST_RESPONSE, null);
205 
206         endpoint.getConnector();
207     }
208 
209     @Test
210     public void testTimeoutSetOnEvent() throws Exception
211     {
212         int testTimeout = 999;
213 
214         OutboundEndpoint endpoint = createOutboundEndpoint(null, null, null, null, MessageExchangePattern.REQUEST_RESPONSE, null);
215 
216         testOutboundEvent = createTestOutboundEvent(endpoint);
217         testOutboundEvent.getMessage().setOutboundProperty(MuleProperties.MULE_EVENT_TIMEOUT_PROPERTY, testTimeout);
218 
219         MuleEvent response = endpoint.process(testOutboundEvent);
220 
221         assertEquals(testTimeout, response.getTimeout());
222     }
223 
224     @Test
225     public void testTransaction()
226     {
227         // TODO
228     }
229 
230     @Test
231     public void testExceptionHandling()
232     {
233         // TODO
234     }
235 
236     @Test
237     public void cachesResolvedStaticEndpoints() throws Exception
238     {
239         OutboundEndpoint prototypeEndpoint = mock(OutboundEndpoint.class);
240         when(prototypeEndpoint.getMuleContext()).thenReturn(muleContext);
241 
242         EndpointBuilder staticEndpointBuilder = mock(EndpointBuilder.class);
243         when(staticEndpointBuilder.buildOutboundEndpoint()).thenReturn(prototypeEndpoint);
244 
245         EndpointBuilder endpointBuilder = mock(EndpointBuilder.class);
246         when(endpointBuilder.buildOutboundEndpoint()).thenReturn(prototypeEndpoint);
247         when(endpointBuilder.clone()).thenReturn(staticEndpointBuilder);
248 
249         DynamicOutboundEndpoint dynamicOutboundEndpoint = new DynamicOutboundEndpoint(endpointBuilder, "test://localhost:#[header:port]");
250 
251         testOutboundEvent = createTestOutboundEvent(dynamicOutboundEndpoint);
252         dynamicOutboundEndpoint.process(testOutboundEvent);
253         dynamicOutboundEndpoint.process(testOutboundEvent);
254 
255         verify(endpointBuilder, times(1)).buildOutboundEndpoint();
256     }
257 
258     protected void assertMessageSentEqual(MuleEvent event) throws MuleException
259     {
260         assertEquals(TEST_MESSAGE, event.getMessageAsString());
261         assertEquals("value1", event.getMessage().getOutboundProperty("prop1"));
262     }
263 
264     protected void assertMessageEqualEncodingPropertyAdded(MuleMessage expect, MuleMessage actual)
265     {
266         assertEquals(expect.getPayload(), actual.getPayload());
267         assertEquals(expect.getEncoding(), actual.getEncoding());
268         assertEquals(expect.getUniqueId(), actual.getUniqueId());
269         assertEquals(expect.getExceptionPayload(), actual.getExceptionPayload());
270 
271         assertEquals(muleContext.getConfiguration().getDefaultEncoding(),
272                      actual.getOutboundProperty(MuleProperties.MULE_ENCODING_PROPERTY));
273 
274     }
275 
276     private void assertEventDispatched()
277     {
278         Prober prober = new PollingProber();
279         prober.check(new Probe()
280         {
281             public boolean isSatisfied()
282             {
283                 return MyMessageDispatcherFactory.dispatcher != null && MyMessageDispatcherFactory.dispatcher.dispatchedEvent;
284             }
285 
286             public String describeFailure()
287             {
288                 return "Expected dispatcher was not called";
289             }
290         });
291 
292         assertNull(MyMessageDispatcherFactory.dispatcher.sensedSendEvent);
293         assertNotNull(MyMessageDispatcherFactory.dispatcher.sensedDispatchEvent);
294         assertNotNull(MyMessageDispatcherFactory.dispatcher.sensedDispatchEvent.getMessage());
295     }
296 
297     private void assertEventSent()
298     {
299         Prober prober = new PollingProber();
300         prober.check(new Probe()
301         {
302             public boolean isSatisfied()
303             {
304                 return MyMessageDispatcherFactory.dispatcher != null && MyMessageDispatcherFactory.dispatcher.sentEvent;
305             }
306 
307             public String describeFailure()
308             {
309                 return "Expected dispatcher was not called";
310             }
311         });
312 
313         assertNull(MyMessageDispatcherFactory.dispatcher.sensedDispatchEvent);
314         assertNotNull(MyMessageDispatcherFactory.dispatcher.sensedSendEvent);
315         assertNotNull(MyMessageDispatcherFactory.dispatcher.sensedSendEvent.getMessage());
316     }
317 
318     private void overrideDispatcherInServiceDescriptor() throws ServiceException
319     {
320         Properties props = new Properties();
321         props.put(MuleProperties.CONNECTOR_DISPATCHER_FACTORY, MyMessageDispatcherFactory.class.getName());
322         DefaultTransportServiceDescriptor serviceDescriptor = (DefaultTransportServiceDescriptor) muleContext.getRegistry().lookupServiceDescriptor(ServiceType.TRANSPORT, "test", null);
323         props.put(MuleProperties.CONNECTOR_INBOUND_EXCHANGE_PATTERNS, "ONE_WAY, REQUEST_RESPONSE");
324         props.put(MuleProperties.CONNECTOR_OUTBOUND_EXCHANGE_PATTERNS, "ONE_WAY, REQUEST_RESPONSE");
325         serviceDescriptor.setOverrides(props);
326     }
327 
328     protected OutboundEndpoint createOutboundEndpoint(Filter filter,
329                                                       SecurityFilter securityFilter,
330                                                       Transformer in,
331                                                       Transformer response,
332                                                       MessageExchangePattern exchangePattern,
333                                                       TransactionConfig txConfig) throws Exception
334     {
335 
336         return createTestOutboundEndpoint("test://localhost:#[header:port]", filter, securityFilter, in, response,
337                                           exchangePattern, txConfig);
338     }
339 
340     private static class FakeMessageDispatcher extends TestMessageDispatcher
341     {
342 
343         private MuleEvent sensedSendEvent;
344         private MuleEvent sensedDispatchEvent;
345         private boolean sentEvent;
346         private boolean dispatchedEvent;
347 
348         public FakeMessageDispatcher(OutboundEndpoint endpoint)
349         {
350             super(endpoint);
351         }
352 
353         @Override
354         protected MuleMessage doSend(MuleEvent event) throws Exception
355         {
356             sensedSendEvent = event;
357             sentEvent = true;
358             return responseMessage;
359         }
360 
361         @Override
362         protected void doDispatch(MuleEvent event) throws Exception
363         {
364             sensedDispatchEvent = event;
365             dispatchedEvent = true;
366         }
367     }
368 
369     public static class MyMessageDispatcherFactory extends TestMessageDispatcherFactory
370     {
371 
372         static FakeMessageDispatcher dispatcher;
373 
374         @Override
375         public synchronized MessageDispatcher create(OutboundEndpoint ep) throws MuleException
376         {
377             if (dispatcher != null)
378             {
379                 throw new IllegalStateException("Dispatcher for this test was already created");
380             }
381 
382             dispatcher = new FakeMessageDispatcher(ep);
383             return dispatcher;
384         }
385     }
386 }