/* * 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.discovery.commons.providers.base; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import java.lang.reflect.Field; import java.util.Random; import java.util.UUID; import java.util.concurrent.locks.ReentrantLock; import org.apache.log4j.Level; import org.apache.log4j.spi.RootLogger; import org.apache.sling.commons.testing.junit.categories.Slow; import org.apache.sling.discovery.commons.providers.BaseTopologyView; import org.apache.sling.discovery.commons.providers.DefaultClusterView; import org.apache.sling.discovery.commons.providers.DummyTopologyView; import org.apache.sling.discovery.commons.providers.EventHelper; import org.apache.sling.discovery.commons.providers.base.ViewStateManagerImpl; import org.apache.sling.discovery.commons.providers.spi.ClusterSyncService; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TestMinEventDelayHandler { private final Logger logger = LoggerFactory.getLogger(this.getClass()); private ViewStateManagerImpl mgr; private Random defaultRandom; private DummyDiscoveryService sds; private Level logLevel; private DummyScheduler scheduler; @Before public void setup() throws Exception { mgr = new ViewStateManagerImpl(new ReentrantLock(), new ClusterSyncService() { @Override public void sync(BaseTopologyView view, Runnable callback) { callback.run(); } @Override public void cancelSync() { // nothing to cancel, we're auto-run } }); defaultRandom = new Random(1234123412); // I want randomness yes, but deterministic, for some methods at least scheduler = new DummyScheduler(); sds = new DummyDiscoveryService(); mgr.installMinEventDelayHandler(sds, scheduler, 1); final org.apache.log4j.Logger discoveryLogger = RootLogger.getLogger("org.apache.sling.discovery"); logLevel = discoveryLogger.getLevel(); discoveryLogger.setLevel(Level.INFO); // changed from Level.DEBUG } @After public void teardown() throws Exception { mgr = null; defaultRandom= null; final org.apache.log4j.Logger discoveryLogger = RootLogger.getLogger("org.apache.sling.discovery"); discoveryLogger.setLevel(logLevel); } @Test public void testReactivate() throws Exception { logger.info("testReactivate: start"); // install a minEventDelayHandler with a longer delay of 2sec mgr.installMinEventDelayHandler(sds, scheduler, 2); final DummyListener listener = new DummyListener(); logger.info("testReactivate: calling handleActivated"); mgr.bind(listener); mgr.handleActivated(); TestHelper.assertNoEvents(listener); final DummyTopologyView view1 = new DummyTopologyView().addInstance(); final DummyTopologyView view2 = DummyTopologyView.clone(view1).addInstance(UUID.randomUUID().toString(), (DefaultClusterView) view1.getLocalInstance().getClusterView(), false, false); final DummyTopologyView view3 = DummyTopologyView.clone(view1).addInstance(UUID.randomUUID().toString(), (DefaultClusterView) view1.getLocalInstance().getClusterView(), false, false); logger.info("testReactivate: calling handleNewView..."); mgr.handleNewView(view1); logger.info("testReactivate: asserting init event"); TestHelper.assertEvents(mgr, listener, EventHelper.newInitEvent(view1)); logger.info("testReactivate: calling handleChanging..."); mgr.handleChanging(); TestHelper.assertEvents(mgr, listener, EventHelper.newChangingEvent(view1)); logger.info("testReactivate: calling handleNewView 2nd time..."); mgr.handleNewView(view2); TestHelper.assertNoEvents(listener); // make sure the MinEventDelayHandler finds a topology when coming back from the delaying, so: sds.setTopoology(view2); logger.info("testReactivate: waiting for async events to have been processed - 4sec"); Thread.sleep(4000); logger.info("testReactivate: waiting for async events to have been processed - max another 2sec"); assertEquals(0, mgr.waitForAsyncEvents(2000)); logger.info("testReactivate: asserting CHANGED event"); TestHelper.assertEvents(mgr, listener, EventHelper.newChangedEvent(view1, view2)); // now do the above again, but this time do a handleDeactivated before receiving another changed event logger.info("testReactivate: calling handleChanging..."); mgr.handleChanging(); TestHelper.assertEvents(mgr, listener, EventHelper.newChangingEvent(view2)); logger.info("testReactivate: calling handleNewView 2nd time..."); mgr.handleNewView(view3); TestHelper.assertNoEvents(listener); // make sure the MinEventDelayHandler finds a topology when coming back from the delaying, so: sds.setTopoology(view3); logger.info("testReactivate: doing handleDeactivated"); final AsyncEventSender asyncEventSender = mgr.getAsyncEventSender(); Field field = mgr.getClass().getDeclaredField("minEventDelayHandler"); field.setAccessible(true); MinEventDelayHandler minEventDelayHandler = (MinEventDelayHandler) field.get(mgr); assertNotNull(minEventDelayHandler); // marking view3 as not current view3.setNotCurrent(); sds.setTopoology(view3); mgr.handleDeactivated(); TestHelper.assertNoEvents(listener); logger.info("testReactivate: now waiting 5 sec to make sure the MinEventDelayHandler would be finished"); TestHelper.assertNoEvents(listener); Thread.sleep(5000); logger.info("testReactivate: after those 5 sec there should however still not be any new event"); TestHelper.assertNoEvents(listener); int cnt = asyncEventSender.getInFlightEventCnt(); if (minEventDelayHandler!=null && minEventDelayHandler.isDelaying()) { cnt++; } assertEquals(0, cnt); } private void assertNoEvents(DummyListener listener) { assertEquals(0, listener.countEvents()); } @Category(Slow.class) //TODO test takes env 50sec @Test public void testNormalDelaying() throws Exception { final DummyListener listener = new DummyListener(); // first activate logger.info("testNormalDelaying: calling handleActivated..."); mgr.handleActivated(); assertNoEvents(listener); // paranoia // then bind logger.info("testNormalDelaying: calling bind..."); mgr.bind(listener); assertNoEvents(listener); // there was no changing or changed yet logger.info("testNormalDelaying: calling handleChanging..."); mgr.handleChanging(); assertNoEvents(listener); final BaseTopologyView view = new DummyTopologyView().addInstance(); logger.info("testNormalDelaying: calling handleNewView..."); mgr.handleNewView(view); TestHelper.assertEvents(mgr, listener, EventHelper.newInitEvent(view)); for(int i=0; i<7; i++) { logger.info("testNormalDelaying: calling randomEventLoop..."); TestHelper.randomEventLoop(mgr, sds, 4, 1500, defaultRandom, listener); Thread.sleep(1000); } } @Category(Slow.class) //TODO test takes env 45sec @Test public void testFailedDelaying() throws Exception { scheduler.failMode(); final DummyListener listener = new DummyListener(); // first activate mgr.handleActivated(); assertNoEvents(listener); // paranoia // then bind mgr.bind(listener); assertNoEvents(listener); // there was no changing or changed yet mgr.handleChanging(); assertNoEvents(listener); final BaseTopologyView view = new DummyTopologyView().addInstance(); mgr.handleNewView(view); TestHelper.assertEvents(mgr, listener, EventHelper.newInitEvent(view)); for(int i=0; i<7; i++) { TestHelper.randomEventLoop(mgr, sds, 100, -1, defaultRandom, listener); Thread.sleep(1000); } } @Test public void testLongMinDelay() throws Exception { mgr.installMinEventDelayHandler(sds, scheduler, 5); final DummyListener listener = new DummyListener(); // first activate logger.info("testLongMinDelay: calling handleActivated..."); mgr.handleActivated(); assertNoEvents(listener); // paranoia // then bind logger.info("testLongMinDelay: calling bind..."); mgr.bind(listener); assertNoEvents(listener); // there was no changing or changed yet logger.info("testLongMinDelay: calling handleChanging..."); mgr.handleChanging(); assertNoEvents(listener); final DummyTopologyView view = new DummyTopologyView().addInstance(); DummyTopologyView clonedView = view.clone(); logger.info("testLongMinDelay: calling handleNewView..."); mgr.handleNewView(view); TestHelper.assertEvents(mgr, listener, EventHelper.newInitEvent(view)); final DummyTopologyView view2 = new DummyTopologyView().addInstance(); view2.addInstance(UUID.randomUUID().toString(), (DefaultClusterView) view2.getLocalInstance().getClusterView(), false, false); logger.info("testLongMinDelay: calling handleNewView..."); clonedView.setNotCurrent(); mgr.handleNewView(view2); TestHelper.assertEvents(mgr, listener, EventHelper.newChangingEvent(clonedView)); assertFalse(view.isCurrent()); } }