/*
* Copyright 2015-2016 the original author or authors.
*
* 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.springframework.integration.zookeeper.event;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import java.util.Collections;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.SmartLifecycle;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.leader.DefaultCandidate;
import org.springframework.integration.leader.event.AbstractLeaderEvent;
import org.springframework.integration.leader.event.DefaultLeaderEventPublisher;
import org.springframework.integration.leader.event.LeaderEventPublisher;
import org.springframework.integration.leader.event.OnGrantedEvent;
import org.springframework.integration.leader.event.OnRevokedEvent;
import org.springframework.integration.support.SmartLifecycleRoleController;
import org.springframework.integration.zookeeper.ZookeeperTestSupport;
import org.springframework.integration.zookeeper.leader.LeaderInitiator;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
/**
* @author Gary Russell
* @since 4.2
*
*/
public class ZookeeperLeaderTests extends ZookeeperTestSupport {
private final BlockingQueue<AbstractLeaderEvent> events = new LinkedBlockingQueue<AbstractLeaderEvent>();
private final SourcePollingChannelAdapter adapter = buildChannelAdapter();
private final SmartLifecycleRoleController controller = new SmartLifecycleRoleController(
Collections.singletonList("sitest"), Collections.<SmartLifecycle>singletonList(this.adapter));
private final CountDownLatch yieldBarrier = new CountDownLatch(1);
@Test
public void testLeader() throws Exception {
assertFalse(this.adapter.isRunning());
LeaderEventPublisher publisher = publisher();
DefaultCandidate candidate1 = new DefaultCandidate("foo", "sitest");
LeaderInitiator initiator1 = new LeaderInitiator(this.client, candidate1, "/sitest");
initiator1.setLeaderEventPublisher(publisher);
initiator1.start();
DefaultCandidate candidate2 = new DefaultCandidate("bar", "sitest");
LeaderInitiator initiator2 = new LeaderInitiator(this.client, candidate2, "/sitest");
initiator2.setLeaderEventPublisher(publisher);
initiator2.start();
AbstractLeaderEvent event = this.events.poll(30, TimeUnit.SECONDS);
assertNotNull(event);
assertThat(event, instanceOf(OnGrantedEvent.class));
assertTrue(this.adapter.isRunning());
event.getContext().yield();
event = this.events.poll(30, TimeUnit.SECONDS);
assertNotNull(event);
assertThat(event, instanceOf(OnRevokedEvent.class));
assertFalse(this.adapter.isRunning());
this.yieldBarrier.countDown();
event = this.events.poll(30, TimeUnit.SECONDS);
assertNotNull(event);
assertThat(event, instanceOf(OnGrantedEvent.class));
assertTrue(this.adapter.isRunning());
initiator1.stop();
initiator2.stop();
event = this.events.poll(30, TimeUnit.SECONDS);
assertNotNull(event);
assertThat(event, instanceOf(OnRevokedEvent.class));
assertFalse(this.adapter.isRunning());
}
private LeaderEventPublisher publisher() {
return new DefaultLeaderEventPublisher(new ApplicationEventPublisher() {
volatile boolean onRevokedEventHappened;
@Override
public void publishEvent(Object event) {
}
@Override
public void publishEvent(ApplicationEvent event) {
AbstractLeaderEvent leadershipEvent = (AbstractLeaderEvent) event;
if (this.onRevokedEventHappened) {
try {
yieldBarrier.await(10, TimeUnit.SECONDS);
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
onRevokedEventHappened = event instanceof OnRevokedEvent;
controller.onApplicationEvent((AbstractLeaderEvent) event);
events.add(leadershipEvent);
}
});
}
private SourcePollingChannelAdapter buildChannelAdapter() {
SourcePollingChannelAdapter adapter = new SourcePollingChannelAdapter();
adapter.setSource(mock(MessageSource.class));
adapter.setOutputChannel(new QueueChannel());
adapter.setTrigger(mock(Trigger.class));
adapter.setBeanFactory(mock(BeanFactory.class));
adapter.setTaskScheduler(mock(TaskScheduler.class));
adapter.afterPropertiesSet();
return adapter;
}
}