SLING-5090 osgi-mock: Support ServiceFactory

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1706494 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java b/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java
index 1c05f05..488cfa7 100644
--- a/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java
+++ b/src/main/java/org/apache/sling/testing/mock/osgi/MockServiceRegistration.java
@@ -24,11 +24,13 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.felix.framework.FilterImpl;
 import org.apache.sling.testing.mock.osgi.OsgiMetadataUtil.OsgiMetadata;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.Constants;
 import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceFactory;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 
@@ -52,12 +54,20 @@
             final Dictionary<String, Object> properties, MockBundleContext bundleContext) {
         this.serviceId = ++serviceCounter;
         this.clazzes = new HashSet<String>(ImmutableList.copyOf(clazzes));
-        this.service = service;
+        
+        if (service instanceof ServiceFactory) {
+            this.service = ((ServiceFactory)service).getService(bundleContext.getBundle(), this);
+        }
+        else {
+            this.service = service;
+        }
+        
         this.properties = properties != null ? properties : new Hashtable<String,Object>();
         this.properties.put(Constants.SERVICE_ID, this.serviceId);
         this.properties.put(Constants.OBJECTCLASS, clazzes);
         this.serviceReference = new MockServiceReference(bundle, this);
         this.bundleContext = bundleContext;
+        
         readOsgiMetadata();
     }
 
@@ -134,4 +144,9 @@
         }
     }
 
+    @Override
+    public String toString() {
+        return "#" + serviceId + " [" + StringUtils.join(clazzes, ",") + "]: " + service.toString();
+    }
+
 }
diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilTest.java
index 53cdd0d..521ca6f 100644
--- a/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilTest.java
+++ b/src/test/java/org/apache/sling/testing/mock/osgi/OsgiServiceUtilTest.java
@@ -39,12 +39,16 @@
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.References;
 import org.apache.felix.scr.annotations.Service;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceFactory;
 import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.component.ComponentContext;
 import org.osgi.service.component.annotations.Modified;
 
@@ -63,6 +67,11 @@
         bundleContext.registerService(ServiceInterface1.class.getName(), service1, null);
         bundleContext.registerService(ServiceInterface2.class.getName(), service2, null);
     }
+    
+    @After
+    public void tearDown() {
+        MockOsgi.shutdown(bundleContext);
+    }
 
     @Test
     public void testService3() {
@@ -144,6 +153,52 @@
         MockOsgi.modified(new Object(), MockOsgi.newBundleContext(), ImmutableMap.<String,Object>of());
     }
 
+    @Test
+    public void testMockedService() {
+        Service5 service5 = Mockito.spy(new Service5());
+        Mockito.doReturn(true).when(service5).doRemoteThing();
+
+        MockOsgi.injectServices(service5, bundleContext);
+        MockOsgi.activate(service5, bundleContext, (Dictionary<String, Object>) null);
+        bundleContext.registerService(ServiceInterface5.class.getName(), service5, null);
+
+        assertSame(service5, bundleContext.getService(
+                bundleContext.getServiceReference(ServiceInterface5.class.getName())));
+        assertEquals(true, service5.doRemoteThing());
+    }
+
+    @Test
+    public void testServiceFactoryViaScr() {
+        ServiceFactory1 serviceFactory1 = new ServiceFactory1();
+        
+        MockOsgi.injectServices(serviceFactory1, bundleContext);
+        MockOsgi.activate(serviceFactory1, bundleContext, (Dictionary<String, Object>) null);
+        bundleContext.registerService(ServiceFactory1.class.getName(), serviceFactory1, null);
+
+        assertSame(serviceFactory1, bundleContext.getService(
+                bundleContext.getServiceReference(ServiceFactory1.class.getName())));
+    }
+
+    @Test
+    public void testServiceFactoryViaManualRegistration() {
+        final ServiceFactory1 serviceFactory1 = new ServiceFactory1();
+        
+        bundleContext.registerService(ServiceFactory1.class.getName(), new ServiceFactory() {
+            @Override
+            public Object getService(Bundle bundle, ServiceRegistration registration) {
+                return serviceFactory1;
+            }
+            @Override
+            public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
+                // nothing to do
+            }
+        }, null);
+
+        assertSame(serviceFactory1, bundleContext.getService(
+                bundleContext.getServiceReference(ServiceFactory1.class.getName())));
+    }
+
+    
     public interface ServiceInterface1 {
         // no methods
     }
@@ -317,18 +372,10 @@
 
     }
 
-    @Test
-    public void testMockedService() {
-        Service5 service5 = Mockito.spy(new Service5());
-        Mockito.doReturn(true).when(service5).doRemoteThing();
-
-        MockOsgi.injectServices(service5, bundleContext);
-        MockOsgi.activate(service5, bundleContext, (Dictionary<String, Object>) null);
-        bundleContext.registerService(ServiceInterface5.class.getName(), service5, null);
-
-        assertSame(service5, bundleContext.getService(
-                bundleContext.getServiceReference(ServiceInterface5.class.getName())));
-        assertEquals(true, service5.doRemoteThing());
+    @Component
+    @Service(value=ServiceFactory1.class, serviceFactory=true)
+    public static class ServiceFactory1 {
+        
     }
-
+        
 }
diff --git a/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest.xml b/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest.xml
index d822d05..a9d3623 100644
--- a/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest.xml
+++ b/src/test/resources/OSGI-INF/org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest.xml
@@ -55,4 +55,11 @@
     </service>
     <property name="service.pid" value="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$Service5"/>
   </scr:component>
+  <scr:component name="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$ServiceFactory1">
+    <implementation class="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$ServiceFactory1"/>
+    <service servicefactory="true">
+      <provide interface="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$ServiceFactory1"/>
+    </service>
+    <property name="service.pid" value="org.apache.sling.testing.mock.osgi.OsgiServiceUtilTest$ServiceFactory1"/>
+  </scr:component>
 </components>