/** * Licensed 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.aurora.scheduler.discovery; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.function.Predicate; import com.google.common.collect.ImmutableMap; import org.apache.aurora.common.io.Codec; import org.apache.aurora.common.thrift.Endpoint; import org.apache.aurora.common.thrift.ServiceInstance; import org.apache.aurora.common.thrift.Status; import org.apache.aurora.common.zookeeper.ServerSet; import org.apache.aurora.common.zookeeper.testing.BaseZooKeeperTest; import org.apache.aurora.scheduler.app.ServiceGroupMonitor; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.framework.recipes.cache.PathChildrenCache; import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent; import org.junit.Before; class BaseCuratorDiscoveryTest extends BaseZooKeeperTest { static final String GROUP_PATH = "/group/root"; static final String MEMBER_TOKEN = "member_"; static final Codec<ServiceInstance> CODEC = ServerSet.JSON_CODEC; static final int PRIMARY_PORT = 42; private CuratorFramework client; private BlockingQueue<PathChildrenCacheEvent> groupEvents; private CuratorServiceGroupMonitor groupMonitor; @Before public void setUpCurator() { client = startNewClient(); PathChildrenCache groupCache = new PathChildrenCache(client, GROUP_PATH, true /* cacheData */); groupEvents = new LinkedBlockingQueue<>(); groupCache.getListenable().addListener((c, event) -> groupEvents.put(event)); Predicate<String> memberSelector = name -> name.contains(MEMBER_TOKEN); groupMonitor = new CuratorServiceGroupMonitor(groupCache, memberSelector, ServerSet.JSON_CODEC); } final CuratorFramework startNewClient() { CuratorFramework curator = CuratorFrameworkFactory.builder() .dontUseContainerParents() // Container nodes are only available in ZK 3.5+. .retryPolicy((retryCount, elapsedTimeMs, sleeper) -> false) // Don't retry. .connectString(String.format("localhost:%d", getServer().getPort())) .build(); curator.start(); addTearDown(curator::close); return curator; } final void expireSession(CuratorFramework curator) throws Exception { getServer().expireClientSession(curator.getZookeeperClient().getZooKeeper().getSessionId()); } final void causeDisconnection() throws Exception { getServer().stop(); getServer().restartNetwork(); } final CuratorFramework getClient() { return client; } final CuratorServiceGroupMonitor getGroupMonitor() { return groupMonitor; } final void startGroupMonitor() throws ServiceGroupMonitor.MonitorException { groupMonitor.start(); addTearDown(groupMonitor::close); } final void expectGroupEvent(PathChildrenCacheEvent.Type eventType) { while (true) { try { PathChildrenCacheEvent event = groupEvents.take(); if (event.getType() == eventType) { break; } } catch (InterruptedException ex) { throw new RuntimeException(ex); } } } final byte[] serialize(ServiceInstance serviceInstance) throws IOException { ByteArrayOutputStream sink = new ByteArrayOutputStream(); CODEC.serialize(serviceInstance, sink); return sink.toByteArray(); } final ServiceInstance serviceInstance(String hostName) { return new ServiceInstance( new Endpoint(hostName, PRIMARY_PORT), ImmutableMap.of(), Status.ALIVE); } }