Search code examples
unit-testingosgiaemsling

Exception on service activation in mock OSGi context


In my Maven project, I've created a simple OSGi service that does nothing but accepts one reference:

import org.apache.sling.api.resource.ResourceResolverFactory;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

@Component
public class MyFoo {
    @Reference
    private ResourceResolverFactory factory;
}

Then, using osgi-mock tutorial, I've created the following test class:

import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
public class MyFooTest {
    @Rule
    public OsgiContext mockContext = new OsgiContext();

    @Test
    public void test() {
        ResourceResolverFactory mockFactory = Mockito.mock(ResourceResolverFactory.class);

        mockContext.registerService(ResourceResolverFactory.class, mockFactory);
        mockContext.registerInjectActivateService(new MyFoo());
    }

}

The test crashes on the last line with the following exception:

org.apache.sling.testing.mock.osgi.NoScrMetadataException: No OSGi SCR metadata found for class MyFoo

    at org.apache.sling.testing.mock.osgi.OsgiServiceUtil.injectServices(OsgiServiceUtil.java:381)
    at org.apache.sling.testing.mock.osgi.MockOsgi.injectServices(MockOsgi.java:148)
    at org.apache.sling.testing.mock.osgi.context.OsgiContextImpl.registerInjectActivateService(OsgiContextImpl.java:153)
    at org.apache.sling.testing.mock.osgi.context.OsgiContextImpl.registerInjectActivateService(OsgiContextImpl.java:141)
    at MyFooTest.testGetResolver(MyFooTest.java:22)
//snippet

Following the advice on the internet, I've reached this configuration guide and ensured that my pom.xml has exactly this configuration for maven-bundle-plugin - this however did not resolve the issue.

Any idea where am I making a mistake?


Solution

  • I tried replicating your issue, ran into the same exception initially and got it working now. Issue is probably due to spoiled classpath because of transitive dependencies between maven-scr-plugin and maven-bundle-plugin.

    Ensure you have the following in place:

    • Use osgi-mock 2.x mock dependency which is OSGI R6 compatible. This is what I used.

          <dependency>
              <groupId>org.apache.sling</groupId>
              <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
              <version>2.3.6</version>
              <scope>test</scope>
          </dependency>
      
    • Remove scr maven plugins and dependencies (maven-scr-plugin and org.apache.felix.scr) as this leads to classpath conflicts when used in conjunction with OSGi R6 annotations. This is the version of maven-bundle-plugin I've used. I picked up all the required dependencies from here.

              <plugin>
                  <groupId>org.apache.felix</groupId>
                  <artifactId>maven-bundle-plugin</artifactId>
                  <version>3.2.0</version>
              </plugin>
      
    • Ensure your plugin build section contains the required configurations to generate the required DS metadata. You can refer to the felix docs that you've linked for more info on this.

          <plugin>
              <groupId>org.apache.felix</groupId>
              <artifactId>maven-bundle-plugin</artifactId>
              <extensions>true</extensions>
              <executions>
                  <execution>
                      <id>scr-metadata</id>
                      <goals>
                          <goal>manifest</goal>
                      </goals>
                  </execution>
              </executions>
              <configuration>
                  <exportScr>true</exportScr>
                  <instructions>
                      <Bundle-SymbolicName>com.aem.chula.chula</Bundle-SymbolicName>
      
                      <Sling-Model-Packages>
                        com.aem.models
                      </Sling-Model-Packages>
      
                      <_dsannotations>*</_dsannotations>
                      <_metatypeannotations>*</_metatypeannotations>
                  </instructions>
              </configuration>
          </plugin>
      
    • Do a mvn clean install which will generate the DS output in /OSG-INF.

    • Run your tests. I've used MockitoJunitRunner, should work fine with PowerMock as well.

    enter image description here