| /* |
| * 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.oak; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| |
| import java.util.UUID; |
| |
| import org.apache.sling.api.resource.ResourceResolver; |
| import org.apache.sling.api.resource.ResourceResolverFactory; |
| import org.apache.sling.discovery.base.its.setup.VirtualInstance; |
| import org.apache.sling.discovery.commons.providers.base.DummyListener; |
| import org.apache.sling.discovery.commons.providers.spi.base.DescriptorHelper; |
| import org.apache.sling.discovery.commons.providers.spi.base.DiscoveryLiteConfig; |
| import org.apache.sling.discovery.commons.providers.spi.base.DiscoveryLiteDescriptorBuilder; |
| import org.apache.sling.discovery.commons.providers.spi.base.DummySlingSettingsService; |
| import org.apache.sling.discovery.commons.providers.spi.base.IdMapService; |
| import org.apache.sling.discovery.oak.its.setup.OakVirtualInstanceBuilder; |
| import org.apache.sling.discovery.oak.its.setup.SimulatedLeaseCollection; |
| import org.junit.Test; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| public class OakDiscoveryServiceTest { |
| |
| private final Logger logger = LoggerFactory.getLogger(this.getClass()); |
| |
| public final class SimpleCommonsConfig implements DiscoveryLiteConfig { |
| |
| private long bgIntervalMillis; |
| private long bgTimeoutMillis; |
| |
| SimpleCommonsConfig(long bgIntervalMillis, long bgTimeoutMillis) { |
| this.bgIntervalMillis = bgIntervalMillis; |
| this.bgTimeoutMillis = bgTimeoutMillis; |
| } |
| |
| @Override |
| public String getSyncTokenPath() { |
| return "/var/synctokens"; |
| } |
| |
| @Override |
| public String getIdMapPath() { |
| return "/var/idmap"; |
| } |
| |
| @Override |
| public long getClusterSyncServiceTimeoutMillis() { |
| return bgTimeoutMillis; |
| } |
| |
| @Override |
| public long getClusterSyncServiceIntervalMillis() { |
| return bgIntervalMillis; |
| } |
| |
| } |
| |
| @Test |
| public void testBindBeforeActivate() throws Exception { |
| OakVirtualInstanceBuilder builder = |
| (OakVirtualInstanceBuilder) new OakVirtualInstanceBuilder() |
| .setDebugName("test") |
| .newRepository("/foo/bar", true); |
| String slingId = UUID.randomUUID().toString();; |
| DiscoveryLiteDescriptorBuilder discoBuilder = new DiscoveryLiteDescriptorBuilder(); |
| discoBuilder.id("id").me(1).activeIds(1); |
| // make sure the discovery-lite descriptor is marked as not final |
| // such that the view is not already set before we want it to be |
| discoBuilder.setFinal(false); |
| DescriptorHelper.setDiscoveryLiteDescriptor(builder.getResourceResolverFactory(), |
| discoBuilder); |
| IdMapService idMapService = IdMapService.testConstructor(new SimpleCommonsConfig(1000, -1), new DummySlingSettingsService(slingId), builder.getResourceResolverFactory()); |
| assertTrue(idMapService.waitForInit(2000)); |
| OakDiscoveryService discoveryService = (OakDiscoveryService) builder.getDiscoverService(); |
| assertNotNull(discoveryService); |
| DummyListener listener = new DummyListener(); |
| for(int i=0; i<100; i++) { |
| discoveryService.bindTopologyEventListener(listener); |
| discoveryService.unbindTopologyEventListener(listener); |
| } |
| discoveryService.bindTopologyEventListener(listener); |
| assertEquals(0, listener.countEvents()); |
| discoveryService.activate(null); |
| assertEquals(0, listener.countEvents()); |
| // some more confusion... |
| discoveryService.unbindTopologyEventListener(listener); |
| discoveryService.bindTopologyEventListener(listener); |
| // only set the final flag now - this makes sure that handlePotentialTopologyChange |
| // will actually detect a valid new, different view and send out an event - |
| // exactly as we want to |
| discoBuilder.setFinal(true); |
| DescriptorHelper.setDiscoveryLiteDescriptor(builder.getResourceResolverFactory(), |
| discoBuilder); |
| discoveryService.checkForTopologyChange(); |
| assertEquals(0, discoveryService.getViewStateManager().waitForAsyncEvents(2000)); |
| assertEquals(1, listener.countEvents()); |
| discoveryService.unbindTopologyEventListener(listener); |
| assertEquals(1, listener.countEvents()); |
| discoveryService.bindTopologyEventListener(listener); |
| assertEquals(0, discoveryService.getViewStateManager().waitForAsyncEvents(2000)); |
| assertEquals(2, listener.countEvents()); // should now have gotten an INIT too |
| } |
| |
| @Test |
| public void testDescriptorSeqNumChange() throws Exception { |
| logger.info("testDescriptorSeqNumChange: start"); |
| OakVirtualInstanceBuilder builder1 = |
| (OakVirtualInstanceBuilder) new OakVirtualInstanceBuilder() |
| .setDebugName("instance1") |
| .newRepository("/foo/barry/foo/", true) |
| .setConnectorPingInterval(999) |
| .setConnectorPingTimeout(999); |
| VirtualInstance instance1 = builder1.build(); |
| OakVirtualInstanceBuilder builder2 = |
| (OakVirtualInstanceBuilder) new OakVirtualInstanceBuilder() |
| .setDebugName("instance2") |
| .useRepositoryOf(instance1) |
| .setConnectorPingInterval(999) |
| .setConnectorPingTimeout(999); |
| VirtualInstance instance2 = builder2.build(); |
| logger.info("testDescriptorSeqNumChange: created both instances, binding listener..."); |
| |
| DummyListener listener = new DummyListener(); |
| OakDiscoveryService discoveryService = (OakDiscoveryService) instance1.getDiscoveryService(); |
| discoveryService.bindTopologyEventListener(listener); |
| |
| logger.info("testDescriptorSeqNumChange: waiting 2sec, listener should not get anything yet"); |
| assertEquals(0, discoveryService.getViewStateManager().waitForAsyncEvents(2000)); |
| assertEquals(0, listener.countEvents()); |
| |
| logger.info("testDescriptorSeqNumChange: issuing 2 heartbeats with each instance should let the topology get established"); |
| instance1.heartbeatsAndCheckView(); |
| instance2.heartbeatsAndCheckView(); |
| instance1.heartbeatsAndCheckView(); |
| instance2.heartbeatsAndCheckView(); |
| |
| logger.info("testDescriptorSeqNumChange: listener should get an event within 2sec from now at latest"); |
| assertEquals(0, discoveryService.getViewStateManager().waitForAsyncEvents(2000)); |
| assertEquals(1, listener.countEvents()); |
| |
| ResourceResolverFactory factory = instance1.getResourceResolverFactory(); |
| ResourceResolver resolver = factory.getServiceResourceResolver(null); |
| |
| instance1.heartbeatsAndCheckView(); |
| assertEquals(0, discoveryService.getViewStateManager().waitForAsyncEvents(2000)); |
| assertEquals(1, listener.countEvents()); |
| |
| // increment the seqNum by 2 - simulating a coming and going instance |
| // while we were sleeping |
| SimulatedLeaseCollection c = builder1.getSimulatedLeaseCollection(); |
| c.incSeqNum(2); |
| logger.info("testDescriptorSeqNumChange: incremented seqnum by 2 - issuing another heartbeat should trigger a topology change"); |
| instance1.heartbeatsAndCheckView(); |
| |
| // due to the nature of the syncService/minEventDelay we now explicitly first sleep 2sec before waiting for async events for another 2sec |
| logger.info("testDescriptorSeqNumChange: sleeping 2sec for topology change to happen"); |
| Thread.sleep(2000); |
| logger.info("testDescriptorSeqNumChange: ensuring no async events are still in the pipe - for another 2sec"); |
| assertEquals(0, discoveryService.getViewStateManager().waitForAsyncEvents(2000)); |
| logger.info("testDescriptorSeqNumChange: now listener should have received 3 events, it got: "+listener.countEvents()); |
| assertEquals(3, listener.countEvents()); |
| } |
| |
| } |