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 */ 017package org.apache.camel.component.test; 018 019import java.util.ArrayList; 020import java.util.Iterator; 021import java.util.List; 022 023import org.apache.camel.Component; 024import org.apache.camel.Endpoint; 025import org.apache.camel.Exchange; 026import org.apache.camel.Processor; 027import org.apache.camel.WrappedFile; 028import org.apache.camel.component.mock.MockEndpoint; 029import org.apache.camel.spi.Metadata; 030import org.apache.camel.spi.UriEndpoint; 031import org.apache.camel.spi.UriParam; 032import org.apache.camel.spi.UriPath; 033import org.apache.camel.util.EndpointHelper; 034import org.apache.camel.util.ObjectHelper; 035import org.slf4j.Logger; 036import org.slf4j.LoggerFactory; 037 038/** 039 * The test component extends the mock component by on startup to pull messages from another endpoint to set the expected message bodies. 040 * 041 * That is, you use the test endpoint in a route and messages arriving on it will be implicitly compared to some 042 * expected messages extracted from some other location. 043 * So you can use, for example, an expected set of message bodies as files. 044 * This will then set up a properly configured Mock endpoint, which is only valid if the received messages 045 * match the number of expected messages and their message payloads are equal. 046 */ 047@UriEndpoint(firstVersion = "1.3.0", scheme = "test", title = "Test", syntax = "test:name", producerOnly = true, label = "core,testing", lenientProperties = true) 048public class TestEndpoint extends MockEndpoint { 049 private static final Logger LOG = LoggerFactory.getLogger(TestEndpoint.class); 050 051 private Endpoint expectedMessageEndpoint; 052 053 @UriPath(description = "Name of endpoint to lookup in the registry to use for polling messages used for testing") @Metadata(required = "true") 054 private String name; 055 @UriParam 056 private boolean anyOrder; 057 @UriParam(defaultValue = "2000") 058 private long timeout = 2000L; 059 @UriParam 060 private boolean split; 061 @UriParam 062 private String delimiter = "\\n|\\r"; 063 064 public TestEndpoint(String endpointUri, Component component) { 065 super(endpointUri, component); 066 } 067 068 public void setExpectedMessageEndpoint(Endpoint expectedMessageEndpoint) { 069 this.expectedMessageEndpoint = expectedMessageEndpoint; 070 } 071 072 @Override 073 protected void doStart() throws Exception { 074 LOG.debug("Consuming expected messages from: {}", expectedMessageEndpoint); 075 076 final List<Object> expectedBodies = new ArrayList<Object>(); 077 EndpointHelper.pollEndpoint(expectedMessageEndpoint, new Processor() { 078 public void process(Exchange exchange) throws Exception { 079 // if file based we need to load the file into memory as the file may be deleted/moved afterwards 080 Object body = getInBody(exchange); 081 if (body instanceof WrappedFile) { 082 body = exchange.getIn().getBody(String.class); 083 } 084 if (split) { 085 // use new lines in both styles 086 Iterator it = ObjectHelper.createIterator(body, delimiter, false, true); 087 while (it.hasNext()) { 088 Object line = it.next(); 089 LOG.trace("Received message body {}", line); 090 expectedBodies.add(line); 091 } 092 } else { 093 expectedBodies.add(body); 094 } 095 } 096 }, timeout); 097 098 LOG.info("Received: {} expected message(s) from: {}", expectedBodies.size(), expectedMessageEndpoint); 099 if (anyOrder) { 100 expectedBodiesReceivedInAnyOrder(expectedBodies); 101 } else { 102 expectedBodiesReceived(expectedBodies); 103 } 104 } 105 106 /** 107 * This method allows us to convert or coerce the expected message body into some other type 108 */ 109 protected Object getInBody(Exchange exchange) { 110 return exchange.getIn().getBody(); 111 } 112 113 public long getTimeout() { 114 return timeout; 115 } 116 117 /** 118 * The timeout to use when polling for message bodies from the URI 119 */ 120 public void setTimeout(long timeout) { 121 this.timeout = timeout; 122 } 123 124 public boolean isAnyOrder() { 125 return anyOrder; 126 } 127 128 /** 129 * Whether the expected messages should arrive in the same order or can be in any order. 130 */ 131 public void setAnyOrder(boolean anyOrder) { 132 this.anyOrder = anyOrder; 133 } 134 135 public boolean isSplit() { 136 return split; 137 } 138 139 /** 140 * If enabled the the messages loaded from the test endpoint will be split using new line delimiters 141 * so each line is an expected message. 142 * <br/> 143 * For example to use a file endpoint to load a file where each line is an expected message. 144 */ 145 public void setSplit(boolean split) { 146 this.split = split; 147 } 148 149 public String getDelimiter() { 150 return delimiter; 151 } 152 153 /** 154 * The split delimiter to use when split is enabled. 155 * By default the delimiter is new line based. 156 * The delimiter can be a regular expression. 157 */ 158 public void setDelimiter(String delimiter) { 159 this.delimiter = delimiter; 160 } 161}