Author: davsclaus Date: Wed Mar 10 11:41:57 2010 New Revision: 921314 URL: http://svn.apache.org/viewvc?rev=921314&view=rev Log: CAMEL-2534: Added integration tests for LB with failover round robin mode.
Added: camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettyFailoverRoundRobinTest.java (with props) camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettySimulateFailoverRoundRobinTest.java (with props) camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettySpringFailoverRoundRobinTest.java (with props) camel/trunk/tests/camel-itest/src/test/resources/org/apache/camel/itest/jetty/JettySpringFailoverRoundRobinTest.xml - copied, changed from r921278, camel/trunk/tests/camel-itest/src/test/resources/org/apache/camel/itest/jetty/JettyJmsTest-context.xml Modified: camel/trunk/components/camel-test/src/main/java/org/apache/camel/test/CamelTestSupport.java camel/trunk/components/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java Modified: camel/trunk/components/camel-test/src/main/java/org/apache/camel/test/CamelTestSupport.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-test/src/main/java/org/apache/camel/test/CamelTestSupport.java?rev=921314&r1=921313&r2=921314&view=diff ============================================================================== --- camel/trunk/components/camel-test/src/main/java/org/apache/camel/test/CamelTestSupport.java (original) +++ camel/trunk/components/camel-test/src/main/java/org/apache/camel/test/CamelTestSupport.java Wed Mar 10 11:41:57 2010 @@ -323,6 +323,13 @@ public abstract class CamelTestSupport e MockEndpoint.assertIsSatisfied(context); } + /** + * Reset all Mock endpoints. + */ + protected void resetMocks() { + MockEndpoint.resetMocks(context); + } + protected void assertValidContext(CamelContext context) { assertNotNull("No context found!", context); } Modified: camel/trunk/components/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java?rev=921314&r1=921313&r2=921314&view=diff ============================================================================== --- camel/trunk/components/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java (original) +++ camel/trunk/components/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java Wed Mar 10 11:41:57 2010 @@ -322,6 +322,13 @@ public abstract class CamelTestSupport e MockEndpoint.assertIsSatisfied(context); } + /** + * Reset all Mock endpoints. + */ + protected void resetMocks() { + MockEndpoint.resetMocks(context); + } + protected void assertValidContext(CamelContext context) { assertNotNull("No context found!", context); } Added: camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettyFailoverRoundRobinTest.java URL: http://svn.apache.org/viewvc/camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettyFailoverRoundRobinTest.java?rev=921314&view=auto ============================================================================== --- camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettyFailoverRoundRobinTest.java (added) +++ camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettyFailoverRoundRobinTest.java Wed Mar 10 11:41:57 2010 @@ -0,0 +1,112 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.itest.jetty; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.Test; + +/** + * @version $Revision$ + */ +public class JettyFailoverRoundRobinTest extends CamelTestSupport { + + private String bad = "jetty:http://localhost:8871/bad"; + private String bad2 = "jetty:http://localhost:8872/bad2"; + private String good = "jetty:http://localhost:8873/good"; + private String good2 = "jetty:http://localhost:8874/good2"; + + @Test + public void testJettyFailoverRoundRobin() throws Exception { + getMockEndpoint("mock:bad").expectedMessageCount(1); + getMockEndpoint("mock:bad2").expectedMessageCount(1); + getMockEndpoint("mock:good").expectedMessageCount(1); + getMockEndpoint("mock:good2").expectedMessageCount(0); + + String reply = template.requestBody("direct:start", null, String.class); + assertEquals("Good", reply); + + assertMockEndpointsSatisfied(); + + // reset mocks and send a message again to see that round robin + // continue where it should + resetMocks(); + + getMockEndpoint("mock:bad").expectedMessageCount(0); + getMockEndpoint("mock:bad2").expectedMessageCount(0); + getMockEndpoint("mock:good").expectedMessageCount(0); + getMockEndpoint("mock:good2").expectedMessageCount(1); + + reply = template.requestBody("direct:start", null, String.class); + assertEquals("Also good", reply); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + // START SNIPPET: e1 + from("direct:start") + // load balance using failover in round robin mode. + // Also do not inherit error handler which means the failover LB will not fallback + // and use error handler but trigger failover to next endpoint immediately. + // -1 is to indicate that failover LB should newer exhaust and keep trying + .loadBalance().failover(-1, false, true) + // this is the four endpoints we will load balance with failover + .to(bad, bad2, good, good2); + // END SNIPPET: e1 + + from(bad) + .to("mock:bad") + .process(new Processor() { + public void process(Exchange exchange) throws Exception { + exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 500); + exchange.getIn().setBody("Something bad happened"); + } + }); + + from(bad2) + .to("mock:bad2") + .process(new Processor() { + public void process(Exchange exchange) throws Exception { + exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 404); + exchange.getIn().setBody("Not found"); + } + }); + + from(good) + .to("mock:good") + .process(new Processor() { + public void process(Exchange exchange) throws Exception { + exchange.getIn().setBody("Good"); + } + }); + + from(good2) + .to("mock:good2") + .process(new Processor() { + public void process(Exchange exchange) throws Exception { + exchange.getIn().setBody("Also good"); + } + }); + } + }; + } +} Propchange: camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettyFailoverRoundRobinTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettyFailoverRoundRobinTest.java ------------------------------------------------------------------------------ svn:keywords = Rev Date Added: camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettySimulateFailoverRoundRobinTest.java URL: http://svn.apache.org/viewvc/camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettySimulateFailoverRoundRobinTest.java?rev=921314&view=auto ============================================================================== --- camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettySimulateFailoverRoundRobinTest.java (added) +++ camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettySimulateFailoverRoundRobinTest.java Wed Mar 10 11:41:57 2010 @@ -0,0 +1,160 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.itest.jetty; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.Test; + +/** + * @version $Revision$ + */ +public class JettySimulateFailoverRoundRobinTest extends CamelTestSupport { + + private String bad = "jetty:http://localhost:8871/bad"; + private String bad2 = "jetty:http://localhost:8872/bad2"; + private String good = "jetty:http://localhost:8873/good"; + private String good2 = "jetty:http://localhost:8874/good2"; + + @Test + public void testJettySimulateFailoverRoundRobin() throws Exception { + getMockEndpoint("mock:bad").expectedMessageCount(1); + getMockEndpoint("mock:bad2").expectedMessageCount(1); + getMockEndpoint("mock:good").expectedMessageCount(1); + getMockEndpoint("mock:good2").expectedMessageCount(0); + + String reply = template.requestBody("direct:start", null, String.class); + assertEquals("Good", reply); + + assertMockEndpointsSatisfied(); + + // reset mocks and send a message again to see that round robin + // continue where it should + resetMocks(); + + getMockEndpoint("mock:bad").expectedMessageCount(0); + getMockEndpoint("mock:bad2").expectedMessageCount(0); + getMockEndpoint("mock:good").expectedMessageCount(0); + getMockEndpoint("mock:good2").expectedMessageCount(1); + + reply = template.requestBody("direct:start", null, String.class); + assertEquals("Also good", reply); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .process(new MyFailoverLoadBalancer(template, bad, bad2, good, good2)); + + from(bad) + .to("mock:bad") + .process(new Processor() { + public void process(Exchange exchange) throws Exception { + exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 500); + exchange.getIn().setBody("Something bad happened"); + } + }); + + from(bad2) + .to("mock:bad2") + .process(new Processor() { + public void process(Exchange exchange) throws Exception { + exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 404); + exchange.getIn().setBody("Not found"); + } + }); + + from(good) + .to("mock:good") + .process(new Processor() { + public void process(Exchange exchange) throws Exception { + exchange.getIn().setBody("Good"); + } + }); + + from(good2) + .to("mock:good2") + .process(new Processor() { + public void process(Exchange exchange) throws Exception { + exchange.getIn().setBody("Also good"); + } + }); + } + }; + } + + /** + * A custom failover processor + */ + public static class MyFailoverLoadBalancer implements Processor { + + private final ProducerTemplate template; + private final List<String> endpoints; + private int counter = -1; + + public MyFailoverLoadBalancer(ProducerTemplate template, String... endpoints) { + this.template = template; + this.endpoints = new ArrayList<String>(Arrays.asList(endpoints)); + } + + public void process(Exchange exchange) throws Exception { + boolean done = false; + while (!done) { + // pick endpoint + if (++counter >= endpoints.size()) { + counter = 0; + } + String endpoint = endpoints.get(counter); + + // process exchange + try { + template.send(endpoint, exchange); + } catch (Exception e) { + exchange.setException(e); + } + + // check whether we are done or prepare for failover + done = exchange.getException() == null; + if (!done) { + prepareExchangeForFailover(exchange); + } + } + } + + private void prepareExchangeForFailover(Exchange exchange) { + exchange.setException(null); + + exchange.setProperty(Exchange.ERRORHANDLER_HANDLED, null); + exchange.setProperty(Exchange.FAILURE_HANDLED, null); + exchange.setProperty(Exchange.EXCEPTION_CAUGHT, null); + exchange.getIn().removeHeader(Exchange.REDELIVERED); + exchange.getIn().removeHeader(Exchange.REDELIVERY_COUNTER); + } + + } + +} \ No newline at end of file Propchange: camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettySimulateFailoverRoundRobinTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettySimulateFailoverRoundRobinTest.java ------------------------------------------------------------------------------ svn:keywords = Rev Date Added: camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettySpringFailoverRoundRobinTest.java URL: http://svn.apache.org/viewvc/camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettySpringFailoverRoundRobinTest.java?rev=921314&view=auto ============================================================================== --- camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettySpringFailoverRoundRobinTest.java (added) +++ camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettySpringFailoverRoundRobinTest.java Wed Mar 10 11:41:57 2010 @@ -0,0 +1,59 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.itest.jetty; + +import org.apache.camel.test.junit4.CamelSpringTestSupport; +import org.junit.Test; +import org.springframework.context.support.AbstractXmlApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @version $Revision$ + */ +public class JettySpringFailoverRoundRobinTest extends CamelSpringTestSupport { + + @Override + protected AbstractXmlApplicationContext createApplicationContext() { + return new ClassPathXmlApplicationContext("org/apache/camel/itest/jetty/JettySpringFailoverRoundRobinTest.xml"); + } + + @Test + public void testJettySpringFailoverRoundRobin() throws Exception { + getMockEndpoint("mock:bad").expectedMessageCount(1); + getMockEndpoint("mock:bad2").expectedMessageCount(1); + getMockEndpoint("mock:good").expectedMessageCount(1); + getMockEndpoint("mock:good2").expectedMessageCount(0); + + String reply = template.requestBody("direct:start", null, String.class); + assertEquals("Good", reply); + + assertMockEndpointsSatisfied(); + + // reset mocks and send a message again to see that round robin + // continue where it should + resetMocks(); + + getMockEndpoint("mock:bad").expectedMessageCount(0); + getMockEndpoint("mock:bad2").expectedMessageCount(0); + getMockEndpoint("mock:good").expectedMessageCount(0); + getMockEndpoint("mock:good2").expectedMessageCount(1); + + reply = template.requestBody("direct:start", null, String.class); + assertEquals("Also good", reply); + } + +} \ No newline at end of file Propchange: camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettySpringFailoverRoundRobinTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: camel/trunk/tests/camel-itest/src/test/java/org/apache/camel/itest/jetty/JettySpringFailoverRoundRobinTest.java ------------------------------------------------------------------------------ svn:keywords = Rev Date Copied: camel/trunk/tests/camel-itest/src/test/resources/org/apache/camel/itest/jetty/JettySpringFailoverRoundRobinTest.xml (from r921278, camel/trunk/tests/camel-itest/src/test/resources/org/apache/camel/itest/jetty/JettyJmsTest-context.xml) URL: http://svn.apache.org/viewvc/camel/trunk/tests/camel-itest/src/test/resources/org/apache/camel/itest/jetty/JettySpringFailoverRoundRobinTest.xml?p2=camel/trunk/tests/camel-itest/src/test/resources/org/apache/camel/itest/jetty/JettySpringFailoverRoundRobinTest.xml&p1=camel/trunk/tests/camel-itest/src/test/resources/org/apache/camel/itest/jetty/JettyJmsTest-context.xml&r1=921278&r2=921314&rev=921314&view=diff ============================================================================== --- camel/trunk/tests/camel-itest/src/test/resources/org/apache/camel/itest/jetty/JettyJmsTest-context.xml (original) +++ camel/trunk/tests/camel-itest/src/test/resources/org/apache/camel/itest/jetty/JettySpringFailoverRoundRobinTest.xml Wed Mar 10 11:41:57 2010 @@ -17,31 +17,60 @@ --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd "> - <bean id="jms" class="org.apache.activemq.camel.component.ActiveMQComponent"> - <property name="brokerURL" value="vm://localhost?broker.persistent=false"/> - </bean> + <camelContext xmlns="http://camel.apache.org/schema/spring"> + <endpoint id="bad" uri="jetty:http://localhost:8871/bar"/> + <endpoint id="bad2" uri="jetty:http://localhost:8872/bad2"/> + <endpoint id="good" uri="jetty:http://localhost:8873/good"/> + <endpoint id="good2" uri="jetty:http://localhost:8874/good2"/> - <bean id="setExchangePatternProcessor" class="org.apache.camel.itest.jetty.SetExchangePatternProcessor"/> + <!-- START SNIPPET: e1 --> + <route> + <from uri="direct:start"/> + <!-- load balance using failover in round robin mode. + Also do not inherit error handler which means the failover LB will not fallback + and use error handler but trigger failover to next endpoint immediately --> + <loadBalance inheritErrorHandler="false"> + <failover roundRobin="true"/> + <!-- and this is the four endpoints we will load balance with failover --> + <to ref="bad"/> + <to ref="bad2"/> + <to ref="good"/> + <to ref="good2"/> + </loadBalance> + </route> + <!-- END SNIPPET: e1 --> - <!-- START SNIPPET: example --> - <camelContext xmlns="http://camel.apache.org/schema/spring" trace="true"> <route> - <from uri="jetty:http://localhost:9000/test"/> - <to uri="log:MyCategory?level=INFO"/> - <process ref="setExchangePatternProcessor"/> - <to uri="jms:responseQueue"/> + <from ref="bad"/> + <to uri="mock:bad"/> + <setHeader headerName="CamelHttpResponseCode"><constant>500</constant></setHeader> + <setBody><constant>Something bad happened</constant></setBody> </route> + <route> - <from uri="jms:responseQueue"/> - <to uri="mock:resultEndpoint"/> + <from ref="bad2"/> + <to uri="mock:bad2"/> + <setHeader headerName="CamelHttpResponseCode"><constant>404</constant></setHeader> + <setBody><constant>Not found</constant></setBody> </route> + + <route> + <from ref="good"/> + <to uri="mock:good"/> + <setBody><constant>Good</constant></setBody> + </route> + + <route> + <from ref="good2"/> + <to uri="mock:good2"/> + <setBody><constant>Also good</constant></setBody> + </route> + </camelContext> - <!-- END SNIPPET: example --> </beans>