/*
* 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.impl.standalone;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.sling.discovery.DiscoveryService;
import org.apache.sling.discovery.PropertyProvider;
import org.apache.sling.discovery.TopologyEvent;
import org.apache.sling.discovery.TopologyEventListener;
import org.apache.sling.settings.SlingSettingsService;
import org.junit.Test;
import org.osgi.framework.Constants;
public class NoClusterDiscoveryServiceTest {
private void invoke(final Object obj, final String methodName) {
invoke(obj, methodName, null, null);
}
private void invoke(final Object obj, final String methodName, final Class[] params, final Object[] args) {
try {
final Method activate = obj.getClass().getDeclaredMethod(methodName, params);
activate.setAccessible(true);
activate.invoke(obj, args);
} catch (final Exception e) {
throw new RuntimeException("Unable to invoke method " + methodName + " on " + obj, e);
}
}
private Object setField(final Object obj, final String fieldName, final Object value) {
Class<?> clazz = obj.getClass();
while ( clazz != null ) {
try {
final Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
return null;
} catch ( final Exception ignore ) {
// ignore
}
clazz = clazz.getSuperclass();
}
throw new RuntimeException("Field " + fieldName + " not found on object " + obj);
}
private DiscoveryService createService(final boolean activate) {
final DiscoveryService service = new NoClusterDiscoveryService();
setField(service, "settingsService", new SlingSettingsService() {
@Override
public String getSlingId() {
return "my-sling-id";
}
@Override
public String getSlingHomePath() {
return null;
}
@Override
public URL getSlingHome() {
return null;
}
@Override
public Set<String> getRunModes() {
return null;
}
@Override
public String getAbsolutePathWithinSlingHome(String relativePath) {
return null;
}
});
if ( activate ) {
invoke(service, "activate");
}
return service;
}
@Test public void testBasics() throws Exception {
final DiscoveryService service = this.createService(true);
assertNotNull(service.getTopology());
assertTrue(service.getTopology().isCurrent());
invoke(service, "deactivate");
assertNull(service.getTopology());
}
@Test public void testListenerAfter() throws Exception {
final DiscoveryService service = this.createService(true);
final List<TopologyEvent> events = new ArrayList<TopologyEvent>();
final TopologyEventListener listener = new TopologyEventListener() {
@Override
public void handleTopologyEvent(final TopologyEvent event) {
events.add(event);
}
};
invoke(service, "bindTopologyEventListener", new Class[] {TopologyEventListener.class}, new Object[] {listener});
assertEquals(1, events.size());
assertEquals(TopologyEvent.Type.TOPOLOGY_INIT, events.get(0).getType());
assertNotNull(events.get(0).getNewView());
assertNull(events.get(0).getOldView());
}
@Test public void testListenerBefore() throws Exception {
final DiscoveryService service = this.createService(false);
final List<TopologyEvent> events = new ArrayList<TopologyEvent>();
final TopologyEventListener listener = new TopologyEventListener() {
@Override
public void handleTopologyEvent(final TopologyEvent event) {
events.add(event);
}
};
invoke(service, "bindTopologyEventListener", new Class[] {TopologyEventListener.class}, new Object[] {listener});
assertEquals(0, events.size());
invoke(service, "activate");
assertEquals(1, events.size());
assertEquals(TopologyEvent.Type.TOPOLOGY_INIT, events.get(0).getType());
assertNotNull(events.get(0).getNewView());
assertNull(events.get(0).getOldView());
}
@Test public void testPropertyChanges() throws Exception {
final DiscoveryService service = this.createService(true);
final List<TopologyEvent> events = new ArrayList<TopologyEvent>();
final TopologyEventListener listener = new TopologyEventListener() {
@Override
public void handleTopologyEvent(final TopologyEvent event) {
events.add(event);
}
};
invoke(service, "bindTopologyEventListener", new Class[] {TopologyEventListener.class}, new Object[] {listener});
events.clear();
final PropertyProvider provider = new PropertyProvider() {
@Override
public String getProperty(final String name) {
if ( "a".equals(name) ) {
return "1";
}
if ( "b".equals(name) ) {
return "2";
}
if ( "c".equals(name) ) {
return "3";
}
return null;
}
};
final Map<String, Object> properties = new HashMap<String, Object>();
properties.put(PropertyProvider.PROPERTY_PROPERTIES, new String[] {"a", "b", "c"});
properties.put(Constants.SERVICE_ID, 1L);
invoke(service, "bindPropertyProvider", new Class[] {PropertyProvider.class, Map.class}, new Object[] {provider, properties});
assertEquals(1, events.size());
assertEquals(TopologyEvent.Type.PROPERTIES_CHANGED, events.get(0).getType());
assertNotNull(events.get(0).getNewView());
assertTrue(events.get(0).getNewView().isCurrent());
assertNotNull(events.get(0).getOldView());
assertFalse(events.get(0).getOldView().isCurrent());
// test properties
assertEquals("1", events.get(0).getNewView().getLocalInstance().getProperty("a"));
assertEquals("2", events.get(0).getNewView().getLocalInstance().getProperty("b"));
assertEquals("3", events.get(0).getNewView().getLocalInstance().getProperty("c"));
assertNull(events.get(0).getOldView().getLocalInstance().getProperty("a"));
assertNull(events.get(0).getOldView().getLocalInstance().getProperty("b"));
assertNull(events.get(0).getOldView().getLocalInstance().getProperty("c"));
events.clear();
invoke(service, "unbindPropertyProvider", new Class[] {PropertyProvider.class, Map.class}, new Object[] {provider, properties});
assertEquals(1, events.size());
assertEquals(TopologyEvent.Type.PROPERTIES_CHANGED, events.get(0).getType());
assertNotNull(events.get(0).getNewView());
assertTrue(events.get(0).getNewView().isCurrent());
assertNotNull(events.get(0).getOldView());
assertFalse(events.get(0).getOldView().isCurrent());
assertEquals("1", events.get(0).getOldView().getLocalInstance().getProperty("a"));
assertEquals("2", events.get(0).getOldView().getLocalInstance().getProperty("b"));
assertEquals("3", events.get(0).getOldView().getLocalInstance().getProperty("c"));
assertNull(events.get(0).getNewView().getLocalInstance().getProperty("a"));
assertNull(events.get(0).getNewView().getLocalInstance().getProperty("b"));
assertNull(events.get(0).getNewView().getLocalInstance().getProperty("c"));
}
}