This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to annotated tag org.apache.sling.testing.osgi-mock-1.1.0 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-osgi-mock.git
commit a822c765b58d380fe9fc07a62ae574cc4c0a4ff1 Author: Stefan Seifert <[email protected]> AuthorDate: Fri Nov 14 09:55:05 2014 +0000 SLING-4162 Introduce "OsgiContext" junit rule for OSGi and OsgiContextImpl git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/mocks/osgi-mock@1639589 13f79535-47bb-0310-9956-ffa450edef68 --- pom.xml | 2 +- .../testing/mock/osgi/context/OsgiContextImpl.java | 185 +++++++++++++++++++++ .../testing/mock/osgi/context/package-info.java | 23 +++ .../sling/testing/mock/osgi/junit/OsgiContext.java | 111 +++++++++++++ .../mock/osgi/junit/OsgiContextCallback.java | 37 +++++ .../testing/mock/osgi/junit/package-info.java | 23 +++ .../mock/osgi/context/OsgiContextImplTest.java | 96 +++++++++++ .../testing/mock/osgi/junit/OsgiContextTest.java | 53 ++++++ 8 files changed, 529 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 83f3930..97b4b77 100644 --- a/pom.xml +++ b/pom.xml @@ -92,7 +92,7 @@ <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> - <scope>test</scope> + <scope>compile</scope> </dependency> </dependencies> diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java b/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java new file mode 100644 index 0000000..d4cb74b --- /dev/null +++ b/src/main/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImpl.java @@ -0,0 +1,185 @@ +/* + * 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.testing.mock.osgi.context; + +import java.lang.reflect.Array; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.Map; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.sling.testing.mock.osgi.MockOsgi; +import org.osgi.framework.BundleContext; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; +import org.osgi.service.component.ComponentContext; + +import aQute.bnd.annotation.ConsumerType; + +import com.google.common.collect.ImmutableMap; + +/** + * Defines OSGi context objects and helper methods. Should not be used directly + * but via the {@link org.apache.sling.testing.mock.osgi.junit.OsgiContext} JUnit rule. + */ +@ConsumerType +public class OsgiContextImpl { + + protected ComponentContext componentContext; + + /** + * Setup actions before test method execution + */ + protected void setUp() { + // can be overridden by subclasses + } + + /** + * Teardown actions after test method execution + */ + protected void tearDown() { + // can be overridden by subclasses + } + + /** + * @return OSGi component context + */ + public final ComponentContext componentContext() { + if (this.componentContext == null) { + this.componentContext = MockOsgi.newComponentContext(); + } + return this.componentContext; + } + + /** + * @return OSGi Bundle context + */ + public final BundleContext bundleContext() { + return componentContext().getBundleContext(); + } + + /** + * Registers a service in the mocked OSGi environment. + * @param <T> Service type + * @param service Service instance + * @return Registered service instance + */ + public final <T> T registerService(final T service) { + return registerService(null, service, null); + } + + /** + * Registers a service in the mocked OSGi environment. + * @param <T> Service type + * @param serviceClass Service class + * @param service Service instance + * @return Registered service instance + */ + public final <T> T registerService(final Class<T> serviceClass, final T service) { + return registerService(serviceClass, service, null); + } + + /** + * Registers a service in the mocked OSGi environment. + * @param <T> Service type + * @param serviceClass Service class + * @param service Service instance + * @param properties Service properties (optional) + * @return Registered service instance + */ + public final <T> T registerService(final Class<T> serviceClass, final T service, final Map<String, Object> properties) { + Dictionary<String, Object> serviceProperties = null; + if (properties != null) { + serviceProperties = new Hashtable<String, Object>(properties); + } + bundleContext().registerService(serviceClass != null ? serviceClass.getName() : null, service, + serviceProperties); + return service; + } + + /** + * Injects dependencies, activates and registers a service in the mocked + * OSGi environment. + * @param <T> Service type + * @param service Service instance + * @return Registered service instance + */ + public final <T> T registerInjectActivateService(final T service) { + return registerInjectActivateService(service, ImmutableMap.<String, Object> of()); + } + + /** + * Injects dependencies, activates and registers a service in the mocked + * OSGi environment. + * @param <T> Service type + * @param service Service instance + * @param properties Service properties (optional) + * @return Registered service instance + */ + public final <T> T registerInjectActivateService(final T service, final Map<String, Object> properties) { + MockOsgi.injectServices(service, bundleContext()); + MockOsgi.activate(service, bundleContext(), properties); + registerService(null, service, null); + return service; + } + + /** + * Lookup a single service + * @param <ServiceType> Service type + * @param serviceType The type (interface) of the service. + * @return The service instance, or null if the service is not available. + */ + @SuppressWarnings("unchecked") + public final <ServiceType> ServiceType getService(final Class<ServiceType> serviceType) { + ServiceReference serviceReference = bundleContext().getServiceReference(serviceType.getName()); + if (serviceReference != null) { + return (ServiceType)bundleContext().getService(serviceReference); + } else { + return null; + } + } + + /** + * Lookup one or several services + * @param <ServiceType> Service type + * @param serviceType The type (interface) of the service. + * @param filter An optional filter (LDAP-like, see OSGi spec) + * @return The services instances or an empty array. + * @throws RuntimeException If the <code>filter</code> string is not a valid OSGi service filter string. + */ + @SuppressWarnings("unchecked") + public final <ServiceType> ServiceType[] getServices(final Class<ServiceType> serviceType, final String filter) { + try { + ServiceReference[] serviceReferences = bundleContext().getServiceReferences(serviceType.getName(), + filter); + if (serviceReferences != null) { + ServiceType[] services = (ServiceType[])Array.newInstance(serviceType, serviceReferences.length); + for (int i = 0; i < serviceReferences.length; i++) { + services[i] = (ServiceType)bundleContext().getService(serviceReferences[i]); + } + return services; + } else { + return (ServiceType[])ArrayUtils.EMPTY_OBJECT_ARRAY; + } + } catch (InvalidSyntaxException ex) { + throw new RuntimeException("Invalid filter syntax: " + filter, ex); + } + } + +} diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/context/package-info.java b/src/main/java/org/apache/sling/testing/mock/osgi/context/package-info.java new file mode 100644 index 0000000..1ac49a4 --- /dev/null +++ b/src/main/java/org/apache/sling/testing/mock/osgi/context/package-info.java @@ -0,0 +1,23 @@ +/* + * 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. + */ +/** + * OSGi context implementation for unit tests. + */ [email protected]("1.0") +package org.apache.sling.testing.mock.osgi.context; diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContext.java b/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContext.java new file mode 100644 index 0000000..1704b72 --- /dev/null +++ b/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContext.java @@ -0,0 +1,111 @@ +/* + * 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.testing.mock.osgi.junit; + +import org.apache.sling.testing.mock.osgi.context.OsgiContextImpl; +import org.junit.rules.ExternalResource; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * JUnit rule for setting up and tearing down OSGi context for unit tests. + */ +public final class OsgiContext extends OsgiContextImpl implements TestRule { + + private final OsgiContextCallback setUpCallback; + private final OsgiContextCallback tearDownCallback; + private final TestRule delegate; + + /** + * Initialize Sling context with default resource resolver type: + * {@link org.apache.sling.testing.mock.sling.MockSling#DEFAULT_RESOURCERESOLVER_TYPE}. + */ + public OsgiContext() { + this(null, null); + } + + /** + * Initialize Sling context with default resource resolver type: + * {@link org.apache.sling.testing.mock.sling.MockSling#DEFAULT_RESOURCERESOLVER_TYPE}. + * @param setUpCallback Allows the application to register an own callback + * function that is called after the built-in setup rules are + * executed. + */ + public OsgiContext(final OsgiContextCallback setUpCallback) { + this(setUpCallback, null); + } + + /** + * Initialize Sling context with resource resolver type. + * @param setUpCallback Allows the application to register an own callback + * function that is called after the built-in setup rules are + * executed. + * @param tearDownCallback Allows the application to register an own + * callback function that is called before the built-in teardown + * rules are executed. + * @param resourceResolverType Resource resolver type. + */ + public OsgiContext(final OsgiContextCallback setUpCallback, final OsgiContextCallback tearDownCallback) { + + this.setUpCallback = setUpCallback; + this.tearDownCallback = tearDownCallback; + + // wrap {@link ExternalResource} rule executes each test method once + this.delegate = new ExternalResource() { + @Override + protected void before() { + OsgiContext.this.setUp(); + OsgiContext.this.executeSetUpCallback(); + } + + @Override + protected void after() { + OsgiContext.this.executeTearDownCallback(); + OsgiContext.this.tearDown(); + } + }; + } + + @Override + public Statement apply(final Statement base, final Description description) { + return this.delegate.apply(base, description); + } + + private void executeSetUpCallback() { + if (this.setUpCallback != null) { + try { + this.setUpCallback.execute(this); + } catch (Throwable ex) { + throw new RuntimeException("Executing setup callback failed.", ex); + } + } + } + + private void executeTearDownCallback() { + if (this.tearDownCallback != null) { + try { + this.tearDownCallback.execute(this); + } catch (Throwable ex) { + throw new RuntimeException("Executing setup callback failed.", ex); + } + } + } + +} diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextCallback.java b/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextCallback.java new file mode 100644 index 0000000..751ce7e --- /dev/null +++ b/src/main/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextCallback.java @@ -0,0 +1,37 @@ +/* + * 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.testing.mock.osgi.junit; + +import java.io.IOException; + +/** + * Callback-interface for application-specific setup and teardown operations to + * customize the {@link OsgiContext} JUnit rule. + */ +public interface OsgiContextCallback { + + /** + * Execute callback action + * @param context Sling context + * @throws IOException + * @throws PersistenceException + */ + void execute(OsgiContext context) throws IOException; + +} diff --git a/src/main/java/org/apache/sling/testing/mock/osgi/junit/package-info.java b/src/main/java/org/apache/sling/testing/mock/osgi/junit/package-info.java new file mode 100644 index 0000000..dd18eb6 --- /dev/null +++ b/src/main/java/org/apache/sling/testing/mock/osgi/junit/package-info.java @@ -0,0 +1,23 @@ +/* + * 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. + */ +/** + * Rule for providing easy access to OSGi context in JUnit tests. + */ [email protected]("1.0") +package org.apache.sling.testing.mock.osgi.junit; diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImplTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImplTest.java new file mode 100644 index 0000000..902624e --- /dev/null +++ b/src/test/java/org/apache/sling/testing/mock/osgi/context/OsgiContextImplTest.java @@ -0,0 +1,96 @@ +/* + * 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.testing.mock.osgi.context; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.osgi.framework.ServiceReference; + +public class OsgiContextImplTest { + + private OsgiContextImpl context; + + @Before + public void setUp() throws Exception { + this.context = new OsgiContextImpl(); + this.context.setUp(); + } + + @After + public void tearDown() throws Exception { + this.context.tearDown(); + } + + @Test + public void testContextObjects() { + assertNotNull(context.componentContext()); + assertNotNull(context.bundleContext()); + } + + @Test + public void testRegisterService() { + Set<String> myService = new HashSet<String>(); + context.registerService(Set.class, myService); + + Set<?> serviceResult = context.getService(Set.class); + assertSame(myService, serviceResult); + } + + @Test + public void testRegisterServiceWithProperties() { + Map<String, Object> props = new HashMap<String, Object>(); + props.put("prop1", "value1"); + + Set<String> myService = new HashSet<String>(); + context.registerService(Set.class, myService, props); + + ServiceReference serviceReference = context.bundleContext().getServiceReference(Set.class.getName()); + Object serviceResult = context.bundleContext().getService(serviceReference); + assertSame(myService, serviceResult); + assertEquals("value1", serviceReference.getProperty("prop1")); + } + + @Test + public void testRegisterMultipleServices() { + Set<String> myService1 = new HashSet<String>(); + context.registerService(Set.class, myService1); + Set<String> myService2 = new HashSet<String>(); + context.registerService(Set.class, myService2); + + Set[] serviceResults = context.getServices(Set.class, null); + assertSame(myService1, serviceResults[0]); + assertSame(myService2, serviceResults[1]); + } + + @Test + public void testRegisterInjectActivate() { + context.registerInjectActivateService(new Object()); + } + +} diff --git a/src/test/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextTest.java b/src/test/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextTest.java new file mode 100644 index 0000000..0de149b --- /dev/null +++ b/src/test/java/org/apache/sling/testing/mock/osgi/junit/OsgiContextTest.java @@ -0,0 +1,53 @@ +/* + * 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.testing.mock.osgi.junit; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import java.io.IOException; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class OsgiContextTest { + + private final OsgiContextCallback contextSetup = mock(OsgiContextCallback.class); + private final OsgiContextCallback contextTeardown = mock(OsgiContextCallback.class); + + // Run all unit tests for each resource resolver types listed here + @Rule + public OsgiContext context = new OsgiContext(contextSetup, contextTeardown); + + @Before + public void setUp() throws IOException { + verify(contextSetup).execute(context); + } + + @Test + public void testBundleContext() { + assertNotNull(context.bundleContext()); + } + +} -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
