blob: 486b8234c5719c8965676287ba7f3d3d60ab8a63 [file] [log] [blame]
/*
* 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.sling.event.impl.jobs.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.sling.commons.scheduler.ScheduleOptions;
import org.apache.sling.commons.scheduler.Scheduler;
import org.apache.sling.discovery.ClusterView;
import org.apache.sling.discovery.InstanceDescription;
import org.apache.sling.discovery.TopologyEvent;
import org.apache.sling.discovery.TopologyEventListener;
import org.apache.sling.discovery.TopologyView;
import org.apache.sling.discovery.commons.InitDelayingTopologyEventListener;
import org.apache.sling.event.impl.TestUtil;
import org.junit.Test;
import org.mockito.Mockito;
public class JobManagerConfigurationTest {
private TopologyView createView() {
final TopologyView view = Mockito.mock(TopologyView.class);
Mockito.when(view.isCurrent()).thenReturn(true);
final InstanceDescription local = Mockito.mock(InstanceDescription.class);
Mockito.when(local.isLeader()).thenReturn(true);
Mockito.when(local.isLocal()).thenReturn(true);
Mockito.when(local.getSlingId()).thenReturn("id");
Mockito.when(view.getLocalInstance()).thenReturn(local);
final ClusterView localView = Mockito.mock(ClusterView.class);
Mockito.when(localView.getId()).thenReturn("1");
Mockito.when(localView.getInstances()).thenReturn(Collections.singletonList(local));
Mockito.when(view.getClusterViews()).thenReturn(Collections.singleton(localView));
Mockito.when(local.getClusterView()).thenReturn(localView);
return view;
}
private static class ChangeListener implements ConfigurationChangeListener {
public final List<Boolean> events = new ArrayList<Boolean>();
private volatile CountDownLatch latch;
public void init(final int count) {
events.clear();
latch = new CountDownLatch(count);
}
public void await() throws Exception {
if ( !latch.await(8000, TimeUnit.MILLISECONDS) ) {
throw new Exception("No configuration event within 8 seconds.");
}
}
@Override
public void configurationChanged(boolean active) {
events.add(active);
latch.countDown();
}
}
private Scheduler createScheduler() {
return new Scheduler() {
@Override
public boolean unschedule(String jobName) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean schedule(final Object job, ScheduleOptions options) {
if ( job instanceof Runnable ) {
final Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
((Runnable)job).run();
}
}, 3000);
return true;
}
return false;
}
@Override
public void removeJob(String name) throws NoSuchElementException {
// TODO Auto-generated method stub
}
@Override
public boolean fireJobAt(String name, Object job, Map<String, Serializable> config, Date date, int times,
long period) {
// TODO Auto-generated method stub
return false;
}
@Override
public void fireJobAt(String name, Object job, Map<String, Serializable> config, Date date) throws Exception {
// TODO Auto-generated method stub
}
@Override
public boolean fireJob(Object job, Map<String, Serializable> config, int times, long period) {
// TODO Auto-generated method stub
return false;
}
@Override
public void fireJob(Object job, Map<String, Serializable> config) throws Exception {
// TODO Auto-generated method stub
}
@Override
public void addPeriodicJob(String name, Object job, Map<String, Serializable> config, long period,
boolean canRunConcurrently, boolean startImmediate) throws Exception {
// TODO Auto-generated method stub
}
@Override
public void addPeriodicJob(String name, Object job, Map<String, Serializable> config, long period,
boolean canRunConcurrently) throws Exception {
// TODO Auto-generated method stub
}
@Override
public void addJob(String name, Object job, Map<String, Serializable> config, String schedulingExpression,
boolean canRunConcurrently) throws Exception {
// TODO Auto-generated method stub
}
@Override
public ScheduleOptions NOW(int times, long period) {
// TODO Auto-generated method stub
return null;
}
@Override
public ScheduleOptions NOW() {
// TODO Auto-generated method stub
return null;
}
@Override
public ScheduleOptions EXPR(String expression) {
// TODO Auto-generated method stub
return null;
}
@Override
public ScheduleOptions AT(Date date, int times, long period) {
// TODO Auto-generated method stub
return null;
}
@Override
public ScheduleOptions AT(Date date) {
// TODO Auto-generated method stub
return null;
}
};
}
@Test public void testTopologyChange() throws Exception {
// mock scheduler
final Scheduler scheduler = this.createScheduler();
final ChangeListener ccl = new ChangeListener();
// add change listener and verify
ccl.init(1);
final JobManagerConfiguration config = new JobManagerConfiguration();
TestUtil.setFieldValue(config, "scheduler", scheduler);
((AtomicBoolean)TestUtil.getFieldValue(config, "active")).set(true);
InitDelayingTopologyEventListener startupDelayListener = new InitDelayingTopologyEventListener(1, new TopologyEventListener() {
@Override
public void handleTopologyEvent(TopologyEvent event) {
config.doHandleTopologyEvent(event);
}
}, scheduler);;
TestUtil.setFieldValue(config, "startupDelayListener", startupDelayListener);
config.addListener(ccl);
ccl.await();
assertEquals(1, ccl.events.size());
assertFalse(ccl.events.get(0));
// create init view
ccl.init(1);
final TopologyView initView = createView();
final TopologyEvent init = new TopologyEvent(TopologyEvent.Type.TOPOLOGY_INIT, null, initView);
config.handleTopologyEvent(init);
ccl.await();
assertEquals(1, ccl.events.size());
assertTrue(ccl.events.get(0));
// change view, followed by change props
ccl.init(2);
final TopologyView view2 = createView();
Mockito.when(initView.isCurrent()).thenReturn(false);
final TopologyEvent change1 = new TopologyEvent(TopologyEvent.Type.TOPOLOGY_CHANGED, initView, view2);
final TopologyView view3 = createView();
final TopologyEvent change2 = new TopologyEvent(TopologyEvent.Type.PROPERTIES_CHANGED, view2, view3);
config.handleTopologyEvent(change1);
Mockito.when(view2.isCurrent()).thenReturn(false);
config.handleTopologyEvent(change2);
ccl.await();
assertEquals(2, ccl.events.size());
assertFalse(ccl.events.get(0));
assertTrue(ccl.events.get(1));
// we wait another 4 secs to see if there is no another event
Thread.sleep(4000);
assertEquals(2, ccl.events.size());
}
}