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.component.mock; 018 019 import java.beans.PropertyChangeListener; 020 import java.beans.PropertyChangeSupport; 021 import java.io.File; 022 import java.util.ArrayList; 023 import java.util.Arrays; 024 import java.util.Collection; 025 import java.util.HashMap; 026 import java.util.HashSet; 027 import java.util.List; 028 import java.util.Map; 029 import java.util.Set; 030 import java.util.concurrent.CopyOnWriteArrayList; 031 import java.util.concurrent.CountDownLatch; 032 import java.util.concurrent.TimeUnit; 033 034 import org.apache.camel.CamelContext; 035 import org.apache.camel.Component; 036 import org.apache.camel.Consumer; 037 import org.apache.camel.Endpoint; 038 import org.apache.camel.Exchange; 039 import org.apache.camel.Expression; 040 import org.apache.camel.Message; 041 import org.apache.camel.Processor; 042 import org.apache.camel.Producer; 043 import org.apache.camel.impl.DefaultEndpoint; 044 import org.apache.camel.impl.DefaultProducer; 045 import org.apache.camel.spi.BrowsableEndpoint; 046 import org.apache.camel.util.CamelContextHelper; 047 import org.apache.camel.util.ExpressionComparator; 048 import org.apache.camel.util.FileUtil; 049 import org.apache.camel.util.ObjectHelper; 050 import org.apache.commons.logging.Log; 051 import org.apache.commons.logging.LogFactory; 052 053 /** 054 * A Mock endpoint which provides a literate, fluent API for testing routes 055 * using a <a href="http://jmock.org/">JMock style</a> API. 056 * 057 * @version $Revision: 752464 $ 058 */ 059 public class MockEndpoint extends DefaultEndpoint implements BrowsableEndpoint { 060 private static final transient Log LOG = LogFactory.getLog(MockEndpoint.class); 061 private int expectedCount; 062 private int counter; 063 private Processor defaultProcessor; 064 private Map<Integer, Processor> processors; 065 private List<Exchange> receivedExchanges; 066 private List<Throwable> failures; 067 private List<Runnable> tests; 068 private CountDownLatch latch; 069 private long sleepForEmptyTest; 070 private long resultWaitTime; 071 private long resultMinimumWaitTime; 072 private int expectedMinimumCount; 073 private List expectedBodyValues; 074 private List actualBodyValues; 075 private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); 076 private String headerName; 077 private Object headerValue; 078 private Object actualHeader; 079 private Processor reporter; 080 081 public MockEndpoint(String endpointUri, Component component) { 082 super(endpointUri, component); 083 init(); 084 } 085 086 public MockEndpoint(String endpointUri) { 087 super(endpointUri); 088 init(); 089 } 090 091 public MockEndpoint() { 092 this(null); 093 } 094 095 /** 096 * A helper method to resolve the mock endpoint of the given URI on the given context 097 * 098 * @param context the camel context to try resolve the mock endpoint from 099 * @param uri the uri of the endpoint to resolve 100 * @return the endpoint 101 */ 102 public static MockEndpoint resolve(CamelContext context, String uri) { 103 return CamelContextHelper.getMandatoryEndpoint(context, uri, MockEndpoint.class); 104 } 105 106 public static void assertWait(long timeout, TimeUnit unit, MockEndpoint... endpoints) throws InterruptedException { 107 long start = System.currentTimeMillis(); 108 long left = unit.toMillis(timeout); 109 long end = start + left; 110 for (MockEndpoint endpoint : endpoints) { 111 if (!endpoint.await(left, TimeUnit.MILLISECONDS)) { 112 throw new AssertionError("Timeout waiting for endpoints to receive enough messages. " + endpoint.getEndpointUri() + " timed out."); 113 } 114 left = end - System.currentTimeMillis(); 115 if (left <= 0) { 116 left = 0; 117 } 118 } 119 } 120 121 public static void assertIsSatisfied(long timeout, TimeUnit unit, MockEndpoint... endpoints) throws InterruptedException { 122 assertWait(timeout, unit, endpoints); 123 for (MockEndpoint endpoint : endpoints) { 124 endpoint.assertIsSatisfied(); 125 } 126 } 127 128 public static void assertIsSatisfied(MockEndpoint... endpoints) throws InterruptedException { 129 for (MockEndpoint endpoint : endpoints) { 130 endpoint.assertIsSatisfied(); 131 } 132 } 133 134 135 /** 136 * Asserts that all the expectations on any {@link MockEndpoint} instances registered 137 * in the given context are valid 138 * 139 * @param context the camel context used to find all the available endpoints to be asserted 140 */ 141 public static void assertIsSatisfied(CamelContext context) throws InterruptedException { 142 ObjectHelper.notNull(context, "camelContext"); 143 Collection<Endpoint> endpoints = context.getSingletonEndpoints(); 144 for (Endpoint endpoint : endpoints) { 145 if (endpoint instanceof MockEndpoint) { 146 MockEndpoint mockEndpoint = (MockEndpoint) endpoint; 147 mockEndpoint.assertIsSatisfied(); 148 } 149 } 150 } 151 152 public static void expectsMessageCount(int count, MockEndpoint... endpoints) throws InterruptedException { 153 for (MockEndpoint endpoint : endpoints) { 154 endpoint.setExpectedMessageCount(count); 155 } 156 } 157 158 public List<Exchange> getExchanges() { 159 return getReceivedExchanges(); 160 } 161 162 public void addPropertyChangeListener(PropertyChangeListener listener) { 163 propertyChangeSupport.addPropertyChangeListener(listener); 164 } 165 166 public void removePropertyChangeListener(PropertyChangeListener listener) { 167 propertyChangeSupport.removePropertyChangeListener(listener); 168 } 169 170 public Consumer createConsumer(Processor processor) throws Exception { 171 throw new UnsupportedOperationException("You cannot consume from this endpoint"); 172 } 173 174 public Producer createProducer() throws Exception { 175 return new DefaultProducer(this) { 176 public void process(Exchange exchange) { 177 onExchange(exchange); 178 } 179 }; 180 } 181 182 public void reset() { 183 init(); 184 } 185 186 187 // Testing API 188 // ------------------------------------------------------------------------- 189 190 /** 191 * Set the processor that will be invoked when the index 192 * message is received. 193 */ 194 public void whenExchangeReceived(int index, Processor processor) { 195 this.processors.put(index, processor); 196 } 197 198 /** 199 * Set the processor that will be invoked when the some message 200 * is received. 201 * 202 * This processor could be overwritten by 203 * {@link #whenExchangeReceived(int, Processor)} method. 204 */ 205 public void whenAnyExchangeReceived(Processor processor) { 206 this.defaultProcessor = processor; 207 } 208 209 /** 210 * Validates that all the available expectations on this endpoint are 211 * satisfied; or throw an exception 212 */ 213 public void assertIsSatisfied() throws InterruptedException { 214 assertIsSatisfied(sleepForEmptyTest); 215 } 216 217 /** 218 * Validates that all the available expectations on this endpoint are 219 * satisfied; or throw an exception 220 * 221 * @param timeoutForEmptyEndpoints the timeout in milliseconds that we 222 * should wait for the test to be true 223 */ 224 public void assertIsSatisfied(long timeoutForEmptyEndpoints) throws InterruptedException { 225 LOG.info("Asserting: " + this + " is satisfied"); 226 if (expectedCount == 0) { 227 if (timeoutForEmptyEndpoints > 0) { 228 LOG.debug("Sleeping for: " + timeoutForEmptyEndpoints + " millis to check there really are no messages received"); 229 Thread.sleep(timeoutForEmptyEndpoints); 230 } 231 assertEquals("Received message count", expectedCount, getReceivedCounter()); 232 } else if (expectedCount > 0) { 233 if (expectedCount != getReceivedCounter()) { 234 waitForCompleteLatch(); 235 } 236 assertEquals("Received message count", expectedCount, getReceivedCounter()); 237 } else if (expectedMinimumCount > 0 && getReceivedCounter() < expectedMinimumCount) { 238 waitForCompleteLatch(); 239 } 240 241 if (expectedMinimumCount >= 0) { 242 int receivedCounter = getReceivedCounter(); 243 assertTrue("Received message count " + receivedCounter + ", expected at least " + expectedMinimumCount, expectedMinimumCount <= receivedCounter); 244 } 245 246 for (Runnable test : tests) { 247 test.run(); 248 } 249 250 for (Throwable failure : failures) { 251 if (failure != null) { 252 LOG.error("Caught on " + getEndpointUri() + " Exception: " + failure, failure); 253 fail("Failed due to caught exception: " + failure); 254 } 255 } 256 } 257 258 /** 259 * Validates that the assertions fail on this endpoint 260 */ 261 public void assertIsNotSatisfied() throws InterruptedException { 262 try { 263 assertIsSatisfied(); 264 fail("Expected assertion failure!"); 265 } catch (AssertionError e) { 266 LOG.info("Caught expected failure: " + e); 267 } 268 } 269 270 /** 271 * Validates that the assertions fail on this endpoint 272 273 * @param timeoutForEmptyEndpoints the timeout in milliseconds that we 274 * should wait for the test to be true 275 */ 276 public void assertIsNotSatisfied(long timeoutForEmptyEndpoints) throws InterruptedException { 277 try { 278 assertIsSatisfied(timeoutForEmptyEndpoints); 279 fail("Expected assertion failure!"); 280 } catch (AssertionError e) { 281 LOG.info("Caught expected failure: " + e); 282 } 283 } 284 285 /** 286 * Specifies the expected number of message exchanges that should be 287 * received by this endpoint 288 * 289 * @param expectedCount the number of message exchanges that should be 290 * expected by this endpoint 291 */ 292 public void expectedMessageCount(int expectedCount) { 293 setExpectedMessageCount(expectedCount); 294 } 295 296 /** 297 * Specifies the minimum number of expected message exchanges that should be 298 * received by this endpoint 299 * 300 * @param expectedCount the number of message exchanges that should be 301 * expected by this endpoint 302 */ 303 public void expectedMinimumMessageCount(int expectedCount) { 304 setMinimumExpectedMessageCount(expectedCount); 305 } 306 307 /** 308 * Adds an expectation that the given header name & value are received by this 309 * endpoint 310 */ 311 public void expectedHeaderReceived(final String name, final Object value) { 312 this.headerName = name; 313 this.headerValue = value; 314 315 expects(new Runnable() { 316 public void run() { 317 assertTrue("No header with name " + headerName + " found.", actualHeader != null); 318 319 Object actualValue = getCamelContext().getTypeConverter().convertTo(actualHeader.getClass(), headerValue); 320 assertEquals("Header of message", actualValue, actualHeader); 321 } 322 }); 323 } 324 325 /** 326 * Adds an expectation that the given body values are received by this 327 * endpoint in the specified order 328 */ 329 public void expectedBodiesReceived(final List bodies) { 330 expectedMessageCount(bodies.size()); 331 this.expectedBodyValues = bodies; 332 this.actualBodyValues = new ArrayList(); 333 334 expects(new Runnable() { 335 public void run() { 336 for (int i = 0; i < expectedBodyValues.size(); i++) { 337 Exchange exchange = getReceivedExchanges().get(i); 338 assertTrue("No exchange received for counter: " + i, exchange != null); 339 340 Object expectedBody = expectedBodyValues.get(i); 341 Object actualBody = null; 342 if (i < actualBodyValues.size()) { 343 actualBody = actualBodyValues.get(i); 344 } 345 346 assertEquals("Body of message: " + i, expectedBody, actualBody); 347 } 348 } 349 }); 350 } 351 352 /** 353 * Adds an expectation that the given body values are received by this 354 * endpoint 355 */ 356 public void expectedBodiesReceived(Object... bodies) { 357 List bodyList = new ArrayList(); 358 bodyList.addAll(Arrays.asList(bodies)); 359 expectedBodiesReceived(bodyList); 360 } 361 362 /** 363 * Adds an expectation that the given body values are received by this 364 * endpoint in any order 365 */ 366 public void expectedBodiesReceivedInAnyOrder(final List bodies) { 367 expectedMessageCount(bodies.size()); 368 this.expectedBodyValues = bodies; 369 this.actualBodyValues = new ArrayList(); 370 371 expects(new Runnable() { 372 public void run() { 373 Set actualBodyValuesSet = new HashSet(actualBodyValues); 374 for (int i = 0; i < expectedBodyValues.size(); i++) { 375 Exchange exchange = getReceivedExchanges().get(i); 376 assertTrue("No exchange received for counter: " + i, exchange != null); 377 378 Object expectedBody = expectedBodyValues.get(i); 379 assertTrue("Message with body " + expectedBody 380 + " was expected but not found in " + actualBodyValuesSet, 381 actualBodyValuesSet.remove(expectedBody)); 382 } 383 } 384 }); 385 } 386 387 /** 388 * Adds an expectation that the given body values are received by this 389 * endpoint in any order 390 */ 391 @SuppressWarnings("unchecked") 392 public void expectedBodiesReceivedInAnyOrder(Object... bodies) { 393 List bodyList = new ArrayList(); 394 bodyList.addAll(Arrays.asList(bodies)); 395 expectedBodiesReceivedInAnyOrder(bodyList); 396 } 397 398 /** 399 * Adds an expection that a file exists with the given name 400 * 401 * @param name name of file, will cater for / and \ on different OS platforms 402 */ 403 public void expectedFileExists(final String name) { 404 expectedFileExists(name, null); 405 } 406 407 /** 408 * Adds an expection that a file exists with the given name 409 * <p/> 410 * Will wait at most 5 seconds while checking for the existence of the file. 411 * 412 * @param name name of file, will cater for / and \ on different OS platforms 413 * @param content content of file to compare, can be <tt>null</tt> to not compare content 414 */ 415 public void expectedFileExists(final String name, final String content) { 416 final File file = new File(FileUtil.normalizePath(name)).getAbsoluteFile(); 417 418 expects(new Runnable() { 419 public void run() { 420 // wait at most 5 seconds for the file to exists 421 final long timeout = System.currentTimeMillis() + 5000; 422 423 boolean stop = false; 424 while (!stop && !file.exists()) { 425 try { 426 Thread.sleep(50); 427 } catch (InterruptedException e) { 428 // ignore 429 } 430 stop = System.currentTimeMillis() > timeout; 431 } 432 433 assertTrue("The file should exists: " + name, file.exists()); 434 435 if (content != null) { 436 String body = getCamelContext().getTypeConverter().convertTo(String.class, file); 437 assertEquals("Content of file: " + name, content, body); 438 } 439 } 440 }); 441 } 442 443 /** 444 * Adds an expectation that messages received should have ascending values 445 * of the given expression such as a user generated counter value 446 */ 447 public void expectsAscending(final Expression expression) { 448 expects(new Runnable() { 449 public void run() { 450 assertMessagesAscending(expression); 451 } 452 }); 453 } 454 455 /** 456 * Adds an expectation that messages received should have descending values 457 * of the given expression such as a user generated counter value 458 */ 459 public void expectsDescending(final Expression expression) { 460 expects(new Runnable() { 461 public void run() { 462 assertMessagesDescending(expression); 463 } 464 }); 465 } 466 467 /** 468 * Adds an expectation that no duplicate messages should be received using 469 * the expression to determine the message ID 470 * 471 * @param expression the expression used to create a unique message ID for 472 * message comparison (which could just be the message 473 * payload if the payload can be tested for uniqueness using 474 * {@link Object#equals(Object)} and 475 * {@link Object#hashCode()} 476 */ 477 public void expectsNoDuplicates(final Expression expression) { 478 expects(new Runnable() { 479 public void run() { 480 assertNoDuplicates(expression); 481 } 482 }); 483 } 484 485 /** 486 * Asserts that the messages have ascending values of the given expression 487 */ 488 public void assertMessagesAscending(Expression expression) { 489 assertMessagesSorted(expression, true); 490 } 491 492 /** 493 * Asserts that the messages have descending values of the given expression 494 */ 495 public void assertMessagesDescending(Expression expression) { 496 assertMessagesSorted(expression, false); 497 } 498 499 protected void assertMessagesSorted(Expression expression, boolean ascending) { 500 String type = ascending ? "ascending" : "descending"; 501 ExpressionComparator comparator = new ExpressionComparator(expression); 502 List<Exchange> list = getReceivedExchanges(); 503 for (int i = 1; i < list.size(); i++) { 504 int j = i - 1; 505 Exchange e1 = list.get(j); 506 Exchange e2 = list.get(i); 507 int result = comparator.compare(e1, e2); 508 if (result == 0) { 509 fail("Messages not " + type + ". Messages" + j + " and " + i + " are equal with value: " + expression.evaluate(e1) + " for expression: " + expression + ". Exchanges: " + e1 + " and " 510 + e2); 511 } else { 512 if (!ascending) { 513 result = result * -1; 514 } 515 if (result > 0) { 516 fail("Messages not " + type + ". Message " + j + " has value: " + expression.evaluate(e1) + " and message " + i + " has value: " + expression.evaluate(e2) + " for expression: " 517 + expression + ". Exchanges: " + e1 + " and " + e2); 518 } 519 } 520 } 521 } 522 523 public void assertNoDuplicates(Expression expression) { 524 Map<Object, Exchange> map = new HashMap<Object, Exchange>(); 525 List<Exchange> list = getReceivedExchanges(); 526 for (int i = 0; i < list.size(); i++) { 527 Exchange e2 = list.get(i); 528 Object key = expression.evaluate(e2); 529 Exchange e1 = map.get(key); 530 if (e1 != null) { 531 fail("Duplicate message found on message " + i + " has value: " + key + " for expression: " + expression + ". Exchanges: " + e1 + " and " + e2); 532 } else { 533 map.put(key, e2); 534 } 535 } 536 } 537 538 /** 539 * Adds the expectation which will be invoked when enough messages are 540 * received 541 */ 542 public void expects(Runnable runnable) { 543 tests.add(runnable); 544 } 545 546 /** 547 * Adds an assertion to the given message index 548 * 549 * @param messageIndex the number of the message 550 * @return the assertion clause 551 */ 552 public AssertionClause message(final int messageIndex) { 553 AssertionClause clause = new AssertionClause() { 554 public void run() { 555 applyAssertionOn(MockEndpoint.this, messageIndex, assertExchangeReceived(messageIndex)); 556 } 557 }; 558 expects(clause); 559 return clause; 560 } 561 562 /** 563 * Adds an assertion to all the received messages 564 * 565 * @return the assertion clause 566 */ 567 public AssertionClause allMessages() { 568 AssertionClause clause = new AssertionClause() { 569 public void run() { 570 List<Exchange> list = getReceivedExchanges(); 571 int index = 0; 572 for (Exchange exchange : list) { 573 applyAssertionOn(MockEndpoint.this, index++, exchange); 574 } 575 } 576 }; 577 expects(clause); 578 return clause; 579 } 580 581 /** 582 * Asserts that the given index of message is received (starting at zero) 583 */ 584 public Exchange assertExchangeReceived(int index) { 585 int count = getReceivedCounter(); 586 assertTrue("Not enough messages received. Was: " + count, count > index); 587 return getReceivedExchanges().get(index); 588 } 589 590 // Properties 591 // ------------------------------------------------------------------------- 592 public List<Throwable> getFailures() { 593 return failures; 594 } 595 596 public int getReceivedCounter() { 597 return getReceivedExchanges().size(); 598 } 599 600 public List<Exchange> getReceivedExchanges() { 601 return receivedExchanges; 602 } 603 604 public int getExpectedCount() { 605 return expectedCount; 606 } 607 608 public long getSleepForEmptyTest() { 609 return sleepForEmptyTest; 610 } 611 612 /** 613 * Allows a sleep to be specified to wait to check that this endpoint really 614 * is empty when {@link #expectedMessageCount(int)} is called with zero 615 * 616 * @param sleepForEmptyTest the milliseconds to sleep for to determine that 617 * this endpoint really is empty 618 */ 619 public void setSleepForEmptyTest(long sleepForEmptyTest) { 620 this.sleepForEmptyTest = sleepForEmptyTest; 621 } 622 623 public long getResultWaitTime() { 624 return resultWaitTime; 625 } 626 627 /** 628 * Sets the maximum amount of time (in millis) the {@link #assertIsSatisfied()} will 629 * wait on a latch until it is satisfied 630 */ 631 public void setResultWaitTime(long resultWaitTime) { 632 this.resultWaitTime = resultWaitTime; 633 } 634 635 /** 636 * Sets the minimum expected amount of time (in millis) the {@link #assertIsSatisfied()} will 637 * wait on a latch until it is satisfied 638 */ 639 public void setMinimumResultWaitTime(long resultMinimumWaitTime) { 640 this.resultMinimumWaitTime = resultMinimumWaitTime; 641 } 642 643 /** 644 * Specifies the expected number of message exchanges that should be 645 * received by this endpoint 646 * 647 * @param expectedCount the number of message exchanges that should be 648 * expected by this endpoint 649 */ 650 public void setExpectedMessageCount(int expectedCount) { 651 this.expectedCount = expectedCount; 652 if (expectedCount <= 0) { 653 latch = null; 654 } else { 655 latch = new CountDownLatch(expectedCount); 656 } 657 } 658 659 /** 660 * Specifies the minimum number of expected message exchanges that should be 661 * received by this endpoint 662 * 663 * @param expectedCount the number of message exchanges that should be 664 * expected by this endpoint 665 */ 666 public void setMinimumExpectedMessageCount(int expectedCount) { 667 this.expectedMinimumCount = expectedCount; 668 if (expectedCount <= 0) { 669 latch = null; 670 } else { 671 latch = new CountDownLatch(expectedMinimumCount); 672 } 673 } 674 675 public Processor getReporter() { 676 return reporter; 677 } 678 679 /** 680 * Allows a processor to added to the endpoint to report on progress of the test 681 */ 682 public void setReporter(Processor reporter) { 683 this.reporter = reporter; 684 } 685 686 // Implementation methods 687 // ------------------------------------------------------------------------- 688 private void init() { 689 expectedCount = -1; 690 counter = 0; 691 processors = new HashMap<Integer, Processor>(); 692 receivedExchanges = new CopyOnWriteArrayList<Exchange>(); 693 failures = new CopyOnWriteArrayList<Throwable>(); 694 tests = new CopyOnWriteArrayList<Runnable>(); 695 latch = null; 696 sleepForEmptyTest = 0; 697 resultWaitTime = 20000L; 698 resultMinimumWaitTime = 0L; 699 expectedMinimumCount = -1; 700 expectedBodyValues = null; 701 actualBodyValues = new ArrayList(); 702 } 703 704 protected synchronized void onExchange(Exchange exchange) { 705 try { 706 if (reporter != null) { 707 reporter.process(exchange); 708 } 709 710 performAssertions(exchange); 711 } catch (Exception e) { 712 failures.add(e); 713 } 714 if (latch != null) { 715 latch.countDown(); 716 } 717 } 718 719 @SuppressWarnings("unchecked") 720 protected void performAssertions(Exchange exchange) throws Exception { 721 Message in = exchange.getIn(); 722 Object actualBody = in.getBody(); 723 724 if (headerName != null) { 725 actualHeader = in.getHeader(headerName); 726 } 727 728 if (expectedBodyValues != null) { 729 int index = actualBodyValues.size(); 730 if (expectedBodyValues.size() > index) { 731 Object expectedBody = expectedBodyValues.get(index); 732 if (expectedBody != null) { 733 actualBody = in.getBody(expectedBody.getClass()); 734 } 735 actualBodyValues.add(actualBody); 736 } 737 } 738 739 LOG.debug(getEndpointUri() + " >>>> " + (++counter) + " : " + exchange + " with body: " + actualBody); 740 741 receivedExchanges.add(exchange); 742 743 Processor processor = processors.get(getReceivedCounter()) != null 744 ? processors.get(getReceivedCounter()) : defaultProcessor; 745 746 if (processor != null) { 747 processor.process(exchange); 748 } 749 } 750 751 protected void waitForCompleteLatch() throws InterruptedException { 752 if (latch == null) { 753 fail("Should have a latch!"); 754 } 755 756 // now lets wait for the results 757 LOG.debug("Waiting on the latch for: " + resultWaitTime + " millis"); 758 long start = System.currentTimeMillis(); 759 latch.await(resultWaitTime, TimeUnit.MILLISECONDS); 760 long delta = System.currentTimeMillis() - start; 761 LOG.debug("Took " + delta + " millis to complete latch"); 762 763 if (resultMinimumWaitTime > 0 && delta < resultMinimumWaitTime) { 764 fail("Expected minimum " + resultMinimumWaitTime 765 + " millis waiting on the result, but was faster with " + delta + " millis."); 766 } 767 } 768 769 protected void assertEquals(String message, Object expectedValue, Object actualValue) { 770 if (!ObjectHelper.equal(expectedValue, actualValue)) { 771 fail(message + ". Expected: <" + expectedValue + "> but was: <" + actualValue + ">"); 772 } 773 } 774 775 protected void assertTrue(String message, boolean predicate) { 776 if (!predicate) { 777 fail(message); 778 } 779 } 780 781 protected void fail(Object message) { 782 if (LOG.isDebugEnabled()) { 783 List<Exchange> list = getReceivedExchanges(); 784 int index = 0; 785 for (Exchange exchange : list) { 786 LOG.debug("Received[" + (++index) + "]: " + exchange); 787 } 788 } 789 throw new AssertionError(getEndpointUri() + " " + message); 790 } 791 792 public int getExpectedMinimumCount() { 793 return expectedMinimumCount; 794 } 795 796 public void await() throws InterruptedException { 797 if (latch != null) { 798 latch.await(); 799 } 800 } 801 802 public boolean await(long timeout, TimeUnit unit) throws InterruptedException { 803 if (latch != null) { 804 return latch.await(timeout, unit); 805 } 806 return true; 807 } 808 809 public boolean isSingleton() { 810 return true; 811 } 812 }