# HG changeset patch # User Roman Kennke # Date 1358530992 -3600 # Node ID ce04776b8b818fbfdf8e91174cfea056d7acbce8 # Parent 31c6026714f59ca3397a09f8d648868344222912# Parent 4a2301e50857e2c16bda637fa45b077ad9b2ae00 Merge diff -r 31c6026714f5 -r ce04776b8b81 client/living-vm-filter/core/src/test/java/com/redhat/thermostat/client/filter/vm/core/VMFilterActivatorTest.java --- a/client/living-vm-filter/core/src/test/java/com/redhat/thermostat/client/filter/vm/core/VMFilterActivatorTest.java Fri Jan 18 18:42:04 2013 +0100 +++ b/client/living-vm-filter/core/src/test/java/com/redhat/thermostat/client/filter/vm/core/VMFilterActivatorTest.java Fri Jan 18 18:43:12 2013 +0100 @@ -40,13 +40,13 @@ import static org.mockito.Mockito.mock; import org.junit.Test; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; import com.redhat.thermostat.client.core.Filter; import com.redhat.thermostat.client.osgi.service.MenuAction; import com.redhat.thermostat.common.dao.VmInfoDAO; import com.redhat.thermostat.test.StubBundleContext; -import com.redhat.thermostat.test.StubServiceReference; -import com.redhat.thermostat.test.StubServiceRegistration; public class VMFilterActivatorTest { @@ -57,8 +57,8 @@ activator.start(ctx); VmInfoDAO dao = mock(VmInfoDAO.class); - StubServiceRegistration reg = (StubServiceRegistration) ctx.registerService(VmInfoDAO.class, dao, null); - StubServiceReference ref = new StubServiceReference(reg.getInfo()); + ServiceRegistration reg = ctx.registerService(VmInfoDAO.class, dao, null); + ServiceReference ref = reg.getReference(); activator.vmInfoDaoTracker.addingService(ref); assertTrue(ctx.isServiceRegistered(MenuAction.class.getName(), LivingVMFilterMenuAction.class)); diff -r 31c6026714f5 -r ce04776b8b81 client/living-vm-filter/swing/src/test/java/com/redhat/thermostat/client/filter/vm/swing/VMFilterActivatorTest.java --- a/client/living-vm-filter/swing/src/test/java/com/redhat/thermostat/client/filter/vm/swing/VMFilterActivatorTest.java Fri Jan 18 18:42:04 2013 +0100 +++ b/client/living-vm-filter/swing/src/test/java/com/redhat/thermostat/client/filter/vm/swing/VMFilterActivatorTest.java Fri Jan 18 18:43:12 2013 +0100 @@ -40,12 +40,12 @@ import static org.mockito.Mockito.mock; import org.junit.Test; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; import com.redhat.thermostat.client.osgi.service.DecoratorProvider; import com.redhat.thermostat.common.dao.VmInfoDAO; import com.redhat.thermostat.test.StubBundleContext; -import com.redhat.thermostat.test.StubServiceReference; -import com.redhat.thermostat.test.StubServiceRegistration; public class VMFilterActivatorTest { @@ -56,8 +56,8 @@ activator.start(ctx); VmInfoDAO dao = mock(VmInfoDAO.class); - StubServiceRegistration reg = (StubServiceRegistration) ctx.registerService(VmInfoDAO.class, dao, null); - StubServiceReference ref = new StubServiceReference(reg.getInfo()); + ServiceRegistration reg = ctx.registerService(VmInfoDAO.class, dao, null); + ServiceReference ref = reg.getReference(); activator.vmInfoDaoTracker.addingService(ref); assertTrue(ctx.isServiceRegistered(DecoratorProvider.class.getName(), LivingVMDecoratorProvider.class)); diff -r 31c6026714f5 -r ce04776b8b81 common/core/src/main/java/com/redhat/thermostat/test/StubBundleContext.java --- a/common/core/src/main/java/com/redhat/thermostat/test/StubBundleContext.java Fri Jan 18 18:42:04 2013 +0100 +++ b/common/core/src/main/java/com/redhat/thermostat/test/StubBundleContext.java Fri Jan 18 18:43:12 2013 +0100 @@ -39,20 +39,27 @@ import java.io.File; import java.io.InputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Dictionary; -import java.util.Iterator; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.osgi.framework.BundleListener; +import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkListener; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceEvent; +import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; @@ -68,31 +75,23 @@ public class StubBundleContext implements BundleContext { static class ServiceInformation { - public String serviceInterface; public Object implementation; public Dictionary properties; public int exportedReferences; - public ServiceInformation(String className, Object impl, Dictionary props) { - this.serviceInterface = className; + public ServiceInformation(Object impl, Dictionary props) { this.implementation = impl; this.properties = props; } } - static class ListenerSpec { - public ServiceListener listener; - public Filter filter; + private int nextServiceId = 0; - public ListenerSpec(ServiceListener listener, Filter filter) { - this.listener = listener; - this.filter = filter; - } - } - + private Map frameworkProperties = new HashMap<>(); private List bundles = new ArrayList<>(); private List registeredServices = new ArrayList<>(); - private List registeredListeners = new ArrayList<>(); + private Map registeredListeners = new HashMap<>(); + private Bundle contextBundle = null; /* * Interface methods @@ -100,12 +99,17 @@ @Override public String getProperty(String key) { - throw new NotImplementedException(); + String result = null; + result = frameworkProperties.get(key); + if (result == null) { + result = System.getProperty(key); + } + return result; } @Override public Bundle getBundle() { - throw new NotImplementedException(); + return contextBundle; } @Override @@ -123,34 +127,40 @@ if (id > Integer.MAX_VALUE) { throw new NotImplementedException(); } + if (id >= bundles.size()) { + return null; + } + return bundles.get((int) id); } @Override + public Bundle getBundle(String location) { + throw new NotImplementedException(); + } + + @Override public Bundle[] getBundles() { - throw new NotImplementedException(); + return bundles.toArray(new Bundle[bundles.size()]); } @Override public void addServiceListener(ServiceListener listener, String filter) throws InvalidSyntaxException { - ListenerSpec spec = new ListenerSpec(listener, createFilter(filter)); - registeredListeners.add(spec); + registeredListeners.put(listener, filter == null ? null : createFilter(filter)); } @Override public void addServiceListener(ServiceListener listener) { - throw new NotImplementedException(); + try { + addServiceListener(listener, null); + } catch (InvalidSyntaxException e) { + throw new AssertionError("a null filter can not have invalid systax"); + } } @Override public void removeServiceListener(ServiceListener listener) { - Iterator iter = registeredListeners.iterator(); - while (iter.hasNext()) { - ListenerSpec item = iter.next(); - if (item.listener == listener) { - iter.remove(); - } - } + registeredListeners.remove(listener); } @Override @@ -179,70 +189,125 @@ } @Override - public ServiceRegistration registerService(String[] clazzes, Object service, Dictionary properties) { - throw new NotImplementedException(); + public ServiceRegistration registerService(String className, Object service, Dictionary properties) { + return registerService(new String[] { className }, service, properties); } @Override - public ServiceRegistration registerService(String className, Object service, Dictionary properties) { - ServiceInformation info = new ServiceInformation(className, service, properties); + public ServiceRegistration registerService(String[] clazzes, Object service, Dictionary properties) { + if (service instanceof ServiceFactory) { + throw new NotImplementedException("support for service factories is not implemented"); + } + + for (String className : clazzes) { + try { + Class clazz = Class.forName(className); + if (!clazz.isAssignableFrom(service.getClass())) { + throw new IllegalArgumentException("service is not a subclass of " + className); + } + } catch (ClassNotFoundException classNotFound) { + throw new IllegalArgumentException("not a valid class: " + className); + } + } + + Object specifiedRanking = null; + Hashtable newProperties = new Hashtable<>(); + if (properties != null) { + Enumeration enumeration = properties.keys(); + while (enumeration.hasMoreElements()) { + Object key = enumeration.nextElement(); + newProperties.put((String)key, properties.get(key)); + } + specifiedRanking = properties.get(Constants.SERVICE_RANKING); + } + + newProperties.put(Constants.OBJECTCLASS, clazzes); + newProperties.put(Constants.SERVICE_ID, nextServiceId); + nextServiceId++; + if (specifiedRanking == null || !(specifiedRanking instanceof Integer)) { + specifiedRanking = 0; + } + newProperties.put(Constants.SERVICE_RANKING, (Integer) specifiedRanking); + + ServiceInformation info = new ServiceInformation(service, newProperties); registeredServices.add(info); - notifyServiceChange(new StubServiceReference(info), true); + notifyServiceChange(new StubServiceReference(info, contextBundle), true); return new StubServiceRegistration(this, info); } @Override - public ServiceReference[] getServiceReferences(String clazz, String filter) throws InvalidSyntaxException { - List toReturn = new ArrayList<>(); + public ServiceReference getServiceReference(Class clazz) { + return getServiceReference(clazz.getName()); + } + + @Override + public ServiceReference getServiceReference(String clazz) { + try { + ServiceReference[] initial = getServiceReferences(clazz, null); + if (initial == null) { + return null; + } - if (filter == null) { - for (ServiceInformation info : registeredServices) { - if (info.serviceInterface.equals(clazz)) { - toReturn.add(new StubServiceReference(info)); - } - } - } else { - Filter toMatch = createFilter(filter); - for (ServiceInformation info : registeredServices) { - if (info.serviceInterface.equals(clazz) && toMatch.match(info.properties)) { - toReturn.add(new StubServiceReference(info)); - } + Arrays.sort(initial); + return initial[initial.length-1]; + } catch (InvalidSyntaxException invalidFilterSyntax) { + throw new AssertionError("a null filter can not have an invalid syntax"); + } + } + + @Override + public Collection getServiceReferences(Class clazz, String filter) throws InvalidSyntaxException { + return Arrays.asList(getServiceReferences(clazz.getName(), filter)); + } + + @Override + public ServiceReference[] getServiceReferences(String clazz, String filter) throws InvalidSyntaxException { + ServiceReference[] allRefs = getAllServiceReferences(clazz, filter); + if (allRefs == null) { + return null; + } + + List result = new ArrayList<>(); + for (ServiceReference ref : allRefs) { + if (ref.isAssignableTo(contextBundle, clazz)) { + result.add(ref); } } - return toReturn.toArray(new ServiceReference[0]); + return result.toArray(new ServiceReference[0]); } @Override public ServiceReference[] getAllServiceReferences(String clazz, String filter) throws InvalidSyntaxException { - throw new NotImplementedException(); - } + List toReturn = new ArrayList<>(); + + Filter toMatch = (filter == null) ? null : createFilter(filter); - @Override - public ServiceReference getServiceReference(String clazz) { - ServiceReference result = null; for (ServiceInformation info : registeredServices) { - if (info.serviceInterface.equals(clazz)) { - result = new StubServiceReference(info); + for (String serviceInterface : (String[]) info.properties.get(Constants.OBJECTCLASS)) { + if (clazz == null || serviceInterface.equals(clazz)) { + if (toMatch == null || toMatch.match(info.properties)) { + toReturn.add(new StubServiceReference(info, contextBundle)); + } + } } } - return result; + + if (toReturn.size() == 0) { + return null; + } + return toReturn.toArray(new ServiceReference[0]); } - @Override - public ServiceReference getServiceReference(Class clazz) { - for (ServiceInformation info : registeredServices) { - if (info.serviceInterface.equals(clazz.getName())) { - return new StubServiceReference(info); - } - } - return null; - } @Override - public Collection getServiceReferences(Class clazz, String filter) throws InvalidSyntaxException { - throw new NotImplementedException(); + public Filter createFilter(String filter) throws InvalidSyntaxException { + // FIXME this will break service trackers if FrameworkUtil is mocked. + // The following call will return null if FrameworkUtil is mocked. + // that's a problem because this is meant to be used (mostly) in test + // environments and that's where FrameworkUtil is likely to be mocked. + return FrameworkUtil.createFilter(filter); } @Override @@ -260,6 +325,9 @@ if (info.exportedReferences == 0) { return false; } + if (!registeredServices.contains(info)) { + return false; + } info.exportedReferences--; return true; } @@ -269,32 +337,30 @@ throw new NotImplementedException(); } - @Override - public Filter createFilter(String filter) throws InvalidSyntaxException { - // FIXME this will break service trackers if FrameworkUtil is mocked - // the following call will return null if FrameworkUtil is mocked. - // that's a problem because this is meant to be used (mostly) in test - // environments and that's where FrameworkUtil is likely to be mocked. - return FrameworkUtil.createFilter(filter); - } - - @Override - public Bundle getBundle(String location) { - throw new NotImplementedException(); - } - /* * Our custom methods */ + public void setProperty(String key, String value) { + frameworkProperties.put(key, value); + } + /** Set the context bundle */ + public void setBundle(Bundle bundle) { + this.contextBundle = bundle; + } + + /** Set the bundle associated with an id */ public void setBundle(int i, Bundle bundle) { bundles.add(i, bundle); } public boolean isServiceRegistered(String serviceName, Class implementationClass) { for (ServiceInformation info : registeredServices) { - if (info.serviceInterface.equals(serviceName) && info.implementation.getClass().equals(implementationClass)) { - return true; + for (String serviceInterface : (String[]) info.properties.get(Constants.OBJECTCLASS)) { + if (serviceInterface.equals(serviceName) + && info.implementation.getClass().equals(implementationClass)) { + return true; + } } } return false; @@ -304,24 +370,26 @@ return registeredServices; } - public Collection getServiceListeners() { - return registeredListeners; + public Collection getServiceListeners() { + return registeredListeners.keySet(); } public void removeService(ServiceInformation info) { if (!registeredServices.contains(info)) { - throw new IllegalStateException("service not registered"); + throw new IllegalArgumentException("service not registered"); } registeredServices.remove(info); - notifyServiceChange(new StubServiceReference(info), false); + notifyServiceChange(new StubServiceReference(info, contextBundle), false); } private void notifyServiceChange(ServiceReference serviceReference, boolean registered) { int eventType = registered ? ServiceEvent.REGISTERED : ServiceEvent.UNREGISTERING; ServiceEvent event = new ServiceEvent(eventType, serviceReference); - for (ListenerSpec l : registeredListeners) { - if (l.filter.match(serviceReference)) { - l.listener.serviceChanged(event); + for (Entry entry : registeredListeners.entrySet()) { + ServiceListener listener = entry.getKey(); + Filter filter = entry.getValue(); + if (filter == null || filter.match(serviceReference)) { + listener.serviceChanged(event); } } } diff -r 31c6026714f5 -r ce04776b8b81 common/core/src/main/java/com/redhat/thermostat/test/StubServiceReference.java --- a/common/core/src/main/java/com/redhat/thermostat/test/StubServiceReference.java Fri Jan 18 18:42:04 2013 +0100 +++ b/common/core/src/main/java/com/redhat/thermostat/test/StubServiceReference.java Fri Jan 18 18:43:12 2013 +0100 @@ -50,39 +50,33 @@ public class StubServiceReference implements ServiceReference { - private ServiceInformation information; + private final Bundle sourceBundle; + private final ServiceInformation information; - public StubServiceReference(ServiceInformation info) { + public StubServiceReference(ServiceInformation info, Bundle sourceBundle) { this.information = info; + this.sourceBundle = sourceBundle; } @Override public Object getProperty(String key) { - if (Constants.OBJECTCLASS.equals(key)) { - return new String[] { information.serviceInterface }; - } - return information.properties.get(key); } @Override public String[] getPropertyKeys() { - if (information.properties == null) { - return new String[] { Constants.OBJECTCLASS }; - } else { - Dictionary props = information.properties; - List toReturn = new ArrayList<>(props.size()); - Enumeration keyEnumeration = props.keys(); - while (keyEnumeration.hasMoreElements()) { - toReturn.add((String) keyEnumeration.nextElement()); - } - return toReturn.toArray(new String[0]); + Dictionary props = information.properties; + List toReturn = new ArrayList<>(props.size()); + Enumeration keyEnumeration = props.keys(); + while (keyEnumeration.hasMoreElements()) { + toReturn.add((String) keyEnumeration.nextElement()); } + return toReturn.toArray(new String[0]); } @Override public Bundle getBundle() { - throw new NotImplementedException(); + return sourceBundle; } @Override @@ -92,12 +86,39 @@ @Override public boolean isAssignableTo(Bundle bundle, String className) { + if (sourceBundle == bundle) { + return true; + } throw new NotImplementedException(); } @Override public int compareTo(Object reference) { - throw new NotImplementedException(); + if (!(reference instanceof ServiceReference)) { + throw new NotImplementedException(); + } + + ServiceReference ref = (ServiceReference) reference; + + Integer myRanking = (Integer) getProperty(Constants.SERVICE_RANKING); + Integer otherRanking = (Integer) ref.getProperty(Constants.SERVICE_RANKING); + + if (myRanking > otherRanking) { + return 1; + } else if (myRanking < otherRanking) { + return -1; + } else { + Integer myServiceId = (Integer) getProperty(Constants.SERVICE_ID); + Integer otherServiceId = (Integer) ref.getProperty(Constants.SERVICE_ID); + + if (myServiceId < otherServiceId) { + return 1; + } else if (myServiceId > otherServiceId) { + return -1; + } else { + return 0; + } + } } public ServiceInformation getInformation() { diff -r 31c6026714f5 -r ce04776b8b81 common/core/src/main/java/com/redhat/thermostat/test/StubServiceRegistration.java --- a/common/core/src/main/java/com/redhat/thermostat/test/StubServiceRegistration.java Fri Jan 18 18:42:04 2013 +0100 +++ b/common/core/src/main/java/com/redhat/thermostat/test/StubServiceRegistration.java Fri Jan 18 18:43:12 2013 +0100 @@ -56,7 +56,7 @@ @Override public ServiceReference getReference() { - throw new NotImplementedException(); + return new StubServiceReference(info, bundleContext.getBundle()); } @Override diff -r 31c6026714f5 -r ce04776b8b81 common/core/src/test/java/com/redhat/thermostat/test/StubBundleContextTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/core/src/test/java/com/redhat/thermostat/test/StubBundleContextTest.java Fri Jan 18 18:43:12 2013 +0100 @@ -0,0 +1,573 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.test; + +import static org.junit.Assert.assertArrayEquals; +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.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import java.io.ByteArrayInputStream; +import java.util.Collection; +import java.util.Hashtable; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleException; +import org.osgi.framework.BundleListener; +import org.osgi.framework.Constants; +import org.osgi.framework.Filter; +import org.osgi.framework.FrameworkListener; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceEvent; +import org.osgi.framework.ServiceListener; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; + +import com.redhat.thermostat.common.NotImplementedException; +import com.redhat.thermostat.test.StubBundleContext.ServiceInformation; + +/** + * Test that StubBundleContext behaves like a BundleContext, based on what is + * specified in the OSGi spec. Other optional methods to help in testing are + * great, but adherence to spec is most important. + */ +public class StubBundleContextTest { + + private StubBundleContext bundleContext; + + @Before + public void setUp() { + bundleContext = new StubBundleContext(); + assertNotNull(bundleContext); + } + + @Test + public void testSetAndGetContextBundle() { + assertEquals(null, bundleContext.getBundle()); + + Bundle bundle = mock(Bundle.class); + bundleContext.setBundle(bundle); + assertSame(bundle, bundleContext.getBundle()); + } + + @Test(expected = NotImplementedException.class) + public void testInstallBundleFromLocation() throws BundleException { + bundleContext.installBundle(""); + } + + @Test(expected = NotImplementedException.class) + public void testInstallBundleFromInputStream() throws BundleException { + bundleContext.installBundle("", new ByteArrayInputStream(new byte[0])); + } + + @Test + public void testSetAndGetBundles() { + assertEquals(null, bundleContext.getBundle(0)); + + Bundle systemBundle = mock(Bundle.class); + bundleContext.setBundle(0, systemBundle); + + assertEquals(systemBundle, bundleContext.getBundle(0)); + + assertArrayEquals(new Bundle[] { systemBundle }, bundleContext.getBundles()); + } + + @Test(expected = NotImplementedException.class) + public void testGetBundleByLargeId() { + bundleContext.getBundle(Long.MAX_VALUE); + } + + @Test(expected = NotImplementedException.class) + public void testGetBundleByLocation() { + bundleContext.getBundle(""); + } + + @Test + public void testAddRemoveFrameworkListener() { + try { + bundleContext.addFrameworkListener(mock(FrameworkListener.class)); + fail("not expected"); + } catch (NotImplementedException notImplemented) { + /* okay: expected */ + } + + try { + bundleContext.removeFrameworkListener(mock(FrameworkListener.class)); + fail("not expected"); + } catch (NotImplementedException notImplemented) { + /* okay: expected */ + } + } + + @Test + public void testAddRemoveBundleListener() { + try { + bundleContext.addBundleListener(mock(BundleListener.class)); + fail("not expected"); + } catch (NotImplementedException notImplemented) { + /* okay: expected */ + } + + try { + bundleContext.removeBundleListener(mock(BundleListener.class)); + fail("not expected"); + } catch (NotImplementedException notImplemented) { + /* okay: expected */ + } + } + + @Test + public void testGetPropertyDelegatesToSystemProperties() { + assertEquals(System.getProperty("user.name"), bundleContext.getProperty("user.name")); + } + + @Test + public void testGetAndSetProperty() { + final String PROPERTY_NAME = "foo.bar.baz"; + final String PROPERTY_NEW_VALUE = "spam.eggs"; + + assertEquals(null, bundleContext.getProperty(PROPERTY_NAME)); + + bundleContext.setProperty(PROPERTY_NAME, PROPERTY_NEW_VALUE); + + assertEquals(PROPERTY_NEW_VALUE, bundleContext.getProperty(PROPERTY_NAME)); + } + + @Test + public void testFilterCreationReturnsASaneFilter() throws InvalidSyntaxException { + Filter filter = bundleContext.createFilter("(foo=bar)"); + assertNotNull(filter); + + Hashtable dict = new Hashtable<>(); + dict.put("foo", "bar"); + + assertTrue(filter.match(dict)); + } + + @Test + public void testAddRemoveService() { + TestService service = mock(TestService.class); + + assertEquals(0, bundleContext.getAllServices().size()); + assertFalse(bundleContext.isServiceRegistered(TestService.class.getName(), service.getClass())); + + ServiceRegistration registration = bundleContext.registerService(TestService.class, service, null); + + assertEquals(1, bundleContext.getAllServices().size()); + assertTrue(bundleContext.isServiceRegistered(TestService.class.getName(), service.getClass())); + + registration.unregister(); + + assertEquals(0, bundleContext.getAllServices().size()); + assertFalse(bundleContext.isServiceRegistered(TestService.class.getName(), service.getClass())); + } + + @Test(expected = IllegalArgumentException.class) + public void testAddServiceThatDoesNotImplementInterfaceClass() { + AnotherTestService service = mock(AnotherTestService.class); + + bundleContext.registerService(TestService.class.getName(), service, null); + } + + @Test(expected = IllegalArgumentException.class) + public void testAddServiceThatDoesNotImplementInterfaceClass2() { + AnotherTestService service = mock(AnotherTestService.class); + + bundleContext.registerService("foo.bar.Baz", service, null); + } + + @Test + public void testAddServiceWithProperties() { + TestService service = mock(TestService.class); + + Hashtable props = new Hashtable(); + props.put(Constants.SERVICE_ID, -10); + props.put(Constants.SERVICE_RANKING, 10); + props.put(Constants.OBJECTCLASS, AnotherTestService.class.getName()); + + ServiceRegistration reg = bundleContext.registerService(TestService.class, service, props); + + ServiceReference serviceRef = reg.getReference(); + + assertArrayEquals(new String[] { TestService.class.getName() }, + (String[]) serviceRef.getProperty(Constants.OBJECTCLASS)); + + assertEquals(10, serviceRef.getProperty(Constants.SERVICE_RANKING)); + assertEquals(0, serviceRef.getProperty(Constants.SERVICE_ID)); + } + + @Test + public void testAddServiceWithNonIntegerRanking() { + TestService service = mock(TestService.class); + + Hashtable props = new Hashtable(); + props.put(Constants.SERVICE_RANKING, new Object()); + + ServiceRegistration reg = bundleContext.registerService(TestService.class, service, props); + + ServiceReference serviceRef = reg.getReference(); + + assertEquals(0, serviceRef.getProperty(Constants.SERVICE_RANKING)); + } + + @Test(expected = IllegalArgumentException.class) + public void testRemoveUnknownService() { + bundleContext.removeService(new ServiceInformation(mock(TestService.class), new Hashtable())); + } + + @Test + public void testAddingAndRemovingListenerWorks() { + assertEquals(0, bundleContext.getServiceListeners().size()); + + ServiceListener listener = mock(ServiceListener.class); + + bundleContext.addServiceListener(listener); + + assertEquals(1, bundleContext.getServiceListeners().size()); + assertEquals(listener, bundleContext.getServiceListeners().toArray()[0]); + + bundleContext.removeServiceListener(listener); + + assertEquals(0, bundleContext.getServiceListeners().size()); + } + + @Test + public void testAddingSameListenerReplacedTheOldOne() { + assertEquals(0, bundleContext.getServiceListeners().size()); + + ServiceListener listener = mock(ServiceListener.class); + + bundleContext.addServiceListener(listener); + + assertEquals(1, bundleContext.getServiceListeners().size()); + + bundleContext.addServiceListener(listener); + + assertEquals(1, bundleContext.getServiceListeners().size()); + } + + @Test + public void testRemovingAnUnknownListenerIsANoOp() { + ServiceListener listener = mock(ServiceListener.class); + bundleContext.addServiceListener(listener); + assertEquals(1, bundleContext.getServiceListeners().size()); + + ServiceListener unknownListener = mock(ServiceListener.class); + bundleContext.removeServiceListener(unknownListener); + + assertEquals(1, bundleContext.getServiceListeners().size()); + } + + @Test + public void testServiceListenersWithoutFiltersWork() { + ServiceListener listener = mock(ServiceListener.class); + bundleContext.addServiceListener(listener); + + bundleContext.registerService(TestService.class, mock(TestService.class), null); + + assertListenerRecievedRegisteredEvent(listener); + } + + @Test + public void testServiceListenersWithFiltersWork() throws InvalidSyntaxException { + ServiceListener specificListener = mock(ServiceListener.class); + String specificFilter = "(" + Constants.OBJECTCLASS + "=" + TestService.class.getName() + ")"; + bundleContext.addServiceListener(specificListener, specificFilter); + + ServiceListener allListener = mock(ServiceListener.class); + String allListenerFilter = "(" + Constants.OBJECTCLASS + "=*)"; + bundleContext.addServiceListener(allListener, allListenerFilter); + + ServiceListener otherListener = mock(ServiceListener.class); + String otherListenerFilter = "(" + Constants.OBJECTCLASS + "=foo.bar.Baz)"; + bundleContext.addServiceListener(otherListener, otherListenerFilter); + + ServiceRegistration registration = bundleContext.registerService(TestService.class, mock(TestService.class), null); + + assertListenerRecievedRegisteredEvent(specificListener); + assertListenerRecievedRegisteredEvent(allListener); + + registration.unregister(); + + assertListenerRecievedUnregisteringEvent(specificListener); + assertListenerRecievedUnregisteringEvent(allListener); + + verify(otherListener, never()).serviceChanged(isA(ServiceEvent.class)); + + } + + private void assertListenerRecievedRegisteredEvent(ServiceListener listener) { + ArgumentCaptor eventCaptor = ArgumentCaptor.forClass(ServiceEvent.class); + verify(listener).serviceChanged(eventCaptor.capture()); + assertEquals(1, eventCaptor.getAllValues().size()); + ServiceEvent event = eventCaptor.getValue(); + assertEquals(ServiceEvent.REGISTERED, event.getType()); + ServiceReference ref = event.getServiceReference(); + assertTrue(ref instanceof StubServiceReference); + } + + private void assertListenerRecievedUnregisteringEvent(ServiceListener listener) { + ArgumentCaptor eventCaptor = ArgumentCaptor.forClass(ServiceEvent.class); + verify(listener, atLeast(1)).serviceChanged(eventCaptor.capture()); + + ServiceEvent event = eventCaptor.getValue(); + assertEquals(ServiceEvent.UNREGISTERING, event.getType()); + ServiceReference ref = event.getServiceReference(); + assertTrue(ref instanceof StubServiceReference); + } + + @Test + public void testGetServiceReferenceReturnsNullForNoMatch() { + assertNull(bundleContext.getServiceReference(TestService.class)); + } + + @Test + public void testGetServiceReferenceReturnsServiceWithHighestServiceRanking() { + TestService service1 = mock(TestService.class); + TestService service2 = mock(TestService.class); + + Hashtable service2Props = new Hashtable(); + service2Props.put(Constants.SERVICE_RANKING, 1000); + + bundleContext.registerService(TestService.class, service1, null); + bundleContext.registerService(TestService.class, service2, service2Props); + + ServiceReference ref = bundleContext.getServiceReference(TestService.class); + + assertSame(service2, bundleContext.getService(ref)); + } + + @Test + public void testGetServiceReferenceReturnsServiceWithLowerServiceId() { + TestService service1 = mock(TestService.class); + TestService service2 = mock(TestService.class); + + bundleContext.registerService(TestService.class, service1, null); + bundleContext.registerService(TestService.class, service2, null); + + ServiceReference ref = bundleContext.getServiceReference(TestService.class); + + assertSame(service1, bundleContext.getService(ref)); + } + + @Test + public void testGetServiceReferences() throws InvalidSyntaxException { + TestService service = mock(TestService.class); + + bundleContext.registerService(TestService.class, service, null); + bundleContext.registerService(AnotherTestService.class, mock(AnotherTestService.class), null); + + Collection refs = bundleContext.getServiceReferences(TestService.class, null); + + assertEquals(1, refs.size()); + assertEquals(service, ((StubServiceReference) refs.toArray()[0]).getInformation().implementation); + } + + @Test + public void testGetAllServiceReferencesNoMatch() throws InvalidSyntaxException { + TestService service = mock(TestService.class); + + bundleContext.registerService(TestService.class, service, null); + bundleContext.registerService(TestService.class, mock(TestService.class), null); + + ServiceReference[] refs = bundleContext.getAllServiceReferences(AnotherTestService.class.getName(), null); + + assertEquals(null, (Object) refs); + } + + @Test + public void testGetAllServiceReferencesWithoutFilter() throws InvalidSyntaxException { + TestService service = mock(TestService.class); + + bundleContext.registerService(TestService.class, service, null); + bundleContext.registerService(AnotherTestService.class, mock(AnotherTestService.class), null); + + ServiceReference[] refs = bundleContext.getAllServiceReferences(TestService.class.getName(), null); + + assertEquals(1, refs.length); + assertEquals(service, ((StubServiceReference) refs[0]).getInformation().implementation); + } + + @Test + public void testGetAllServiceReferencesWithFilter() throws InvalidSyntaxException { + TestService service = mock(TestService.class); + + bundleContext.registerService(TestService.class, service, null); + bundleContext.registerService(AnotherTestService.class, mock(AnotherTestService.class), null); + + String filter = "(" + Constants.OBJECTCLASS + "=" + TestService.class.getName() + ")"; + ServiceReference[] refs = bundleContext.getAllServiceReferences(TestService.class.getName(), filter); + + assertEquals(1, refs.length); + assertEquals(service, ((StubServiceReference) refs[0]).getInformation().implementation); + } + + @Test + public void testGetAllServiceReferencesWithNoClassNameJustFilter() throws InvalidSyntaxException { + TestService service = mock(TestService.class); + + bundleContext.registerService(TestService.class, service, null); + bundleContext.registerService(AnotherTestService.class, mock(AnotherTestService.class), null); + + String filter = "(" + Constants.OBJECTCLASS + "=" + TestService.class.getName() + ")"; + ServiceReference[] refs = bundleContext.getAllServiceReferences(null, filter); + + assertEquals(1, refs.length); + assertEquals(service, ((StubServiceReference) refs[0]).getInformation().implementation); + } + + @Test + public void testGetServiceUsingClassObject() { + TestService service = mock(TestService.class); + + bundleContext.registerService(TestService.class, service, null); + + ServiceReference ref = bundleContext.getServiceReference(TestService.class); + assertNotNull(ref); + + Object returnedService = bundleContext.getService(ref); + + assertSame(service, returnedService); + } + + @Test + public void testGetServiceUsingClassName() { + TestService service = mock(TestService.class); + + bundleContext.registerService(TestService.class, service, null); + + ServiceReference ref = bundleContext.getServiceReference(TestService.class.getName()); + assertNotNull(ref); + + Object returnedService = bundleContext.getService(ref); + + assertSame(service, returnedService); + } + + @Test + public void testUngetService() { + bundleContext.registerService(TestService.class, mock(TestService.class), null); + + ServiceReference ref = bundleContext.getServiceReference(TestService.class.getName()); + Object returnedService = bundleContext.getService(ref); + + assertTrue(bundleContext.ungetService(ref)); + + assertFalse(bundleContext.ungetService(ref)); + } + + @Test + public void testUngetServiceOnUnregisteredService() { + ServiceRegistration registration = bundleContext.registerService(TestService.class, mock(TestService.class), null); + + ServiceReference ref = bundleContext.getServiceReference(TestService.class.getName()); + Object returnedService = bundleContext.getService(ref); + + registration.unregister(); + + assertFalse(bundleContext.ungetService(ref)); + } + + @Test + public void testReferenceExportCountIsCorrect() { + TestService service = mock(TestService.class); + + ServiceRegistration reg = bundleContext.registerService(TestService.class, service, null); + + ServiceReference ref = bundleContext.getServiceReference(TestService.class); + assertNotNull(ref); + + assertEquals(0, bundleContext.getExportedServiceCount(reg)); + + Object returnedService = bundleContext.getService(ref); + + assertEquals(1, bundleContext.getExportedServiceCount(reg)); + + bundleContext.ungetService(ref); + + assertEquals(0, bundleContext.getExportedServiceCount(reg)); + } + + @Test(expected = NotImplementedException.class) + public void testGetDataFile() { + bundleContext.getDataFile(""); + } + + @Test + public void testIsServiceRegisteredForRegisteredService() { + ComplexService service = mock(ComplexService.class); + + String[] ifaces = new String[] { TestService.class.getName(), AnotherTestService.class.getName() }; + ServiceRegistration reg = bundleContext.registerService(ifaces, service, null); + + assertTrue(bundleContext.isServiceRegistered(AnotherTestService.class.getName(), service.getClass())); + + } + + @Test + public void testIsServiceRegisteredForUnregisteredService() { + ComplexService service = mock(ComplexService.class); + TestService someOtherService = mock(TestService.class); + + String[] ifaces = new String[] { TestService.class.getName(), AnotherTestService.class.getName() }; + ServiceRegistration reg = bundleContext.registerService(ifaces, service, null); + + assertFalse(bundleContext.isServiceRegistered(AnotherTestService.class.getName(), someOtherService.getClass())); + } + + /* + * Dummy service interfaces + */ + + static interface TestService { /* just a marker */} + + static interface AnotherTestService { /* just a marker */} + + static interface ComplexService extends TestService, AnotherTestService { /* ditto */} +}