You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by st...@apache.org on 2015/10/20 16:12:34 UTC

svn commit: r1709601 [4/11] - in /sling/trunk/bundles/extensions/discovery: base/ base/src/ base/src/main/ base/src/main/java/ base/src/main/java/org/ base/src/main/java/org/apache/ base/src/main/java/org/apache/sling/ base/src/main/java/org/apache/sli...

Added: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/commons/DefaultTopologyViewTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/commons/DefaultTopologyViewTest.java?rev=1709601&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/commons/DefaultTopologyViewTest.java (added)
+++ sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/commons/DefaultTopologyViewTest.java Tue Oct 20 14:12:31 2015
@@ -0,0 +1,209 @@
+/*
+ * 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.base.commons;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Iterator;
+import java.util.Set;
+import java.util.UUID;
+
+import org.apache.sling.discovery.InstanceDescription;
+import org.apache.sling.discovery.InstanceFilter;
+import org.apache.sling.discovery.TopologyEvent.Type;
+import org.apache.sling.discovery.base.its.setup.TopologyHelper;
+import org.apache.sling.discovery.commons.providers.DefaultClusterView;
+import org.apache.sling.discovery.commons.providers.DefaultInstanceDescription;
+import org.junit.Test;
+
+import junitx.util.PrivateAccessor;
+
+public class DefaultTopologyViewTest {
+
+    @Test
+    public void testForcedLeaderChangeCompare() throws Exception {
+        // create view 1 with first instance the leader
+        final String slingId1 = UUID.randomUUID().toString();
+        final DefaultTopologyView view1 = TopologyHelper.createTopologyView(UUID
+                .randomUUID().toString(), slingId1);
+        final DefaultInstanceDescription id2 = TopologyHelper.addInstanceDescription(view1, TopologyHelper
+                .createInstanceDescription(view1.getClusterViews().iterator()
+                        .next()));
+        final String slingId2 = id2.getSlingId();
+        final DefaultInstanceDescription id3 = TopologyHelper.addInstanceDescription(view1, TopologyHelper
+                .createInstanceDescription(view1.getClusterViews().iterator()
+                        .next()));
+        final String slingId3 = id3.getSlingId();
+        
+        // now create view 2 with exactly the same instances as above, but the second instance the leader
+        DefaultTopologyView view2 = TopologyHelper.cloneTopologyView(view1, slingId2);
+        // make sure we've chosen a new leader:
+        assertNotEquals(view1.getClusterViews().iterator().next().getLeader().getSlingId(),
+                view2.getClusterViews().iterator().next().getLeader().getSlingId());
+        // and now test the compare method which should catch the leader change
+        assertTrue(view1.compareTopology(view2)==Type.TOPOLOGY_CHANGED);
+        
+        // same thing now with view3 which takes slingId3 as the leader
+        DefaultTopologyView view3 = TopologyHelper.cloneTopologyView(view1, slingId3);
+        // make sure we've chosen a new leader:
+        assertNotEquals(view1.getClusterViews().iterator().next().getLeader().getSlingId(),
+                view3.getClusterViews().iterator().next().getLeader().getSlingId());
+        // and now test the compare method which should catch the leader change
+        assertTrue(view1.compareTopology(view3)==Type.TOPOLOGY_CHANGED);
+    }
+    
+    @Test
+    public void testCompare() throws Exception {
+
+        DefaultTopologyView newView = TopologyHelper.createTopologyView(UUID
+                .randomUUID().toString(), UUID.randomUUID().toString());
+
+        try {
+            newView.compareTopology(null);
+            fail("Should complain about null");
+        } catch (Exception e) {
+            // ok
+        }
+
+        DefaultTopologyView oldView = TopologyHelper
+                .cloneTopologyView(newView);
+        assertNull(newView.compareTopology(oldView));
+
+        DefaultInstanceDescription id = TopologyHelper
+                .createInstanceDescription(newView.getClusterViews().iterator()
+                        .next());
+        TopologyHelper.addInstanceDescription(newView, id);
+        assertEquals(Type.TOPOLOGY_CHANGED, newView.compareTopology(oldView));
+
+        assertEquals(2, newView.getInstances().size());
+        // addInstanceDescription now no longer throws an exception if you add
+        // the same
+        // instance twice. this provides greater stability
+        TopologyHelper.addInstanceDescription(newView, id);
+        assertEquals(2, newView.getInstances().size());
+        // try{
+        // TopologyTestHelper.addInstanceDescription(newView, id);
+        // fail("should not be able to add twice");
+        // } catch(Exception e) {
+        // // ok
+        // }
+
+        oldView = TopologyHelper.cloneTopologyView(newView);
+        assertNull(newView.compareTopology(oldView));
+
+        DefaultInstanceDescription instance = (DefaultInstanceDescription) newView.getInstances().iterator().next();
+        instance.setProperty("a", "b");
+        assertEquals(Type.PROPERTIES_CHANGED, newView.compareTopology(oldView));
+        oldView = TopologyHelper.cloneTopologyView(newView);
+        assertNull(newView.compareTopology(oldView));
+
+        instance.setProperty("a", "B");
+        assertEquals(Type.PROPERTIES_CHANGED, newView.compareTopology(oldView));
+        oldView = TopologyHelper.cloneTopologyView(newView);
+        assertNull(newView.compareTopology(oldView));
+
+        instance.setProperty("a", "B");
+        assertNull(newView.compareTopology(oldView));
+        
+        // now change the properties of the first instance but modify the second instance' cluster
+        Iterator<InstanceDescription> it = newView.getInstances().iterator();
+        DefaultInstanceDescription firstInstance = (DefaultInstanceDescription) it.next();
+        assertNotNull(firstInstance);
+        DefaultInstanceDescription secondInstance = (DefaultInstanceDescription) it.next();
+        assertNotNull(secondInstance);
+        firstInstance.setProperty("c", "d");
+        DefaultClusterView cluster = new DefaultClusterView(UUID.randomUUID().toString());
+        PrivateAccessor.setField(secondInstance, "clusterView", null);
+        cluster.addInstanceDescription(secondInstance);
+        assertEquals(Type.TOPOLOGY_CHANGED, newView.compareTopology(oldView));
+    }
+
+    @Test
+    public void testFind() throws Exception {
+        DefaultTopologyView newView = TopologyHelper.createTopologyView(UUID
+                .randomUUID().toString(), UUID.randomUUID().toString());
+        TopologyHelper.createAndAddInstanceDescription(newView, newView
+                .getClusterViews().iterator().next());
+
+        try {
+            newView.findInstances(null);
+            fail("should complain");
+        } catch (IllegalArgumentException iae) {
+            // ok
+        }
+
+        final DefaultInstanceDescription id = TopologyHelper
+                .createAndAddInstanceDescription(newView, newView
+                        .getClusterViews().iterator().next());
+        TopologyHelper.createAndAddInstanceDescription(newView, newView
+                .getClusterViews().iterator().next());
+        assertEquals(4, newView.findInstances(new InstanceFilter() {
+
+            public boolean accept(InstanceDescription instance) {
+                return true;
+            }
+        }).size());
+        assertEquals(1, newView.findInstances(new InstanceFilter() {
+
+            public boolean accept(InstanceDescription instance) {
+                return instance.getSlingId().equals(id.getSlingId());
+            }
+        }).size());
+        assertEquals(1, newView.findInstances(new InstanceFilter() {
+
+            public boolean accept(InstanceDescription instance) {
+                return instance.isLeader();
+            }
+        }).size());
+        assertEquals(1, newView.findInstances(new InstanceFilter() {
+            boolean first = true;
+
+            public boolean accept(InstanceDescription instance) {
+                if (!first) {
+                    return false;
+                }
+                first = false;
+                return true;
+            }
+        }).size());
+    }
+
+    @Test
+    public void testGetInstances() throws Exception {
+        DefaultTopologyView newView = TopologyHelper.createTopologyView(UUID
+                .randomUUID().toString(), UUID.randomUUID().toString());
+
+        Set<InstanceDescription> instances = newView.getInstances();
+        assertNotNull(instances);
+
+        try {
+            instances.remove(instances.iterator().next());
+            fail("list should not be modifiable");
+        } catch (Exception e) {
+            // ok
+        }
+
+    }
+
+}

Propchange: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/commons/DefaultTopologyViewTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/commons/DummyDiscoveryService.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/commons/DummyDiscoveryService.java?rev=1709601&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/commons/DummyDiscoveryService.java (added)
+++ sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/commons/DummyDiscoveryService.java Tue Oct 20 14:12:31 2015
@@ -0,0 +1,71 @@
+/*
+ * 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.base.commons;
+
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.commons.scheduler.Scheduler;
+import org.apache.sling.discovery.base.connectors.BaseConfig;
+import org.apache.sling.discovery.base.connectors.announcement.AnnouncementRegistry;
+import org.apache.sling.discovery.base.connectors.ping.ConnectorRegistry;
+
+public class DummyDiscoveryService extends BaseDiscoveryService {
+
+    private final ClusterViewService clusterViewService;
+    private final AnnouncementRegistry topologyRegistry;
+
+    public DummyDiscoveryService(String slingId,
+            ClusterViewService clusterViewService,
+            AnnouncementRegistry topologyRegistry,
+            ResourceResolverFactory resourceResolverFactory, BaseConfig config, 
+            ConnectorRegistry connectorRegistry, Scheduler scheduler) {
+        this.clusterViewService = clusterViewService;
+        this.topologyRegistry = topologyRegistry;
+    }
+    
+    @Override
+    public void updateProperties() {
+        throw new IllegalStateException("updateProperties not yet impl");
+    }
+
+    @Override
+    protected ClusterViewService getClusterViewService() {
+        return clusterViewService;
+    }
+
+    @Override
+    protected AnnouncementRegistry getAnnouncementRegistry() {
+        return topologyRegistry;
+    }
+
+    @Override
+    protected void handleIsolatedFromTopology() {
+        throw new IllegalStateException("handleIsolatedFromTopology not yet impl");
+    }
+    
+    @Override
+    public void handlePotentialTopologyChange() {
+        throw new IllegalStateException("handlePotentialTopologyChange not yet impl");
+    }
+    
+    @Override
+    public void handleTopologyChanging() {
+        throw new IllegalStateException("handleTopologyChanging not yet impl");
+    }
+    
+}

Propchange: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/commons/DummyDiscoveryService.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/DummyVirtualInstanceBuilder.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/DummyVirtualInstanceBuilder.java?rev=1709601&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/DummyVirtualInstanceBuilder.java (added)
+++ sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/DummyVirtualInstanceBuilder.java Tue Oct 20 14:12:31 2015
@@ -0,0 +1,85 @@
+/*
+ * 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.base.connectors;
+
+import org.apache.sling.discovery.base.commons.BaseDiscoveryService;
+import org.apache.sling.discovery.base.commons.ClusterViewService;
+import org.apache.sling.discovery.base.commons.DummyDiscoveryService;
+import org.apache.sling.discovery.base.commons.ViewChecker;
+import org.apache.sling.discovery.base.its.setup.ModifiableTestBaseConfig;
+import org.apache.sling.discovery.base.its.setup.VirtualInstance;
+import org.apache.sling.discovery.base.its.setup.VirtualInstanceBuilder;
+import org.apache.sling.discovery.base.its.setup.mock.DummyViewChecker;
+import org.apache.sling.discovery.base.its.setup.mock.MockFactory;
+import org.apache.sling.discovery.base.its.setup.mock.SimpleClusterViewService;
+import org.apache.sling.discovery.base.its.setup.mock.SimpleConnectorConfig;
+
+public class DummyVirtualInstanceBuilder extends VirtualInstanceBuilder {
+
+    private ModifiableTestBaseConfig connectorConfig;
+
+    public DummyVirtualInstanceBuilder() {
+    }
+
+    @Override
+    public VirtualInstanceBuilder createNewRepository() throws Exception {
+        this.factory = MockFactory.mockResourceResolverFactory();
+        return this;
+    }
+
+    @Override
+    public VirtualInstanceBuilder setPath(String string) {
+        // nothing to do now
+        return this;
+    }
+    
+    @Override
+    public Object[] getAdditionalServices(VirtualInstance instance) throws Exception {
+        return null;
+    }
+    
+    protected ClusterViewService createClusterViewService() {
+        return new SimpleClusterViewService(getSlingId());
+    }
+
+    protected ViewChecker createViewChecker() throws Exception {
+        return DummyViewChecker.testConstructor(getSlingSettingsService(), getResourceResolverFactory(), getConnectorRegistry(), getAnnouncementRegistry(), getScheduler(), getConnectorConfig());
+    }
+
+    protected BaseDiscoveryService createDiscoveryService() throws Exception {
+        return new DummyDiscoveryService(getSlingId(), getClusterViewService(), getAnnouncementRegistry(), getResourceResolverFactory(), getConnectorConfig(), getConnectorRegistry(), getScheduler());
+    }
+
+    @Override
+    public ModifiableTestBaseConfig getConnectorConfig() {
+        if (connectorConfig==null) {
+            connectorConfig = createConnectorConfig();
+        }
+        return connectorConfig;
+    }
+
+    private ModifiableTestBaseConfig createConnectorConfig() {
+        return new SimpleConnectorConfig();
+    }
+    
+    @Override
+    protected void resetRepo() {
+        // does nothing
+    }
+}

Propchange: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/DummyVirtualInstanceBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/LargeTopologyWithHubTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/LargeTopologyWithHubTest.java?rev=1709601&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/LargeTopologyWithHubTest.java (added)
+++ sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/LargeTopologyWithHubTest.java Tue Oct 20 14:12:31 2015
@@ -0,0 +1,123 @@
+/*
+ * 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.base.connectors;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.sling.commons.testing.junit.Retry;
+import org.apache.sling.commons.testing.junit.RetryRule;
+import org.apache.sling.discovery.ClusterView;
+import org.apache.sling.discovery.TopologyView;
+import org.apache.sling.discovery.base.its.setup.TopologyHelper;
+import org.apache.sling.discovery.base.its.setup.VirtualConnector;
+import org.apache.sling.discovery.base.its.setup.VirtualInstance;
+import org.apache.sling.discovery.base.its.setup.VirtualInstanceBuilder;
+import org.apache.sling.testing.tools.sling.TimeoutsProvider;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class LargeTopologyWithHubTest {
+
+    private static final Logger logger = LoggerFactory.getLogger(LargeTopologyWithHubTest.class);
+
+    private static List<VirtualInstance> instances;
+    private static VirtualInstance hub;
+    private static List<String> slingIds;
+    private static final int TEST_SIZE = 50;
+    
+    @Rule
+    public final RetryRule retryRule = new RetryRule();
+
+    private VirtualInstanceBuilder newBuilder() {
+        return new DummyVirtualInstanceBuilder();
+    }
+    
+    @Before
+    public void setup() throws Throwable {
+        instances = new LinkedList<VirtualInstance>();
+        final int defaultHeartbeatTimeout = 3600; // 1 hour should be enough, really
+        final int heartbeatTimeout = TimeoutsProvider.getInstance().getTimeout(defaultHeartbeatTimeout);
+        VirtualInstanceBuilder hubBuilder = newBuilder()
+                .newRepository("/var/discovery/impl/", true)
+                .setDebugName("hub")
+                .setConnectorPingInterval(5)
+                .setConnectorPingTimeout(heartbeatTimeout);
+        hub = hubBuilder.build();
+        instances.add(hub);
+        hub.getConfig().setViewCheckTimeout(heartbeatTimeout);
+//        hub.installVotingOnHeartbeatHandler();
+        hub.heartbeatsAndCheckView();
+        hub.heartbeatsAndCheckView();
+        assertNotNull(hub.getClusterViewService().getLocalClusterView());
+        hub.startViewChecker(1);
+        hub.dumpRepo();
+        
+        slingIds = new LinkedList<String>();
+        slingIds.add(hub.getSlingId());
+        logger.info("setUp: using heartbeatTimeout of "+heartbeatTimeout+"sec "
+                + "(default: "+defaultHeartbeatTimeout+")");
+        for(int i=0; i<TEST_SIZE; i++) {
+            logger.info("setUp: creating instance"+i);
+            VirtualInstanceBuilder builder2 = newBuilder()
+                    .newRepository("/var/discovery/impl/", false)
+                    .setDebugName("instance"+i)
+                    .setConnectorPingInterval(5)
+                    .setConnectorPingTimeout(heartbeatTimeout);
+            VirtualInstance instance = builder2.build();
+            instances.add(instance);
+            instance.getConfig().setViewCheckTimeout(heartbeatTimeout);
+//            instance.installVotingOnHeartbeatHandler();
+            instance.heartbeatsAndCheckView();
+            instance.heartbeatsAndCheckView();
+            ClusterView clusterView = instance.getClusterViewService().getLocalClusterView();
+            assertNotNull(clusterView);
+            new VirtualConnector(instance, hub);
+            slingIds.add(instance.getSlingId());
+        }
+    }
+    
+    @After
+    public void tearDown() throws Exception {
+        for (Iterator<VirtualInstance> it = instances.iterator(); it.hasNext();) {
+            final VirtualInstance instance = it.next();
+            instance.stop();
+        }
+    }
+    
+    @Test
+    @Retry(timeoutMsec=30000, intervalMsec=500)
+    public void testLargeTopologyWithHub() throws Exception {
+        hub.dumpRepo();
+        final TopologyView tv = hub.getDiscoveryService().getTopology();
+        assertNotNull(tv);
+        logger.info(
+                "testLargeTopologyWithHub: checking if all connectors are registered, TopologyView has {} Instances", 
+                tv.getInstances().size());
+        TopologyHelper.assertTopologyConsistsOf(tv, slingIds.toArray(new String[slingIds.size()]));
+        logger.info("testLargeTopologyWithHub: test passed");
+    }
+}
\ No newline at end of file

Propchange: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/LargeTopologyWithHubTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/announcement/AnnouncementRegistryImplTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/announcement/AnnouncementRegistryImplTest.java?rev=1709601&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/announcement/AnnouncementRegistryImplTest.java (added)
+++ sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/announcement/AnnouncementRegistryImplTest.java Tue Oct 20 14:12:31 2015
@@ -0,0 +1,391 @@
+/*
+ * 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.base.connectors.announcement;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.List;
+import java.util.UUID;
+
+import javax.jcr.Session;
+
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.commons.testing.jcr.RepositoryProvider;
+import org.apache.sling.discovery.ClusterView;
+import org.apache.sling.discovery.InstanceDescription;
+import org.apache.sling.discovery.base.connectors.BaseConfig;
+import org.apache.sling.discovery.base.its.setup.TopologyHelper;
+import org.apache.sling.discovery.base.its.setup.VirtualInstanceHelper;
+import org.apache.sling.discovery.base.its.setup.mock.MockFactory;
+import org.apache.sling.discovery.base.its.setup.mock.SimpleConnectorConfig;
+import org.apache.sling.discovery.commons.providers.DefaultClusterView;
+import org.apache.sling.discovery.commons.providers.DefaultInstanceDescription;
+import org.apache.sling.discovery.commons.providers.spi.impl.DummySlingSettingsService;
+import org.junit.Before;
+import org.junit.Test;
+
+public class AnnouncementRegistryImplTest {
+
+    private AnnouncementRegistryImpl registry;
+    private String slingId;
+    private ResourceResolverFactory resourceResolverFactory;
+    private BaseConfig config;
+
+    @Before
+    public void setup() throws Exception {
+        resourceResolverFactory = MockFactory
+                .mockResourceResolverFactory();
+        config = new SimpleConnectorConfig() {
+            public long getConnectorPingTimeout() {
+                // 10s for tests that also run on apache jenkins
+                return 10;
+            };
+        };
+        slingId = UUID.randomUUID().toString();
+        Session l = RepositoryProvider.instance().getRepository()
+                .loginAdministrative(null);
+        try {
+            l.removeItem("/var");
+            l.save();
+            l.logout();
+        } catch (Exception e) {
+            l.refresh(false);
+            l.logout();
+        }
+        registry = AnnouncementRegistryImpl.testConstructorAndActivate(
+                resourceResolverFactory, new DummySlingSettingsService(slingId), config);
+    }
+
+    @Test
+    public void testRegisterUnregister() throws Exception {
+        try{
+            registry.registerAnnouncement(null);
+            fail("should complain");
+        } catch(IllegalArgumentException iae) {
+            // ok
+        }
+        try{
+            registry.unregisterAnnouncement(null);
+            fail("should complain");
+        } catch(IllegalArgumentException iae) {
+            // ok
+        }
+        try{
+            registry.unregisterAnnouncement("");
+            fail("should complain");
+        } catch(IllegalArgumentException iae) {
+            // ok
+        }
+        
+        try{
+            new Announcement(null);
+            fail("should complain");
+        } catch(IllegalArgumentException iae) {
+            // ok
+        }
+        try{
+            new Announcement("");
+            fail("should complain"); 
+        } catch(IllegalArgumentException iae) {
+            // ok
+        }
+        
+        Announcement ann = new Announcement(slingId);
+        assertFalse(ann.isValid());
+        assertFalse(registry.registerAnnouncement(ann)!=-1);
+        
+        DefaultClusterView localCluster = new DefaultClusterView(UUID.randomUUID().toString());
+        ann.setLocalCluster(localCluster);
+        assertFalse(ann.isValid());
+        assertFalse(registry.registerAnnouncement(ann)!=-1);
+
+        try{
+            registry.listInstances(localCluster);
+            fail("doing getInstances() on an empty cluster should throw an illegalstateexception");
+        } catch(IllegalStateException ise) {
+            // ok
+        }
+        
+        DefaultInstanceDescription instance = TopologyHelper.createInstanceDescription(ann.getOwnerId(), true, localCluster);
+        assertEquals(instance.getSlingId(), ann.getOwnerId());
+        assertTrue(ann.isValid());
+        assertTrue(registry.registerAnnouncement(ann)!=-1);
+        
+        assertEquals(1, registry.listInstances(localCluster).size());
+        
+        registry.checkExpiredAnnouncements();
+        assertEquals(1, registry.listInstances(localCluster).size());
+        
+        registry.unregisterAnnouncement(ann.getOwnerId());
+        assertEquals(0, registry.listInstances(localCluster).size());
+        assertTrue(ann.isValid());
+        assertTrue(registry.registerAnnouncement(ann)!=-1);
+        assertEquals(1, registry.listInstances(localCluster).size());
+
+        Thread.sleep(10500);
+        assertEquals(0, registry.listInstances(localCluster).size());
+    
+    }
+    
+    @Test
+    public void testLists() throws Exception {
+        try{
+            registry.listAnnouncementsInSameCluster(null);
+            fail("should complain");
+        } catch(IllegalArgumentException iae) {
+            // ok
+        }
+        try{
+            registry.listAnnouncementsInSameCluster(null);
+            fail("should complain");
+        } catch(IllegalArgumentException iae) {
+            // ok
+        }
+        assertEquals(0, registry.listLocalAnnouncements().size());
+        assertEquals(0, registry.listLocalIncomingAnnouncements().size());
+        DefaultClusterView localCluster = new DefaultClusterView(UUID.randomUUID().toString());
+        DefaultInstanceDescription instance = TopologyHelper.createInstanceDescription(slingId, true, localCluster);        
+        assertEquals(0, registry.listAnnouncementsInSameCluster(localCluster).size());
+        assertEquals(0, registry.listLocalAnnouncements().size());
+        assertEquals(0, registry.listLocalIncomingAnnouncements().size());
+        
+        Announcement ann = new Announcement(slingId);
+        ann.setLocalCluster(localCluster);
+        ann.setInherited(true);
+        registry.registerAnnouncement(ann);
+        assertEquals(1, registry.listAnnouncementsInSameCluster(localCluster).size());
+        assertEquals(1, registry.listLocalAnnouncements().size());
+        assertEquals(0, registry.listLocalIncomingAnnouncements().size());
+        ann.setInherited(true);
+        assertEquals(0, registry.listLocalIncomingAnnouncements().size());
+        assertTrue(registry.hasActiveAnnouncement(slingId));
+        assertFalse(registry.hasActiveAnnouncement(UUID.randomUUID().toString()));
+        registry.unregisterAnnouncement(slingId);
+        assertEquals(0, registry.listAnnouncementsInSameCluster(localCluster).size());
+        assertEquals(0, registry.listLocalAnnouncements().size());
+        assertEquals(0, registry.listLocalIncomingAnnouncements().size());
+        assertFalse(registry.hasActiveAnnouncement(slingId));
+        assertFalse(registry.hasActiveAnnouncement(UUID.randomUUID().toString()));
+        ann.setInherited(false);
+        registry.registerAnnouncement(ann);
+        assertEquals(1, registry.listAnnouncementsInSameCluster(localCluster).size());
+        assertEquals(1, registry.listLocalAnnouncements().size());
+        assertEquals(1, registry.listLocalIncomingAnnouncements().size());
+        assertTrue(registry.hasActiveAnnouncement(slingId));
+        assertFalse(registry.hasActiveAnnouncement(UUID.randomUUID().toString()));
+        registry.unregisterAnnouncement(slingId);
+        assertEquals(0, registry.listAnnouncementsInSameCluster(localCluster).size());
+        assertEquals(0, registry.listLocalAnnouncements().size());
+        assertEquals(0, registry.listLocalIncomingAnnouncements().size());
+        assertFalse(registry.hasActiveAnnouncement(slingId));
+        assertFalse(registry.hasActiveAnnouncement(UUID.randomUUID().toString()));
+        
+        assertEquals(1, ann.listInstances().size());
+        registry.addAllExcept(ann, localCluster, new AnnouncementFilter() {
+            
+            public boolean accept(String receivingSlingId, Announcement announcement) {
+                assertNotNull(receivingSlingId);
+                assertNotNull(announcement);
+                return true;
+            }
+        });
+        assertEquals(1, ann.listInstances().size());
+        registry.registerAnnouncement(createAnnouncement(createCluster(3), 1, false));
+        assertEquals(1, registry.listAnnouncementsInSameCluster(localCluster).size());
+        assertEquals(3, registry.listInstances(localCluster).size());
+        registry.addAllExcept(ann, localCluster, new AnnouncementFilter() {
+            
+            public boolean accept(String receivingSlingId, Announcement announcement) {
+                assertNotNull(receivingSlingId);
+                assertNotNull(announcement);
+                return true;
+            }
+        });
+        assertEquals(4, ann.listInstances().size());
+        registry.registerAnnouncement(ann);
+        assertEquals(2, registry.listAnnouncementsInSameCluster(localCluster).size());
+    }
+    
+    private ClusterView createCluster(int numInstances) {
+        DefaultClusterView localCluster = new DefaultClusterView(UUID.randomUUID().toString());
+        for (int i = 0; i < numInstances; i++) {
+            DefaultInstanceDescription instance = TopologyHelper.createInstanceDescription(UUID.randomUUID().toString(), (i==0 ? true : false), localCluster);        
+        }
+        return localCluster;
+    }
+    
+    private ClusterView createCluster(String... instanceIds) {
+        DefaultClusterView localCluster = new DefaultClusterView(UUID.randomUUID().toString());
+        for (int i = 0; i < instanceIds.length; i++) {
+            DefaultInstanceDescription instance = TopologyHelper.createInstanceDescription(instanceIds[i], (i==0 ? true : false), localCluster);        
+        }
+        return localCluster;
+    }
+
+    private Announcement createAnnouncement(ClusterView remoteCluster, int ownerIndex, boolean inherited) {
+        List<InstanceDescription> instances = remoteCluster.getInstances();
+        Announcement ann = new Announcement(instances.get(ownerIndex).getSlingId());
+        ann.setInherited(inherited);
+        ann.setLocalCluster(remoteCluster);
+        return ann;
+    }
+    
+    @Test
+    public void testExpiry() throws InterruptedException, NoSuchFieldException {
+        ClusterView cluster1 = createCluster(4);
+        ClusterView cluster2 = createCluster(3);
+        ClusterView cluster3 = createCluster(5);
+        
+        ClusterView myCluster = createCluster(slingId);
+        
+        Announcement ann1 = createAnnouncement(cluster1, 0, true);
+        Announcement ann2 = createAnnouncement(cluster2, 1, true);
+        Announcement ann3 = createAnnouncement(cluster3, 1, false);
+        
+        assertTrue(registry.registerAnnouncement(ann1)!=-1);
+        assertTrue(registry.registerAnnouncement(ann2)!=-1);
+        assertTrue(registry.registerAnnouncement(ann3)!=-1);
+        assertTrue(registry.hasActiveAnnouncement(cluster1.getInstances().get(0).getSlingId()));
+        assertTrue(registry.hasActiveAnnouncement(cluster2.getInstances().get(1).getSlingId()));
+        assertTrue(registry.hasActiveAnnouncement(cluster3.getInstances().get(1).getSlingId()));
+        assertEquals(3, registry.listAnnouncementsInSameCluster(myCluster).size());
+        assertEquals(3, registry.listLocalAnnouncements().size());
+        assertEquals(1, registry.listLocalIncomingAnnouncements().size());
+
+        
+        {
+            Announcement testAnn = createAnnouncement(myCluster, 0, false);
+            assertEquals(1, testAnn.listInstances().size());
+            registry.addAllExcept(testAnn, myCluster, null);
+            assertEquals(13, testAnn.listInstances().size());
+        }
+
+        
+        Thread.sleep(10500);
+        {
+            Announcement testAnn = createAnnouncement(myCluster, 0, false);
+            assertEquals(1, testAnn.listInstances().size());
+            registry.addAllExcept(testAnn, myCluster, null);
+            assertEquals(13, testAnn.listInstances().size());
+        }
+        assertTrue(registry.registerAnnouncement(ann3)!=-1);
+        {
+            Announcement testAnn = createAnnouncement(myCluster, 0, false);
+            assertEquals(1, testAnn.listInstances().size());
+            registry.addAllExcept(testAnn, myCluster, null);
+            assertEquals(13, testAnn.listInstances().size());
+        }
+        
+        registry.checkExpiredAnnouncements();
+        
+        assertEquals(1, registry.listAnnouncementsInSameCluster(myCluster).size());
+        assertEquals(1, registry.listLocalAnnouncements().size());
+        assertEquals(1, registry.listLocalIncomingAnnouncements().size());
+        assertFalse(registry.hasActiveAnnouncement(cluster1.getInstances().get(0).getSlingId()));
+        assertFalse(registry.hasActiveAnnouncement(cluster2.getInstances().get(1).getSlingId()));
+        assertTrue(registry.hasActiveAnnouncement(cluster3.getInstances().get(1).getSlingId()));
+        {
+            Announcement testAnn = createAnnouncement(myCluster, 0, false);
+            assertEquals(1, testAnn.listInstances().size());
+            registry.addAllExcept(testAnn, myCluster, null);
+            assertEquals(6, testAnn.listInstances().size());
+        }
+        
+    }
+    
+    @Test
+    public void testCluster() throws Exception {
+        ClusterView cluster1 = createCluster(2);
+        ClusterView cluster2 = createCluster(4);
+        ClusterView cluster3 = createCluster(7);
+        
+        Announcement ann1 = createAnnouncement(cluster1, 1, true);
+        Announcement ann2 = createAnnouncement(cluster2, 2, true);
+        Announcement ann3 = createAnnouncement(cluster3, 3, false);
+        
+        final String instance1 = UUID.randomUUID().toString();
+        final String instance2 = UUID.randomUUID().toString();
+        final String instance3 = UUID.randomUUID().toString();
+        ClusterView myCluster = createCluster(instance1, instance2, instance3);
+
+        AnnouncementRegistryImpl registry1 = AnnouncementRegistryImpl.testConstructorAndActivate(
+                resourceResolverFactory, new DummySlingSettingsService(instance1), config);
+        AnnouncementRegistryImpl registry2 = AnnouncementRegistryImpl.testConstructorAndActivate(
+                resourceResolverFactory, new DummySlingSettingsService(instance2), config);
+        AnnouncementRegistryImpl registry3 = AnnouncementRegistryImpl.testConstructorAndActivate(
+                resourceResolverFactory, new DummySlingSettingsService(instance3), config);
+
+        assertTrue(registry1.registerAnnouncement(ann1)!=-1);
+        assertTrue(registry2.registerAnnouncement(ann2)!=-1);
+        assertTrue(registry3.registerAnnouncement(ann3)!=-1);
+        
+        assertTrue(registry1.hasActiveAnnouncement(cluster1.getInstances().get(1).getSlingId()));
+        assertTrue(registry2.hasActiveAnnouncement(cluster2.getInstances().get(2).getSlingId()));
+        assertTrue(registry3.hasActiveAnnouncement(cluster3.getInstances().get(3).getSlingId()));
+
+        assertEquals(3, registry1.listAnnouncementsInSameCluster(myCluster).size());
+        assertEquals(1, registry1.listLocalAnnouncements().size());
+        assertEquals(0, registry1.listLocalIncomingAnnouncements().size());
+        assertAnnouncements(registry1, myCluster, 4, 16);
+        
+        assertEquals(3, registry2.listAnnouncementsInSameCluster(myCluster).size());
+        assertEquals(1, registry2.listLocalAnnouncements().size());
+        assertEquals(0, registry2.listLocalIncomingAnnouncements().size());
+        assertAnnouncements(registry2, myCluster, 4, 16);
+
+        assertEquals(3, registry3.listAnnouncementsInSameCluster(myCluster).size());
+        assertEquals(1, registry3.listLocalAnnouncements().size());
+        assertEquals(1, registry3.listLocalIncomingAnnouncements().size());
+        assertAnnouncements(registry3, myCluster, 4, 16);
+        
+        myCluster = createCluster(instance1, instance2);
+        
+        VirtualInstanceHelper.dumpRepo(resourceResolverFactory);
+
+        assertEquals(2, registry1.listAnnouncementsInSameCluster(myCluster).size());
+        assertEquals(1, registry1.listLocalAnnouncements().size());
+        assertEquals(0, registry1.listLocalIncomingAnnouncements().size());
+        assertAnnouncements(registry1, myCluster, 3, 8);
+        
+        assertEquals(2, registry2.listAnnouncementsInSameCluster(myCluster).size());
+        assertEquals(1, registry2.listLocalAnnouncements().size());
+        assertEquals(0, registry2.listLocalIncomingAnnouncements().size());
+        assertAnnouncements(registry2, myCluster, 3, 8);
+        
+        Thread.sleep(10500);
+        assertAnnouncements(registry1, myCluster, 3, 8);
+        assertAnnouncements(registry2, myCluster, 3, 8);
+        registry1.checkExpiredAnnouncements();
+        registry2.checkExpiredAnnouncements();
+        assertAnnouncements(registry1, myCluster, 1, 2);
+        assertAnnouncements(registry2, myCluster, 1, 2);
+    }
+
+    private void assertAnnouncements(AnnouncementRegistryImpl registry,
+            ClusterView myCluster, int expectedNumAnnouncements, int expectedNumInstances) {
+        Announcement ann = createAnnouncement(myCluster, 0, false);
+        registry.addAllExcept(ann, myCluster, null);
+        assertEquals(expectedNumInstances, ann.listInstances().size());
+    }
+    
+}

Propchange: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/announcement/AnnouncementRegistryImplTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/ConnectorRegistryImplTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/ConnectorRegistryImplTest.java?rev=1709601&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/ConnectorRegistryImplTest.java (added)
+++ sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/ConnectorRegistryImplTest.java Tue Oct 20 14:12:31 2015
@@ -0,0 +1,118 @@
+/*
+ * 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.base.connectors.ping;
+
+import static org.junit.Assert.fail;
+
+import java.net.URL;
+import java.util.UUID;
+
+import org.apache.sling.discovery.base.commons.ClusterViewService;
+import org.apache.sling.discovery.base.connectors.BaseConfig;
+import org.apache.sling.discovery.base.connectors.DummyVirtualInstanceBuilder;
+import org.apache.sling.discovery.base.connectors.announcement.AnnouncementRegistryImpl;
+import org.apache.sling.discovery.base.its.setup.VirtualInstance;
+import org.apache.sling.discovery.base.its.setup.VirtualInstanceBuilder;
+import org.apache.sling.discovery.base.its.setup.mock.MockFactory;
+import org.apache.sling.discovery.base.its.setup.mock.SimpleConnectorConfig;
+import org.apache.sling.discovery.commons.providers.spi.impl.DummySlingSettingsService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ConnectorRegistryImplTest {
+
+    private VirtualInstance i;
+
+    public VirtualInstanceBuilder newBuilder() {
+        return new DummyVirtualInstanceBuilder();
+    }
+    
+    @Before
+    public void setup() throws Exception {
+        VirtualInstanceBuilder builder = newBuilder()
+                .newRepository("/var/discovery/impl/", true)
+                .setDebugName("i")
+                .setConnectorPingInterval(20)
+                .setConnectorPingTimeout(20);
+        i = builder.build();
+    }
+    
+    @After
+    public void teardown() throws Exception {
+        if (i!=null) {
+            try {
+                i.stopViewChecker();
+            } catch (Throwable e) {
+                e.printStackTrace();
+                i.stop();
+                throw new RuntimeException(e);
+            }
+            i.stop();
+        }
+    }
+    
+    @Test
+    public void testRegisterUnregister() throws Exception {
+        BaseConfig config = new SimpleConnectorConfig() {
+            @Override
+            public long getConnectorPingTimeout() {
+                return 20000;
+            }
+        };
+        AnnouncementRegistryImpl announcementRegistry = AnnouncementRegistryImpl.testConstructorAndActivate(
+                MockFactory.mockResourceResolverFactory(), new DummySlingSettingsService(UUID.randomUUID().toString()), config);
+
+        ConnectorRegistry c = ConnectorRegistryImpl.testConstructor(
+                announcementRegistry, config);
+
+        final URL url = new URL("http://localhost:1234/connector");
+        final ClusterViewService cvs = i.getClusterViewService();
+        try {
+            c.registerOutgoingConnector(null, url);
+            fail("should have complained");
+        } catch (IllegalArgumentException e) {
+            // ok
+        }
+        try {
+            c.registerOutgoingConnector(cvs, null);
+            fail("should have complained");
+        } catch (IllegalArgumentException e) {
+            // ok
+        }
+        TopologyConnectorClientInformation client = c
+                .registerOutgoingConnector(cvs, url);
+        try {
+            // should not be able to register same url twice
+            client = c.registerOutgoingConnector(cvs, url);
+            // ok - no longer complains - SLING-3446
+        } catch (IllegalStateException e) {
+            fail("should no longer be thrown"); // SLING-3446
+        }
+
+        try {
+            c.unregisterOutgoingConnector(null);
+            fail("should have complained");
+        } catch (IllegalArgumentException e) {
+            // ok
+        }
+
+        c.unregisterOutgoingConnector(client.getId());
+    }
+}

Propchange: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/ConnectorRegistryImplTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/TopologyConnectorServletTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/TopologyConnectorServletTest.java?rev=1709601&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/TopologyConnectorServletTest.java (added)
+++ sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/TopologyConnectorServletTest.java Tue Oct 20 14:12:31 2015
@@ -0,0 +1,115 @@
+/*
+ * 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.base.connectors.ping;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.sling.discovery.base.connectors.BaseConfig;
+import org.junit.Before;
+import org.junit.Test;
+
+import junitx.util.PrivateAccessor;
+
+public class TopologyConnectorServletTest {
+
+    private TopologyConnectorServlet servlet;
+    
+    private HttpServletRequest getRequest(String host, String addr) {
+        HttpServletRequest result = mock(HttpServletRequest.class);
+        when(result.getRemoteAddr()).thenReturn(addr);
+        when(result.getRemoteHost()).thenReturn(host);
+        return result;
+    }
+    
+    @Before
+    public void setUp() throws Exception {
+        servlet = new TopologyConnectorServlet();
+        BaseConfig config = mock(BaseConfig.class);
+        PrivateAccessor.setField(servlet, "config", config);
+    }
+    
+    @Test
+    public void testNull() throws Exception {
+        servlet.initWhitelist(null); // should work fine
+        servlet.initWhitelist(new String[0]); // should also work fine
+    }
+    
+    @Test
+    public void testPlaintextWhitelist_enabled() throws Exception {
+        servlet.initWhitelist(new String[] {"foo", "bar"});
+        assertTrue(servlet.isWhitelisted(getRequest("foo", "x")));
+        assertTrue(servlet.isWhitelisted(getRequest("bar", "x")));
+        assertTrue(servlet.isWhitelisted(getRequest("y", "foo")));
+        assertTrue(servlet.isWhitelisted(getRequest("y", "bar")));
+    }
+    
+    @Test
+    public void testPlaintextWhitelist_disabled() throws Exception {
+        servlet.initWhitelist(new String[] {});
+        assertFalse(servlet.isWhitelisted(getRequest("foo", "x")));
+        assertFalse(servlet.isWhitelisted(getRequest("bar", "x")));
+        assertFalse(servlet.isWhitelisted(getRequest("y", "foo")));
+        assertFalse(servlet.isWhitelisted(getRequest("y", "bar")));
+    }
+    
+    @Test
+    public void testWildcardWhitelist() throws Exception {
+        servlet.initWhitelist(new String[] {"foo*", "b?r", "test"});
+        assertTrue(servlet.isWhitelisted(getRequest("foo", "x")));
+        assertTrue(servlet.isWhitelisted(getRequest("fooo", "x")));
+        assertTrue(servlet.isWhitelisted(getRequest("foooo", "x")));
+        assertTrue(servlet.isWhitelisted(getRequest("x", "foo")));
+        assertTrue(servlet.isWhitelisted(getRequest("x", "fooo")));
+        assertTrue(servlet.isWhitelisted(getRequest("x", "foooo")));
+        assertTrue(servlet.isWhitelisted(getRequest("bur", "x")));
+        assertTrue(servlet.isWhitelisted(getRequest("x", "bur")));
+        assertTrue(servlet.isWhitelisted(getRequest("x", "test")));
+        assertFalse(servlet.isWhitelisted(getRequest("fo", "x")));
+        assertFalse(servlet.isWhitelisted(getRequest("x", "testy")));
+    }
+    
+    @Test
+    public void testSubnetMaskWhitelist() throws Exception {
+        servlet.initWhitelist(new String[] {"1.2.3.4/24", "2.3.4.1/30", "3.4.5.6/31"});
+        
+        assertTrue(servlet.isWhitelisted(getRequest("foo", "1.2.3.4")));
+        assertFalse(servlet.isWhitelisted(getRequest("1.2.3.4", "1.2.4.3")));
+        assertTrue(servlet.isWhitelisted(getRequest("foo", "1.2.3.1")));
+        assertTrue(servlet.isWhitelisted(getRequest("foo", "1.2.3.254")));
+        assertFalse(servlet.isWhitelisted(getRequest("foo", "1.2.4.5")));
+
+        assertTrue(servlet.isWhitelisted(getRequest("foo", "2.3.4.1")));
+        assertTrue(servlet.isWhitelisted(getRequest("foo", "2.3.4.2")));
+        assertFalse(servlet.isWhitelisted(getRequest("foo", "2.3.4.3")));
+        assertFalse(servlet.isWhitelisted(getRequest("foo", "2.3.4.4")));
+
+        assertFalse(servlet.isWhitelisted(getRequest("foo", "3.4.5.1")));
+        assertFalse(servlet.isWhitelisted(getRequest("foo", "3.4.5.2")));
+        assertFalse(servlet.isWhitelisted(getRequest("foo", "3.4.5.3")));
+        assertFalse(servlet.isWhitelisted(getRequest("foo", "3.4.5.4")));
+        assertFalse(servlet.isWhitelisted(getRequest("foo", "3.4.5.5")));
+        assertFalse(servlet.isWhitelisted(getRequest("foo", "3.4.5.6")));
+        assertFalse(servlet.isWhitelisted(getRequest("foo", "3.4.5.7")));
+    }
+}

Propchange: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/TopologyConnectorServletTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/TopologyRequestValidatorTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/TopologyRequestValidatorTest.java?rev=1709601&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/TopologyRequestValidatorTest.java (added)
+++ sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/TopologyRequestValidatorTest.java Tue Oct 20 14:12:31 2015
@@ -0,0 +1,180 @@
+/*
+ * 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 SF 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.base.connectors.ping;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.StringReader;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.message.BasicHeader;
+import org.apache.sling.discovery.base.connectors.BaseConfig;
+import org.apache.sling.discovery.base.its.setup.mock.SimpleConnectorConfig;
+import org.hamcrest.Description;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.jmock.api.Action;
+import org.jmock.api.Invocation;
+import org.jmock.integration.junit4.JUnit4Mockery;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TopologyRequestValidatorTest {
+    
+    private TopologyRequestValidator topologyRequestValidator;
+    private Mockery context = new JUnit4Mockery();
+
+
+    @Before
+    public void before() throws SecurityException, IllegalArgumentException, NoSuchFieldException, IllegalAccessException {
+        BaseConfig config= new SimpleConnectorConfig();
+        setPrivate(config, "sharedKey", "testKey");
+        setPrivate(config, "hmacEnabled", true);
+        setPrivate(config, "encryptionEnabled", true);
+        setPrivate(config, "keyInterval", 3600*100*4);
+        topologyRequestValidator = new TopologyRequestValidator(config);
+    }
+    
+    private void setPrivate(Object o, String field, Object value) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
+        Field f = o.getClass().getDeclaredField(field);
+        if ( !f.isAccessible()) {
+            f.setAccessible(true);
+        }
+        f.set(o, value);
+    }
+
+    @Test
+    public void testTrustRequest() throws IOException {
+        final HttpPut method = new HttpPut("/TestUri");
+        String clearMessage = "TestMessage";
+        final String message = topologyRequestValidator.encodeMessage(clearMessage);
+        Assert.assertNotNull(message);
+        Assert.assertNotEquals(message, clearMessage);
+        topologyRequestValidator.trustMessage(method, message);
+        
+        Assert.assertNotNull(method.getFirstHeader(TopologyRequestValidator.HASH_HEADER));
+        Assert.assertNotNull(method.getFirstHeader(TopologyRequestValidator.HASH_HEADER).getValue());
+        Assert.assertTrue(method.getFirstHeader(TopologyRequestValidator.HASH_HEADER).getValue().length() > 0);
+        Assert.assertNotNull(method.getFirstHeader(TopologyRequestValidator.SIG_HEADER));
+        Assert.assertNotNull(method.getFirstHeader(TopologyRequestValidator.SIG_HEADER).getValue());
+        Assert.assertTrue(method.getFirstHeader(TopologyRequestValidator.SIG_HEADER).getValue().length() > 0);
+        final HttpServletRequest request = context.mock(HttpServletRequest.class);
+        context.checking(new Expectations() {
+            {
+                allowing(request).getHeader(with(TopologyRequestValidator.HASH_HEADER));
+                will(returnValue(method.getFirstHeader(TopologyRequestValidator.HASH_HEADER).getValue()));
+                
+                allowing(request).getHeader(with(TopologyRequestValidator.SIG_HEADER));
+                will(returnValue(method.getFirstHeader(TopologyRequestValidator.SIG_HEADER).getValue()));
+                
+                allowing(request).getHeader(with("Content-Encoding"));
+                will(returnValue(""));
+
+                allowing(request).getRequestURI();
+                will(returnValue(method.getURI().getPath()));
+                
+                allowing(request).getReader();
+                will(returnValue(new BufferedReader(new StringReader(message))));
+            }
+        });
+        
+        Assert.assertTrue(topologyRequestValidator.isTrusted(request));
+        Assert.assertEquals(clearMessage, topologyRequestValidator.decodeMessage(request));
+    }
+    
+    
+    
+    @Test
+    public void testTrustResponse() throws IOException {
+        final HttpServletRequest request = context.mock(HttpServletRequest.class);
+        context.checking(new Expectations() {
+            {
+                allowing(request).getRequestURI();
+                will(returnValue("/Test/Uri2"));
+            }
+        });
+
+        final HttpServletResponse response = context.mock(HttpServletResponse.class);
+        final Map<Object, Object> headers = new HashMap<Object, Object>();
+        context.checking(new Expectations() {
+            {
+                allowing(response).setHeader(with(any(String.class)), with(any(String.class)));
+                will(new Action(){
+
+                    public void describeTo(Description desc) {
+                        desc.appendText("Setting header ");
+                    }
+
+                    public Object invoke(Invocation invocation) throws Throwable {
+                        headers.put(invocation.getParameter(0), invocation.getParameter(1));
+                        return null;
+                    }
+                    
+                });
+            }
+        });
+
+        String clearMessage =  "TestMessage2";
+        final String message = topologyRequestValidator.encodeMessage(clearMessage);
+        topologyRequestValidator.trustMessage(response, request, message);
+        
+        final HttpEntity responseEntity = context.mock(HttpEntity.class);
+        context.checking(new Expectations() {
+        	{
+        		allowing(responseEntity).getContent();
+        		will(returnValue(new ByteArrayInputStream(message.getBytes())));
+        	}
+        });
+        
+        final HttpResponse resp = context.mock(HttpResponse.class);
+        context.checking(new Expectations(){
+            {
+                allowing(resp).getFirstHeader(with(any(String.class)));
+                will(new Action() {
+                    public void describeTo(Description desc) {
+                        desc.appendText("Getting (first) header ");
+                    }
+
+                    public Object invoke(Invocation invocation) throws Throwable {
+                        return new BasicHeader((String)invocation.getParameter(0), (String)headers.get(invocation.getParameter(0)));
+                    }
+                    
+                });
+                
+                allowing(resp).getEntity();
+                will(returnValue(responseEntity));
+            } 
+        });
+        topologyRequestValidator.isTrusted(resp);
+        topologyRequestValidator.decodeMessage("/Test/Uri2", resp);
+        
+    }
+    
+    
+
+}

Propchange: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/TopologyRequestValidatorTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/wl/WildcardHelperTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/wl/WildcardHelperTest.java?rev=1709601&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/wl/WildcardHelperTest.java (added)
+++ sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/wl/WildcardHelperTest.java Tue Oct 20 14:12:31 2015
@@ -0,0 +1,117 @@
+/*
+ * 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.base.connectors.ping.wl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.UUID;
+
+import org.apache.commons.net.util.SubnetUtils;
+import org.junit.Test;
+
+public class WildcardHelperTest {
+
+    @Test
+    public void testNullValues() {
+        
+        SubnetUtils s = new SubnetUtils("1.2.3.4/10");
+        s = new SubnetUtils("1.2.3.4", "255.255.0.0");
+        
+        try{
+            WildcardHelper.wildcardAsRegex(null);
+            fail("should complain");
+        } catch(IllegalArgumentException iae) {
+            // ok
+        }
+        try{
+            WildcardHelper.matchesWildcard(null, "foo");
+            fail("should complain");
+        } catch(IllegalArgumentException iae) {
+            // ok
+        }
+        try{
+            WildcardHelper.matchesWildcard("foo", null);
+            fail("should complain");
+        } catch(IllegalArgumentException iae) {
+            // ok
+        }
+    }
+    
+    @Test
+    public void testEmptyValue() {
+        final String expected = "\\Q\\E";
+        assertEquals(expected, WildcardHelper.wildcardAsRegex(""));
+    }
+    
+    @Test
+    public void testWithoutWildcards() {
+        for(int i=0; i<1000; i++) {
+            String randomString = UUID.randomUUID().toString();
+            assertTrue(WildcardHelper.matchesWildcard(randomString, randomString));
+        }
+    }
+    
+    @Test
+    public void testWildcards() {
+        assertTrue(WildcardHelper.matchesWildcard("", "*"));
+        assertTrue(WildcardHelper.matchesWildcard("fooo", "*"));
+        assertTrue(WildcardHelper.matchesWildcard("fooo", "**"));
+        assertTrue(WildcardHelper.matchesWildcard("fooo", "**?"));
+        assertTrue(WildcardHelper.matchesWildcard("fooo", "????"));
+        assertFalse(WildcardHelper.matchesWildcard("fooo", "???"));
+        assertFalse(WildcardHelper.matchesWildcard("fooo", "?????"));
+
+        for(int i=0; i<100; i++) {
+            String randomString = UUID.randomUUID().toString();
+            assertTrue(WildcardHelper.matchesWildcard(randomString, "*"));
+            assertTrue(WildcardHelper.matchesWildcard(randomString, randomString.substring(0, randomString.length()-1)+"?"));
+            assertTrue(WildcardHelper.matchesWildcard(randomString, randomString.substring(0, randomString.length()-1)+"*"));
+            assertTrue(WildcardHelper.matchesWildcard(randomString, randomString.substring(0, randomString.length()-2)+"??"));
+            assertTrue(WildcardHelper.matchesWildcard(randomString, randomString.substring(0, randomString.length()-2)+"*"));
+            assertTrue(WildcardHelper.matchesWildcard(randomString, "?" + randomString.substring(1, randomString.length())));
+            assertTrue(WildcardHelper.matchesWildcard(randomString, "*" + randomString.substring(1, randomString.length())));
+            assertTrue(WildcardHelper.matchesWildcard(randomString, "??" + randomString.substring(2, randomString.length())));
+            assertTrue(WildcardHelper.matchesWildcard(randomString, "*" + randomString.substring(2, randomString.length())));
+        }
+        
+        assertTrue(WildcardHelper.matchesWildcard("fooo", "f*"));
+        assertTrue(WildcardHelper.matchesWildcard("fooo", "fo*"));
+        assertTrue(WildcardHelper.matchesWildcard("fooo", "foo*"));
+        assertTrue(WildcardHelper.matchesWildcard("fooo", "fooo*"));
+        assertFalse(WildcardHelper.matchesWildcard("fooo", "fooo?"));
+        assertFalse(WildcardHelper.matchesWildcard("fooo", "foooo*"));
+        
+        assertTrue(WildcardHelper.matchesWildcard("fooo", "*"));
+        assertFalse(WildcardHelper.matchesWildcard("fooo", "?"));
+        assertFalse(WildcardHelper.matchesWildcard("fooo", "f?"));
+
+        assertTrue(WildcardHelper.matchesWildcard("fo", "f?"));
+
+        assertTrue(WildcardHelper.matchesWildcard("foooba", "f*b?"));
+        assertFalse(WildcardHelper.matchesWildcard("fooobar", "f*b?"));
+        assertFalse(WildcardHelper.matchesWildcard("foooba", "f*b?r"));
+        assertTrue(WildcardHelper.matchesWildcard("fooobar", "f*b?r"));
+        assertTrue(WildcardHelper.matchesWildcard("foooba", "f???b?"));
+        assertFalse(WildcardHelper.matchesWildcard("foooba", "f??b?"));
+        assertFalse(WildcardHelper.matchesWildcard("foooba", "f??b?"));
+    }
+}

Propchange: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/connectors/ping/wl/WildcardHelperTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/its/AbstractClusterLoadTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/its/AbstractClusterLoadTest.java?rev=1709601&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/its/AbstractClusterLoadTest.java (added)
+++ sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/its/AbstractClusterLoadTest.java Tue Oct 20 14:12:31 2015
@@ -0,0 +1,287 @@
+/*
+ * 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 SF 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.base.its;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+
+import org.apache.sling.discovery.base.commons.UndefinedClusterViewException;
+import org.apache.sling.discovery.base.its.setup.VirtualInstance;
+import org.apache.sling.discovery.base.its.setup.VirtualInstanceBuilder;
+import org.apache.sling.discovery.base.its.setup.WithholdingAppender;
+import org.apache.sling.testing.tools.retry.RetryLoop;
+import org.junit.After;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Migrated from org.apache.sling.discovery.impl.cluster.ClusterLoadTest
+ */
+public abstract class AbstractClusterLoadTest {
+
+    // wait up to 120 sec - in 1sec wait-intervals
+    private static final int INSTANCE_VIEW_TIMEOUT_SECONDS = 120;
+    private static final int INSTANCE_VIEW_POLL_INTERVAL_MILLIS = 500;
+
+    private final Random random = new Random();
+
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    List<VirtualInstance> instances = new LinkedList<VirtualInstance>();
+
+    @After
+    public void tearDown() throws Exception {
+    	if (instances==null || instances.size()==0) {
+    		return;
+    	}
+    	for (Iterator<VirtualInstance> it = instances.iterator(); it.hasNext();) {
+    	    VirtualInstance i = it.next();
+			i.stop();
+			it.remove();
+		}
+    }
+    
+    public abstract VirtualInstanceBuilder newBuilder();
+    
+
+    @Test
+    public void testFramework() throws Exception {
+        logger.info("testFramework: building 1st instance..");
+        VirtualInstanceBuilder builder = newBuilder()
+                .newRepository("/var/discovery/impl/ClusterLoadTest/testFramework/", true)
+                .setDebugName("firstInstance")
+                .setConnectorPingTimeout(3)
+                .setConnectorPingInterval(20)
+                .setMinEventDelay(0);
+        VirtualInstance firstInstance = builder.build();
+		instances.add(firstInstance);
+    	Thread.sleep(2000);
+    	// without any heartbeat action, the discovery service reports its local instance
+    	// in so called 'isolated' mode - lets test for that
+    	try{
+    	    firstInstance.getClusterViewService().getLocalClusterView();
+    	    fail("should complain");
+    	} catch(UndefinedClusterViewException e) {
+    	    // SLING-5030:
+    	}
+        firstInstance.startViewChecker(1);
+        Thread.sleep(4000);
+        // after a heartbeat and letting it settle, the discovery service must have
+        // established a view - test for that
+        firstInstance.dumpRepo();
+        firstInstance.assertEstablishedView();
+
+        VirtualInstanceBuilder builder2 = newBuilder()
+                .useRepositoryOf(builder)
+                .setDebugName("secondInstance")
+                .setConnectorPingTimeout(3)
+                .setConnectorPingInterval(20)
+                .setMinEventDelay(0);
+        firstInstance.dumpRepo();
+        logger.info("testFramework: building 2nd instance..");
+        VirtualInstance secondInstance = builder2.build();
+        instances.add(secondInstance);
+        secondInstance.startViewChecker(1);
+        Thread.sleep(4000);
+        firstInstance.dumpRepo();
+        assertEquals(firstInstance.getClusterViewService().getLocalClusterView().getInstances().size(), 2);
+        assertEquals(secondInstance.getClusterViewService().getLocalClusterView().getInstances().size(), 2);
+    }
+
+    @Test
+    public void testTwoInstances() throws Throwable {
+    	doTest(2, 5);
+    }
+
+    @Test
+    public void testThreeInstances() throws Throwable {
+    	doTest(3, 6);
+    }
+
+    @Test
+    public void testFourInstances() throws Throwable {
+    	doTest(4, 7);
+    }
+
+    @Test
+    public void testFiveInstances() throws Throwable {
+    	doTest(5, 8);
+    }
+
+    @Test
+    public void testSixInstances() throws Throwable {
+    	doTest(6, 9);
+    }
+
+    @Test
+    public void testSevenInstances() throws Throwable {
+    	doTest(7, 10);
+    }
+
+    private void doTest(final int size, final int loopCnt) throws Throwable {
+        WithholdingAppender withholdingAppender = null;
+        boolean failure = true;
+        try{
+            logger.info("doTest("+size+","+loopCnt+"): muting log output...");
+            withholdingAppender = WithholdingAppender.install();
+            doDoTest(size, loopCnt);
+            failure = false;
+        } finally {
+            if (withholdingAppender!=null) {
+                if (failure) {
+                    logger.info("doTest("+size+","+loopCnt+"): writing muted log output due to failure...");
+                }
+                withholdingAppender.release(failure);
+                if (!failure) {
+                    logger.info("doTest("+size+","+loopCnt+"): not writing muted log output due to success...");
+                }
+            }
+            logger.info("doTest("+size+","+loopCnt+"): unmuted log output.");
+        }
+    }
+    
+	private void doDoTest(final int size, final int loopCnt) throws Throwable {
+		if (size<2) {
+			fail("can only test 2 or more instances");
+		}
+        VirtualInstanceBuilder builder = newBuilder()
+                .newRepository("/var/discovery/impl/ClusterLoadTest/doTest-"+size+"-"+loopCnt+"/", true)
+                .setDebugName("firstInstance")
+                .setConnectorPingTimeout(3)
+                .setConnectorPingInterval(20)
+                .setMinEventDelay(0);
+		VirtualInstance firstInstance = builder.build();
+		firstInstance.startViewChecker(1);
+		instances.add(firstInstance);
+		for(int i=1; i<size; i++) {
+		    VirtualInstanceBuilder builder2 = newBuilder()
+		            .useRepositoryOf(builder)
+		            .setDebugName("subsequentInstance-"+i)
+	                .setConnectorPingTimeout(3)
+	                .setMinEventDelay(0)
+	                .setConnectorPingInterval(20);
+			VirtualInstance subsequentInstance = builder2.build();
+			instances.add(subsequentInstance);
+			subsequentInstance.startViewChecker(1);
+		}
+
+		for(int i=0; i<loopCnt; i++) {
+			logger.info("=====================");
+			logger.info(" START of LOOP "+i);
+			logger.info("=====================");
+
+			// count how many instances had heartbeats running in the first place
+			int aliveCnt = 0;
+			for (Iterator<VirtualInstance> it = instances.iterator(); it.hasNext();) {
+			    VirtualInstance instance = it.next();
+				if (instance.isViewCheckerRunning()) {
+					aliveCnt++;
+				}
+			}
+			logger.info("=====================");
+			logger.info(" original aliveCnt "+aliveCnt);
+			logger.info("=====================");
+			if (aliveCnt==0) {
+				// if no one is sending heartbeats, all instances go back to isolated mode
+				aliveCnt=1;
+			}
+
+            final int aliveCntFinal = aliveCnt;
+
+			for (Iterator<VirtualInstance> it = instances.iterator(); it.hasNext();) {
+			    VirtualInstance instance = it.next();
+				try {
+                    instance.dumpRepo();
+                } catch (Exception e) {
+                    logger.error("Failed dumping repo for instance " + instance.getSlingId(), e);
+                }
+			}
+
+			// then verify that each instance sees that many instances
+			for (Iterator<VirtualInstance> it = instances.iterator(); it.hasNext();) {
+                final VirtualInstance instance = it.next();
+				if (!instance.isViewCheckerRunning()) {
+					// if the heartbeat is not running, this instance is considered dead
+					// hence we're not doing any assert here (as the count is only
+					// valid if heartbeat/checkView is running and that would void the test)
+				} else {
+                    new RetryLoop(new ConditionImplementation(instance, aliveCntFinal), INSTANCE_VIEW_TIMEOUT_SECONDS,
+                            INSTANCE_VIEW_POLL_INTERVAL_MILLIS);
+				}
+			}
+
+			// start/stop heartbeats accordingly
+			logger.info("Starting/Stopping heartbeats with count="+instances.size());
+			for (Iterator<VirtualInstance> it = instances.iterator(); it.hasNext();) {
+			    VirtualInstance instance = it.next();
+				if (random.nextBoolean()) {
+					logger.info("Starting heartbeats with "+instance.slingId);
+					instance.startViewChecker(1);
+					logger.info("Started heartbeats with "+instance.slingId);
+				} else {
+					logger.info("Stopping heartbeats with "+instance.slingId);
+					instance.stopViewChecker();
+					logger.info("Stopped heartbeats with "+instance.slingId);
+				}
+			}
+
+		}
+	}
+
+    class ConditionImplementation implements RetryLoop.Condition {
+
+        private final int expectedAliveCount;
+        private final VirtualInstance instance;
+
+        private ConditionImplementation(VirtualInstance instance, int expectedAliveCount) {
+            this.expectedAliveCount = expectedAliveCount;
+            this.instance = instance;
+        }
+
+        public boolean isTrue() throws Exception {
+            boolean result = false;
+            int actualAliveCount = -1;
+            try{
+                actualAliveCount = instance.getClusterViewService().getLocalClusterView().getInstances().size();
+                result = expectedAliveCount == actualAliveCount;
+            } catch(UndefinedClusterViewException e) {
+                logger.info("no view at the moment: "+e);
+                return false;
+            } catch(Exception e) {
+                logger.error("isTrue: got exception: "+e, e);
+                throw e;
+            }
+            if (!result) {
+                logger.info("isTrue: expected="+expectedAliveCount+", actual="+actualAliveCount+", result="+result);
+            }
+            return result;
+        }
+
+        public String getDescription() {
+            return "Waiting for instance with " + instance.getSlingId() + " to see " + expectedAliveCount
+                    + " instances";
+        }
+    }
+
+}

Propchange: sling/trunk/bundles/extensions/discovery/base/src/test/java/org/apache/sling/discovery/base/its/AbstractClusterLoadTest.java
------------------------------------------------------------------------------
    svn:eol-style = native