001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.test.junit4;
018    
019    import java.io.File;
020    import java.util.Collection;
021    import java.util.List;
022    import java.util.Locale;
023    
024    import org.apache.camel.CamelContext;
025    import org.apache.camel.Channel;
026    import org.apache.camel.Endpoint;
027    import org.apache.camel.Exchange;
028    import org.apache.camel.Expression;
029    import org.apache.camel.InvalidPayloadException;
030    import org.apache.camel.Message;
031    import org.apache.camel.Predicate;
032    import org.apache.camel.Processor;
033    import org.apache.camel.Route;
034    import org.apache.camel.builder.Builder;
035    import org.apache.camel.builder.RouteBuilder;
036    import org.apache.camel.builder.ValueBuilder;
037    import org.apache.camel.impl.DefaultCamelContext;
038    import org.apache.camel.impl.DefaultExchange;
039    import org.apache.camel.processor.DelegateProcessor;
040    import org.apache.camel.util.ExchangeHelper;
041    import org.apache.camel.util.PredicateAssertHelper;
042    import org.junit.Assert;
043    import org.junit.Rule;
044    import org.junit.rules.TestName;
045    import org.slf4j.Logger;
046    import org.slf4j.LoggerFactory;
047    
048    /**
049     * A bunch of useful testing methods
050     *
051     * @version 
052     */
053    public abstract class TestSupport extends Assert {
054    
055        protected static final String LS = System.getProperty("line.separator");
056        private static final Logger LOG = LoggerFactory.getLogger(TestSupport.class);
057        protected transient Logger log = LoggerFactory.getLogger(getClass());
058    
059        // CHECKSTYLE:OFF
060        @Rule
061        public TestName testName = new TestName();
062        // CHECKSTYLE:ON
063    
064        // Builder methods for expressions used when testing
065        // -------------------------------------------------------------------------
066    
067        /**
068         * Returns a value builder for the given header
069         */
070        public static ValueBuilder header(String name) {
071            return Builder.header(name);
072        }
073    
074        /**
075         * Returns a value builder for the given property
076         */
077        public static ValueBuilder property(String name) {
078            return Builder.property(name);
079        }    
080        
081        /**
082         * Returns a predicate and value builder for the inbound body on an exchange
083         */
084        public static ValueBuilder body() {
085            return Builder.body();
086        }
087    
088        /**
089         * Returns a predicate and value builder for the inbound message body as a
090         * specific type
091         */
092        public static <T> ValueBuilder bodyAs(Class<T> type) {
093            return Builder.bodyAs(type);
094        }
095    
096        /**
097         * Returns a predicate and value builder for the outbound body on an
098         * exchange
099         */
100        public static ValueBuilder outBody() {
101            return Builder.outBody();
102        }
103    
104        /**
105         * Returns a predicate and value builder for the outbound message body as a
106         * specific type
107         */
108        public static <T> ValueBuilder outBodyAs(Class<T> type) {
109            return Builder.outBodyAs(type);
110        }
111    
112        /**
113         * Returns a predicate and value builder for the fault body on an
114         * exchange
115         */
116        public static ValueBuilder faultBody() {
117            return Builder.faultBody();
118        }
119    
120        /**
121         * Returns a predicate and value builder for the fault message body as a
122         * specific type
123         */
124        public static <T> ValueBuilder faultBodyAs(Class<T> type) {
125            return Builder.faultBodyAs(type);
126        }
127    
128        /**
129         * Returns a value builder for the given system property
130         */
131        public static ValueBuilder systemProperty(String name) {
132            return Builder.systemProperty(name);
133        }
134    
135        /**
136         * Returns a value builder for the given system property
137         */
138        public static ValueBuilder systemProperty(String name, String defaultValue) {
139            return Builder.systemProperty(name, defaultValue);
140        }
141    
142        // Assertions
143        // -----------------------------------------------------------------------
144    
145        public static <T> T assertIsInstanceOf(Class<T> expectedType, Object value) {
146            assertNotNull("Expected an instance of type: " + expectedType.getName() + " but was null", value);
147            assertTrue("object should be a " + expectedType.getName() + " but was: " + value + " with type: "
148                       + value.getClass().getName(), expectedType.isInstance(value));
149            return expectedType.cast(value);
150        }
151    
152        public static void assertEndpointUri(Endpoint endpoint, String uri) {
153            assertNotNull("Endpoint is null when expecting endpoint for: " + uri, endpoint);
154            assertEquals("Endoint uri for: " + endpoint, uri, endpoint.getEndpointUri());
155        }
156    
157        /**
158         * Asserts the In message on the exchange contains the expected value
159         */
160        public static Object assertInMessageHeader(Exchange exchange, String name, Object expected) {
161            return assertMessageHeader(exchange.getIn(), name, expected);
162        }
163    
164        /**
165         * Asserts the Out message on the exchange contains the expected value
166         */
167        public static Object assertOutMessageHeader(Exchange exchange, String name, Object expected) {
168            return assertMessageHeader(exchange.getOut(), name, expected);
169        }
170    
171        /**
172         * Asserts that the given exchange has an OUT message of the given body value
173         *
174         * @param exchange the exchange which should have an OUT message
175         * @param expected the expected value of the OUT message
176         * @throws InvalidPayloadException is thrown if the payload is not the expected class type
177         */
178        public static void assertInMessageBodyEquals(Exchange exchange, Object expected) throws InvalidPayloadException {
179            assertNotNull("Should have a response exchange!", exchange);
180    
181            Object actual;
182            if (expected == null) {
183                actual = ExchangeHelper.getMandatoryInBody(exchange);
184                assertEquals("in body of: " + exchange, expected, actual);
185            } else {
186                actual = ExchangeHelper.getMandatoryInBody(exchange, expected.getClass());
187            }
188            assertEquals("in body of: " + exchange, expected, actual);
189    
190            LOG.debug("Received response: " + exchange + " with in: " + exchange.getIn());
191        }
192    
193        /**
194         * Asserts that the given exchange has an OUT message of the given body value
195         *
196         * @param exchange the exchange which should have an OUT message
197         * @param expected the expected value of the OUT message
198         * @throws InvalidPayloadException is thrown if the payload is not the expected class type
199         */
200        public static void assertOutMessageBodyEquals(Exchange exchange, Object expected) throws InvalidPayloadException {
201            assertNotNull("Should have a response exchange!", exchange);
202    
203            Object actual;
204            if (expected == null) {
205                actual = ExchangeHelper.getMandatoryOutBody(exchange);
206                assertEquals("output body of: " + exchange, expected, actual);
207            } else {
208                actual = ExchangeHelper.getMandatoryOutBody(exchange, expected.getClass());
209            }
210            assertEquals("output body of: " + exchange, expected, actual);
211    
212            LOG.debug("Received response: " + exchange + " with out: " + exchange.getOut());
213        }
214    
215        public static Object assertMessageHeader(Message message, String name, Object expected) {
216            Object value = message.getHeader(name);
217            assertEquals("Header: " + name + " on Message: " + message, expected, value);
218            return value;
219        }
220    
221        /**
222         * Asserts that the given expression when evaluated returns the given answer
223         */
224        public static Object assertExpression(Expression expression, Exchange exchange, Object expected) {
225            Object value;
226            if (expected != null) {
227                value = expression.evaluate(exchange, expected.getClass());
228            } else {
229                value = expression.evaluate(exchange, Object.class);
230            }
231    
232            LOG.debug("Evaluated expression: " + expression + " on exchange: " + exchange + " result: " + value);
233    
234            assertEquals("Expression: " + expression + " on Exchange: " + exchange, expected, value);
235            return value;
236        }
237    
238        /**
239         * Asserts that the predicate returns the expected value on the exchange
240         */
241        public static void assertPredicateMatches(Predicate predicate, Exchange exchange) {
242            assertPredicate(predicate, exchange, true);
243        }
244    
245        /**
246         * Asserts that the predicate returns the expected value on the exchange
247         */
248        public static void assertPredicateDoesNotMatch(Predicate predicate, Exchange exchange) {
249            try {
250                PredicateAssertHelper.assertMatches(predicate, "Predicate should match: ", exchange);
251            } catch (AssertionError e) {
252                LOG.debug("Caught expected assertion error: " + e);
253            }
254            assertPredicate(predicate, exchange, false);
255        }
256    
257        /**
258         * Asserts that the predicate returns the expected value on the exchange
259         */
260        public static boolean assertPredicate(final Predicate predicate, Exchange exchange, boolean expected) {
261            if (expected) {
262                PredicateAssertHelper.assertMatches(predicate, "Predicate failed: ", exchange);
263            }
264            boolean value = predicate.matches(exchange);
265    
266            LOG.debug("Evaluated predicate: " + predicate + " on exchange: " + exchange + " result: " + value);
267    
268            assertEquals("Predicate: " + predicate + " on Exchange: " + exchange, expected, value);
269            return value;
270        }
271    
272        /**
273         * Resolves an endpoint and asserts that it is found
274         */
275        public static Endpoint resolveMandatoryEndpoint(CamelContext context, String uri) {
276            Endpoint endpoint = context.getEndpoint(uri);
277    
278            assertNotNull("No endpoint found for URI: " + uri, endpoint);
279    
280            return endpoint;
281        }
282    
283        /**
284         * Resolves an endpoint and asserts that it is found
285         */
286        public static <T extends Endpoint> T resolveMandatoryEndpoint(CamelContext context, String uri,
287                                                                  Class<T> endpointType) {
288            T endpoint = context.getEndpoint(uri, endpointType);
289    
290            assertNotNull("No endpoint found for URI: " + uri, endpoint);
291    
292            return endpoint;
293        }
294    
295        /**
296         * Creates an exchange with the given body
297         */
298        protected Exchange createExchangeWithBody(CamelContext camelContext, Object body) {
299            Exchange exchange = new DefaultExchange(camelContext);
300            Message message = exchange.getIn();        
301            message.setHeader("testClass", getClass().getName());
302            message.setBody(body);
303            return exchange;
304        }
305    
306        public static <T> T assertOneElement(List<T> list) {
307            assertEquals("Size of list should be 1: " + list, 1, list.size());
308            return list.get(0);
309        }
310    
311        /**
312         * Asserts that a list is of the given size
313         */
314        public static <T> List<T> assertListSize(List<T> list, int size) {
315            return assertListSize("List", list, size);
316        }
317    
318        /**
319         * Asserts that a list is of the given size
320         */
321        public static <T> List<T> assertListSize(String message, List<T> list, int size) {
322            assertEquals(message + " should be of size: "
323                    + size + " but is: " + list, size, list.size());
324            return list;
325        }
326    
327        /**
328         * Asserts that a list is of the given size
329         */
330        public static <T> Collection<T> assertCollectionSize(Collection<T> list, int size) {
331            return assertCollectionSize("List", list, size);
332        }
333    
334        /**
335         * Asserts that a list is of the given size
336         */
337        public static <T> Collection<T> assertCollectionSize(String message, Collection<T> list, int size) {
338            assertEquals(message + " should be of size: "
339                    + size + " but is: " + list, size, list.size());
340            return list;
341        }
342    
343        /**
344         * A helper method to create a list of Route objects for a given route builder
345         */
346        public static List<Route> getRouteList(RouteBuilder builder) throws Exception {
347            CamelContext context = new DefaultCamelContext();
348            context.addRoutes(builder);
349            context.start();
350            List<Route> answer = context.getRoutes();
351            context.stop();
352            return answer;
353        }
354    
355        /**
356         * Asserts that the text contains the given string
357         *
358         * @param text the text to compare
359         * @param containedText the text which must be contained inside the other text parameter
360         */
361        public static void assertStringContains(String text, String containedText) {
362            assertNotNull("Text should not be null!", text);
363            assertTrue("Text: " + text + " does not contain: " + containedText, text.contains(containedText));
364        }
365    
366        /**
367         * If a processor is wrapped with a bunch of DelegateProcessor or DelegateAsyncProcessor objects
368         * this call will drill through them and return the wrapped Processor.
369         */
370        public static Processor unwrap(Processor processor) {
371            while (true) {
372                if (processor instanceof DelegateProcessor) {
373                    processor = ((DelegateProcessor)processor).getProcessor();
374                } else {
375                    return processor;
376                }
377            }
378        }
379    
380        /**
381         * If a processor is wrapped with a bunch of DelegateProcessor or DelegateAsyncProcessor objects
382         * this call will drill through them and return the Channel.
383         * <p/>
384         * Returns null if no channel is found.
385         */
386        public static Channel unwrapChannel(Processor processor) {
387            while (true) {
388                if (processor instanceof Channel) {
389                    return (Channel) processor;
390                } else if (processor instanceof DelegateProcessor) {
391                    processor = ((DelegateProcessor)processor).getProcessor();
392                } else {
393                    return null;
394                }
395            }
396        }
397    
398        /**
399         * Recursively delete a directory, useful to zapping test data
400         *
401         * @param file the directory to be deleted
402         */
403        public static void deleteDirectory(String file) {
404            deleteDirectory(new File(file));
405        }
406    
407        /**
408         * Recursively delete a directory, useful to zapping test data
409         *
410         * @param file the directory to be deleted
411         */
412        public static void deleteDirectory(File file) {
413            int tries = 0;
414            int maxTries = 5;
415            boolean exists = true;
416            while (exists && (tries < maxTries)) {
417                recursivelyDeleteDirectory(file);
418                tries++;
419                exists = file.exists(); 
420                if (exists) {
421                    try {
422                        Thread.sleep(1000);
423                    } catch (InterruptedException e) {
424                        // Ignore
425                    }
426                }
427            }
428            if (exists) {
429                throw new RuntimeException("Deletion of file " + file + " failed");
430            }
431        }
432    
433        private static void recursivelyDeleteDirectory(File file) {
434            if (!file.exists()) {
435                return;
436            }
437            
438            if (file.isDirectory()) {
439                File[] files = file.listFiles();
440                for (int i = 0; i < files.length; i++) {
441                    recursivelyDeleteDirectory(files[i]);
442                }
443            }
444            boolean success = file.delete();
445            if (!success) {
446                LOG.warn("Deletion of file: " + file.getAbsolutePath() + " failed");
447            }
448        }
449    
450        /**
451         * create the directory
452         *
453         * @param file the directory to be created
454         */
455        public static void createDirectory(String file) {
456            File dir = new File(file);
457            dir.mkdirs();
458        }
459    
460        /**
461         * To be used for folder/directory comparison that works across different platforms such
462         * as Window, Mac and Linux.
463         */
464        public static void assertDirectoryEquals(String expected, String actual) {
465            assertDirectoryEquals(null, expected, actual);
466        }
467    
468        /**
469         * To be used for folder/directory comparison that works across different platforms such
470         * as Window, Mac and Linux.
471         */
472        public static void assertDirectoryEquals(String message, String expected, String actual) {
473            // must use single / as path separators
474            String expectedPath = expected.replace('\\', '/');
475            String actualPath = actual.replace('\\', '/');
476    
477            if (message != null) {
478                assertEquals(message, expectedPath, actualPath);
479            } else {
480                assertEquals(expectedPath, actualPath);
481            }
482        }
483    
484        /**
485         * To be used to check is a file is found in the file system
486         */
487        public static void assertFileExists(String filename) {
488            File file = new File(filename).getAbsoluteFile();
489            assertTrue("File " + filename + " should exist", file.exists());
490        }
491    
492        /**
493         * Is this OS the given platform.
494         * <p/>
495         * Uses <tt>os.name</tt> from the system properties to determine the OS.
496         *
497         * @param platform such as Windows
498         * @return <tt>true</tt> if its that platform.
499         */
500        public static boolean isPlatform(String platform) {
501            String osName = System.getProperty("os.name").toLowerCase(Locale.US);
502            return osName.indexOf(platform.toLowerCase(Locale.US)) > -1;
503        }
504    
505        /**
506         * Is this Java by the given vendor.
507         * <p/>
508         * Uses <tt>java.vendor</tt> from the system properties to determine the vendor.
509         *
510         * @param vendor such as IBM
511         * @return <tt>true</tt> if its that vendor.
512         */
513        public static boolean isJavaVendor(String vendor) {
514            String javaVendor = System.getProperty("java.vendor").toLowerCase(Locale.US);
515            return javaVendor.indexOf(vendor.toLowerCase(Locale.US)) > -1;
516        }
517    
518        /**
519         * Is this Java 1.5
520         *
521         * @return <tt>true</tt> if its Java 1.5, <tt>false</tt> if its not (for example Java 1.6 or better)
522         * @deprecated will be removed in the near future as Camel now requires JDK1.6+
523         */
524        @Deprecated
525        public static boolean isJava15() {
526            String javaVersion = System.getProperty("java.version").toLowerCase(Locale.US);
527            return javaVersion.startsWith("1.5");
528        }
529    
530        /**
531         * Gets the current test method name
532         *
533         * @return the method name
534         */
535        public String getTestMethodName() {
536            return testName.getMethodName();
537        }
538    
539    }