Проблемы тестирования сервисов, созданных с помощью maven-scr-plugin, при использовании pax-exam

Я создал очень простую службу «HelloWorld», чтобы продемонстрировать свою проблему. Он использует плагин maven-scr-plugin для создания дескриптора службы и имеет модульный тест pax-exam. Но когда я пытаюсь запустить «mvn clean test», он некоторое время блокируется, прежде чем выдать мне эту ошибку:

 org.ops4j.pax.swissbox.tracker.ServiceLookupException: gave up waiting for service com.liveops.examples.osgi.helloworld.HelloWorldService

Если я запускаю «mvn -DskipTests=true package», а затем запускаю «mvn test» (без очистки), он работает. Разница, похоже, заключается в добавлении этой строки в мой файл META-INF/M ANIFEST.MF:

 Service-Component: OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml

Кто-нибудь знает, есть ли способ убедиться, что эта строка добавлена ​​​​ранее в процессе сборки, чтобы «mvn clean test» прошел? Или может я что-то еще делаю не так?


Для справки, вот pom.xml, служба и модульный тест.

    <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.liveops.examples</groupId>
    <artifactId>HelloWorldService</artifactId>
    <version>1.0.0-SNAPSHOT</version>

    <packaging>bundle</packaging>

    <dependencies>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>org.osgi.core</artifactId>
            <version>4.3.1</version>
        </dependency>
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>
        <dependency>
            <groupId>org.ops4j.pax.exam</groupId>
            <artifactId>pax-exam</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
             <groupId>org.ops4j.pax.exam</groupId>
             <artifactId>pax-exam-container-native</artifactId>
             <version>3.3.0</version>
             <scope>test</scope>
         </dependency>
        <dependency>
            <groupId>org.ops4j.pax.exam</groupId>
            <artifactId>pax-exam-junit4</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.ops4j.pax.url</groupId>
            <artifactId>pax-url-aether</artifactId>
            <version>1.6.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.ops4j.pax.exam</groupId>
            <artifactId>pax-exam-link-mvn</artifactId>
            <version>3.3.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.5.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.felix</groupId>
            <artifactId>org.apache.felix.framework</artifactId>
            <version>4.0.2</version>
            <scope>test</scope>
        </dependency>     
        <dependency>
            <groupId>org.apache.felix</groupId>
            <artifactId>org.apache.felix.scr.annotations</artifactId>
            <version>1.9.0</version>
        </dependency>
    </dependencies>

    <properties>
        <namespace>com.liveops.examples.osgi.helloworld</namespace>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.0</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>

            <plugin>
                <!--
                 | the following instructions build a simple set of public/private classes into an OSGi bundle
                -->
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <version>2.3.7</version>
                <extensions>true</extensions>                
                <configuration>
                    <instructions>
                        <Bundle-SymbolicName>${project.name}</Bundle-SymbolicName>
                        <Bundle-Version>${project.version}</Bundle-Version>
                        <!-- Bundle-Activator>${namespace}.internal.HelloActivator</Bundle-Activator -->
                        <!--
                         | assume public classes are in the top package, and private classes are under ".internal"
                        -->
                        <Export-Package>!${namespace}.internal.*,${namespace}.*;version="${project.version}"</Export-Package>
                        <Private-Package>${namespace}.internal.*</Private-Package>
                        <!--
                         | each module can override these defaults in their osgi.bnd file
     -->
                        <!--_include>-osgi.bnd</_include-->
                    </instructions>
                </configuration>   
                <executions>
                    <execution>
                        <id>generate-manifest</id>
                        <phase>process-classes</phase>
                        <goals>
                            <goal>manifest</goal>
                        </goals>
                    </execution>
                </executions>          
            </plugin>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-scr-plugin</artifactId>
                <version>1.9.0</version>
                <configuration>
                    <supportedProjectTypes>
                        <supportedProjectType>jar</supportedProjectType>
                        <supportedProjectType>bundle</supportedProjectType>
                        <supportedProjectType>war</supportedProjectType>
                    </supportedProjectTypes>
                    <generateAccessors>true</generateAccessors>
                    <strictMode>true</strictMode>
                    <specVersion>1.1</specVersion>
                    <outputDirectory>target/classes</outputDirectory>
                </configuration>
                <executions>
                    <execution>
                        <id>generate-scr-scrdescriptor</id>
                        <goals>
                            <goal>scr</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

Класс реализации HelloWorld

package com.liveops.examples.osgi.helloworld.internal;

import com.liveops.examples.osgi.helloworld.HelloWorldService;
import org.apache.felix.scr.annotations.Service;
import org.apache.felix.scr.annotations.Component;


@Component
@Service(HelloWorldService.class)
public class HelloImpl implements HelloWorldService
{  
    public String helloWorld(String personalization)
    {
        return "Hello " + personalization + "!";
    }
}

Модульный тест

package com.liveops.examples.osgi.helloworld.internal;

import com.liveops.examples.osgi.helloworld.HelloWorldService;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.util.PathUtils;

import javax.inject.Inject;

import static org.ops4j.pax.exam.CoreOptions.*;

@RunWith(PaxExam.class)
public class HelloImplTest
{
    @Inject
    HelloWorldService hws;

    @Configuration

    public static Option[] configuration() throws Exception{
            return options(
                    systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("WARN"),
                    mavenBundle("org.apache.felix", "org.apache.felix.scr", "1.6.2"),
                    bundle("reference:file:" + PathUtils.getBaseDir() + "/target/classes"),
                           junitBundles());
    }

    @Test
    public void testInjection()
    {
        Assert.assertNotNull(hws);
    }

    @Test
    public void testHelloWorld() throws Exception
    {
        Assert.assertNotNull(hws);
        Assert.assertEquals("Hello UnitTest!", hws.helloWorld("UnitTest"));

    }
}

person peterc    schedule 30.09.2013    source источник


Ответы (3)


Используйте ProbeBuilder для улучшения протестированного пакета:

    @ProbeBuilder
public TestProbeBuilder probeConfiguration(TestProbeBuilder probe) {
    probe.setHeader("Service-Component", "OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml");
    return probe;
}

Это, скорее всего, все, чего не хватает.

РЕДАКТИРОВАТЬ:

на всякий случай, если вы пытаетесь использовать pax-exam в том же пакете, вам необходимо выполнить определенные действия в вашем методе конфигурации:

streamBundle(bundle()
.add(SomceClass.class).add("OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml", new File("src/main/resources/OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml")
.toURL())
.set("Service-Component", "OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml")
.build()).start()

полный пример можно найти по адресу здесь

person Achim Nierbeck    schedule 01.10.2013
comment
Спасибо за ответ, но это, похоже, не работает. По-видимому, @ProbeBuilder устарел, и когда я пробую этот метод, я получаю эту ошибку: ERROR: PAXEXAM-PROBE-c57393ab-7878-4dd3-b533-cbbfb90411d4 (18): Component descriptor entry 'OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml' not found - person peterc; 01.10.2013
comment
Это, конечно, не устарело, вы добавили этот метод в свой тестовый класс? Взгляните на один из моих примеров: github.com/ANierbeck/Camel-Pax-Exam-Demo/blob/master/ - person Achim Nierbeck; 01.10.2013
comment
org.ops4j.pax.exam.junit.ProbeBuilder устарел и был заменен org.ops4j.pax.exam.ProbeBuilder. - person Harald Wellmann; 02.10.2013
comment
@hwellmann, @achim-nierbeck - Ааа, спасибо за разъяснение. Моя ошибка, я пытался использовать junit.ProbeBuilder. Однако по-прежнему возникает ошибка «Файл не найден». - person peterc; 02.10.2013
comment
@peterc вполне может быть, что он еще не сгенерирован? Используете ли вы тесты pax-exam вместо модульных тестов? Они обычно для itests. - person Achim Nierbeck; 02.10.2013
comment
@AchimNierbeck Этот пример этого не показывает, но моя цель состояла в том, чтобы использовать pax-exam для внедрения фиктивных сервисов на этапе модульного тестирования. Я также планирую использовать его для интеграционных тестов, но это можно сделать из другого проекта maven, поэтому у меня не должно быть проблем, с которыми я сталкиваюсь здесь. - person peterc; 02.10.2013
comment
@peterc В этом примере не показано, как использовать макеты, но он используется на этапе модульного тестирования, поэтому вам необходимо убедиться, что вы используете все свои классы и ресурсы вашего проекта в пользовательском пакете, созданном с помощью streamBuilder, как показано в моем примере. и в коде выше. - person Achim Nierbeck; 03.10.2013
comment
Спасибо @AchimNierbeck. Тогда я буду использовать это как шаблон для этих тестов. - person peterc; 03.10.2013

У меня может быть исправление для этого, хотя это кажется немного неэлегантным. Я могу явно добавить Service-Component в раздел maven-bundle-plugin файла pom.

    <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <version>2.3.7</version>
        <extensions>true</extensions>                
        <configuration>
            <instructions>
                <Bundle-SymbolicName>${project.name}</Bundle-SymbolicName>
                <Bundle-Version>${project.version}</Bundle-Version>
                <Export-Package>!${namespace}.internal.*,${namespace}.*;version="${project.version}"</Export-Package>
                <Private-Package>${namespace}.internal.*</Private-Package>

                <!--Explicitly add the components no that they can be found in the test phase -->
                <Service-Component>OSGI-INF/com.liveops.examples.osgi.helloworld.internal.HelloImpl.xml</Service-Component>
            </instructions>
        </configuration>   
        <executions>
            <execution>
                <id>generate-manifest</id>
                <phase>process-classes</phase>
                <goals>
                    <goal>manifest</goal>
                </goals>
            </execution>
        </executions>          
    </plugin>

Пожалуйста, дайте мне знать, если кто-нибудь может придумать лучший способ.

person peterc    schedule 01.10.2013

Плагин Maven SCR только генерирует дескрипторы компонентов службы, но не включает их в манифест автоматически.

Так что нет ничего неэлегантного во включении инструкции <Service-Component> в конфигурацию плагина Maven Bundle, это просто задокументированное использование.

Так как заголовок манифеста отсутствует, SCR не регистрирует никаких сервисов от имени вашего пакета, поэтому Pax Exam не может найти нужный сервис.

person Harald Wellmann    schedule 01.10.2013
comment
Я ценю ваш ответ. Я думаю, что я пойду по этому пути, но в документе, на который вы ссылаетесь, говорится, что <Service-Component> будет создан, когда вы используете как maven-scr-plugin, так и maven-bundle-plugin, поэтому вам не нужно настраивать это самостоятельно. И он действительно создает эту запись в файле MANIFEST.MF. Просто это слишком поздно для этапа тестирования, и, как вы сказали, сервис не зарегистрирован, поэтому pax-exam не может его найти. - person peterc; 02.10.2013