/** * 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.component.zookeeper.policy; import java.util.concurrent.TimeUnit; import org.apache.camel.CamelContext; import org.apache.camel.ExchangePattern; import org.apache.camel.ProducerTemplate; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.mock.MockEndpoint; import org.apache.camel.component.zookeeper.ZooKeeperTestSupport; import org.apache.camel.impl.DefaultCamelContext; import org.apache.commons.logging.LogFactory; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.hamcrest.CoreMatchers.is; public class FailoverCuratorLeaderRoutePolicyTest extends ZooKeeperTestSupport { public static final String ZNODE = "/curatorleader"; public static final String BASE_ZNODE = "/someapp"; private static final Logger LOG = LoggerFactory.getLogger(FailoverCuratorLeaderRoutePolicyTest.class); protected CamelContext createCamelContext() throws Exception { disableJMX(); return super.createCamelContext(); } @Test public void masterSlaveScenarioContolledByPolicy() throws Exception { ZookeeperPolicyEnforcedContext master = createEnforcedContext("master"); ZookeeperPolicyEnforcedContext slave = createEnforcedContext("slave"); Thread.sleep(5000); // Send messages to the master and the slave. // The route is enabled in the master and gets through, but that sent to // the slave context is rejected. master.sendMessageToEnforcedRoute("message for master", 1); slave.sendMessageToEnforcedRoute("message for slave", 0); // trigger failover by killing the master... then assert that the slave // can now receive messages. master.shutdown(); slave.sendMessageToEnforcedRoute("second message for slave", 1); slave.shutdown(); } @Test public void ensureRoutesDoNotStartBeforeElection() throws Exception { DefaultCamelContext context = new DefaultCamelContext(); context.addRoutes(new RouteBuilder() { @Override public void configure() throws Exception { CuratorLeaderRoutePolicy policy = new CuratorLeaderRoutePolicy("zookeeper:localhost:" + getServerPort() + BASE_ZNODE + ZNODE + 2); from("timer://foo?fixedRate=true&period=5").routePolicy(policy).id("single_route").autoStartup(true).to("mock:controlled"); } }); context.start(); // this check verifies that a route marked as autostartable is not started automatically. It will be the policy responsibility to eventually start it. assertThat(context.getRouteStatus("single_route").isStarted(), is(false)); assertThat(context.getRouteStatus("single_route").isStarting(), is(false)); context.shutdown(); } private static class ZookeeperPolicyEnforcedContext { private CamelContext controlledContext; private ProducerTemplate template; private MockEndpoint mock; private String routename; ZookeeperPolicyEnforcedContext(String name) throws Exception { controlledContext = new DefaultCamelContext(); routename = name; template = controlledContext.createProducerTemplate(); mock = controlledContext.getEndpoint("mock:controlled", MockEndpoint.class); controlledContext.addRoutes(new FailoverRoute(name)); controlledContext.start(); } public void sendMessageToEnforcedRoute(String message, int expected) throws InterruptedException { mock.expectedMessageCount(expected); try { template.sendBody("vm:" + routename, ExchangePattern.InOut, message); } catch (Exception e) { if (expected > 0) { LOG.error(e.getMessage(), e); fail("Expected messages..."); } } mock.await(2, TimeUnit.SECONDS); mock.assertIsSatisfied(2000); } public void shutdown() throws Exception { LogFactory.getLog(getClass()).debug("stopping"); controlledContext.stop(); LogFactory.getLog(getClass()).debug("stopped"); } } private ZookeeperPolicyEnforcedContext createEnforcedContext(String name) throws Exception, InterruptedException { ZookeeperPolicyEnforcedContext context = new ZookeeperPolicyEnforcedContext(name); delay(1000); return context; } public static class FailoverRoute extends RouteBuilder { private String routename; public FailoverRoute(String routename) { // need names as if we use the same direct ep name in two contexts // in the same vm shutting down one context shuts the endpoint for // both. this.routename = routename; } public void configure() throws Exception { CuratorLeaderRoutePolicy policy = new CuratorLeaderRoutePolicy("zookeeper:localhost:" + getServerPort() + BASE_ZNODE + ZNODE); from("vm:" + routename).routePolicy(policy).id(routename).to("mock:controlled"); } } }