Службы администрирования конфигурации и декларативные службы не созданы на этапе тестирования экзамена pax

Я написал @component в DS, который должен создаваться и активироваться в нескольких экземплярах. Чтобы проверить это, я написал тест на экзамен pax, в котором я загружаю karaf и добавляю scr. Все работает нормально, но... он не будет создавать экземпляры служб до тех пор, пока не будет запущен тестовый метод, поэтому у меня нет места для утверждений и т. д.

@Test
public final void testing() throws Exception { 
props = createProperties(user, pass, host);
cfg = configurationAdmin.
     createFactoryConfiguration(CouchbaseConnectionProvider.SVC_NAME);
cfg.update(props);

final ServiceTracker tracker = new ServiceTracker(bundleContext, CouchbaseConnectionProvider.class, null);
tracker.open();

CouchbaseConnectionProvider svc = (CouchbaseConnectionProvider) tracker.waitForService(5000);
// It will wait 5s and after testing exits it will create the service
}

Что я здесь делаю неправильно? Поскольку при выходе из метода он правильно создаст и активирует службу со всеми свойствами.

Я могу добавить, что метод тестирования использует поток "ion(3)-127.0.0.1", а когда DS создает экземпляр, использует поток "84-b6b23468b652)".

Привет, Марио

Обновление 3 На самом деле там было две ошибки, одна на моей стороне, а другая где-то еще (в felix CM?), так как конфигурация стала доступной через мой пакет интерфейса через некоторое время (пока контейнер закрывался), но он действительно должен быть привязан к тестовому пакету pax (и, конечно, к самому CM) и никогда не быть «свободным: d», когда контейнер закрывается. Где этот баг я не знаю - я завершу минималистичный проект mvn и попробую ребят из felix cm и выложу сюда обновление.

Обновление 2. Я сообщил об ошибке (https://ops4j1.jira.com/browse/PAXEXAM-725), если кому-то интересно следить за прогрессом (если есть баг ;))

Обновление 1 Это моя конфигурация в тестовом классе

package se.crossbreed.foundation.persistence.provider.couchbase;

@RunWith(PaxExam.class)
@ExamReactorStrategy(PerClass.class)
public class CouchbaseConnectionProviderTests extends CbTestBase {
  ...
}

Вот конфигурация в тестовом классе, которая будет использовать базовый класс для базовых параметров.

@org.ops4j.pax.exam.Configuration
public Option[] config() {
    List<Option> options = super.baseConfig();
    options.addAll(Arrays
            .asList(features(karafStandardRepo, "scr"),
                    mavenBundle()
                            .groupId("se.crossbreed.foundation.persistence")
                            .artifactId(
                                    "se.crossbreed.foundation.persistence.core")
                            .versionAsInProject(),
                    mavenBundle().groupId("io.reactivex")
                            .artifactId("rxjava").versionAsInProject(),
                    mavenBundle()
                            .groupId("se.crossbreed.ports.bundles")
                            .artifactId(
                                    "se.crossbreed.ports.bundles.couchbase.java-client")
                            .versionAsInProject(),
                    mavenBundle()
                            .groupId("se.crossbreed.foundation.persistence")
                            .artifactId(
                                    "se.crossbreed.foundation.persistence.provider.couchbase")
                            .versionAsInProject()));

    // above bundle is the one I'm trying to test and where
    // this test resides in (project wise)
    return options.toArray(new Option[] {});
}

Базовая конфигурация получена из базового класса

protected List<Option> baseConfig() {
    return new ArrayList<Option>(
            Arrays.asList(new Option[] {
                    logLevel(LogLevel.INFO),
                    karafDistributionConfiguration().frameworkUrl(karafUrl)
                            .unpackDirectory(new File("target", "exam"))
                            .useDeployFolder(false),
                    configureConsole().ignoreLocalConsole(),
                    mavenBundle().groupId("biz.aQute.bnd")
                            .artifactId("bndlib").version("${version.bndlib}"),
                    mavenBundle()
                            .groupId("se.crossbreed.foundation")
                            .artifactId(
                                    "se.crossbreed.foundation.core.annotations")
                            .versionAsInProject(),
                    mavenBundle()
                            .groupId("se.crossbreed.foundation")
                            .artifactId(
                                    "se.crossbreed.foundation.core.interfaces")
                            .versionAsInProject() }));
}

Пакет для теста есть

package se.crossbreed.foundation.persistence.provider.couchbase;

И CouchbaseConnectionProvider находится в том же пакете

package se.crossbreed.foundation.persistence.provider.couchbase;

import se.crossbreed.foundation.persistence.core.CbDbConnectionProvider;

public interface CouchbaseConnectionProvider extends CbDbConnectionProvider {
    public final static String SVC_NAME = "couchbase.connection.provider";
}

Реализация:

package se.crossbreed.foundation.persistence.provider.couchbase.impl;

@Component(immediate = true, name = 
    CouchbaseConnectionProvider.SVC_NAME, provide = {
    CouchbaseConnectionProvider.class, CbDbConnectionProvider.class,
    CbService.class }, properties = { "providerType=DOCUMENT" }, 
    configurationPolicy = ConfigurationPolicy.require)
    public class CouchbaseConnectionProviderImpl implements
    CouchbaseConnectionProvider { ... }

Вот структура проекта Couchbase Provider и тест, который я не могу заставить работать (пока тест не будет запущен;).

Структура проекта поставщика диванов и теста


person Mario Toffia    schedule 07.07.2015    source источник


Ответы (3)


(На самом деле я не вижу ничего плохого в вашем коде, ConfigurationAdmin должен работать асинхронно. Новая служба, появившаяся после теста, по-прежнему выглядит как проблема синхронизации. В этом случае эта настройка может это исправить.)

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

@org.ops4j.pax.exam.Configuration
public Option[] config() {
    List<Option> options = super.baseConfig();
    options.addAll(Arrays
        .asList(features(karafStandardRepo, "scr"),
        //missing conversion: putAll() needs a Map        
        ConfigurationAdminOptions.factoryConfiguration(CouchbaseConnectionProvider.SVC_NAME)
                        .putAll(createProperties(user, pass, host)).create(true).asOption(),
                mavenBundle()
                        .groupId("se.crossbreed.foundation.persistence")
                        .artifactId(
                                "se.crossbreed.foundation.persistence.core")
                        .versionAsInProject(),
                mavenBundle().groupId("io.reactivex")
                        .artifactId("rxjava").versionAsInProject(),
                mavenBundle()
                        .groupId("se.crossbreed.ports.bundles")
                        .artifactId(
                                   "se.crossbreed.ports.bundles.couchbase.java-client")
                        .versionAsInProject(),
                mavenBundle()
                        .groupId("se.crossbreed.foundation.persistence")
                        .artifactId(
                                "se.crossbreed.foundation.persistence.provider.couchbase")
                        .versionAsInProject()));

    // above bundle is the one I'm trying to test and where
    // this test resides in (project wise)
    return options.toArray(new Option[] {});
}

Настройки Мавена:

<dependency>
    <groupId>org.ops4j.pax.exam</groupId>
    <artifactId>pax-exam-cm</artifactId>
    <version>${exam.version}</version>                
</dependency>

Затем вы также можете просто использовать аннотацию @Inject, чтобы получить CouchbaseConnectionProvider внутри теста.

@Inject
CouchbaseConnectionProvider svc;
person user3653004    schedule 08.07.2015
comment
Спасибо за вашу помощь с AdminOptions! Да, я вижу, что он публикует его асинхронно (я думаю, DS является одним из слушателей). Однако кажется, что его поток ожидает во время теста. Это ошибка, о которой нужно сообщить в PAX? Этот конкретный случай - однако причина, по которой у меня есть экземпляр в моем тестовом методе, заключается в том, что я могу проверить его с другой зависимостью службы (внутри провайдера CouchbaseConnectionProvider) и как он активируется и деактивируется (надеюсь, правильно). В этой установке это будет невозможно сделать. - person Mario Toffia; 08.07.2015
comment
Спасибо за вашу помощь! На самом деле это была моя вина, я не указал правильного владельца для конфигурации (опущен нуль или правильное расположение пакета для моего пакета гибридного провайдера). Единственная загадка для меня осталась, почему в мире сервис был создан на более позднем этапе, так как он не владел конфигом... странно - но еще раз спасибо! :) ура / Марио - person Mario Toffia; 09.07.2015

Я подозреваю, что тест развертывает интерфейс CouchbaseConnectionProvider с самим собой. Таким образом, вы пытаетесь получить услугу, используя интерфейс, отличный от того, который предоставляет реальная служба.

Вы должны попытаться добавить импорт и экспорт в свой тестовый пакет для пакета, в котором находится CouchbaseConnectionProvider.

Для этого используйте ProbeBuilder

@ProbeBuilder
public TestProbeBuilder probeConfiguration(TestProbeBuilder probe) {
    probe.setHeader(Constants.IMPORT_PACKAGE, "..");
    probe.setHeader(Constants.EXPORT_PACKAGE, "..");
    return probe;
}
person Christian Schneider    schedule 07.07.2015
comment
Спасибо! :) - Теперь я понимаю, что вы пытаетесь мне сказать - да, тест находится в папке с тестами в том же проекте, что и мой src/main/java для интерфейса (и реализации) - Если сервис-трекер не работает - все будет в порядке но моя проблема в том, что DS не даже создаст/активирует мой сервис (см. обновленный вопрос :)). Это будет сделано после завершения метода тестирования и закрытия контейнера (тогда он будет создан). - person Mario Toffia; 07.07.2015
comment
Это была моя ошибка, я привязывал конфигурацию к текущему исполняемому пакету, опуская местоположение пакета в createFactoryConfiguration — спасибо за вашу помощь! - person Mario Toffia; 09.07.2015

спасибо вам обоим за ваш вклад - я решил ответить на этот вопрос сам, так как у меня была ошибка в моем коде и мне помог Кристоф.

Я цитирую его ответ здесь, если кто-то еще сделал то, что сделал я.

Проблема заключалась в том, что я не установил анонимное владение конфигурацией через (pid, null) в createFactoryConfiguration. Вместо этого я использовал createFactoryConfiguration(pid), после чего он был привязан к текущему исполняемому пакету, а не к пакету, который я тестировал. Как объяснил Кристоф, я мог получить местоположение пакета услуг и установить его явно.

Привет, Марио

Вот ответ Кристофа Лаубриха

"Christoph Läubrich добавил комментарий - 13 минут назад

Хорошо, я думаю, что теперь я знаю, в чем может быть проблема: вы используете createFactoryConfiguration(java.lang.String factoryPid), это означает, что вы создадите конфигурацию, которая привязана исключительно к вашему пакету! Таким образом, никакому другому пакету не разрешен доступ к конфигурации! Вместо этого используйте createFactoryConfiguration(java.lang.String factoryPid, java.lang.String location) с нулевым аргументом для местоположения! Таким образом вы создаете анонимную конфигурацию, которая будет привязана к первому пакету, извлекающему эту конфигурацию. В качестве альтернативы вы можете получить местоположение целевого пакета и явно передать его в качестве параметра, но часто это не требуется. Если это все еще не работает, мы должны более внимательно изучить вашу конфигурацию, подключиться к оболочке karaf (при остановке в точке останова) и получить список всех пакетов (bundle:list) и список всех компонентов (scr: список). Также вы должны собрать подробную информацию о пакете зонда и пакете, который должен предоставлять услугу (пакеты: импорт)».

person Mario Toffia    schedule 09.07.2015
comment
Вернее, то, что я сделал, это то, что я использую правильное расположение пакета, поскольку это то, что нужно, вместо первого захвата... cheers / mario - person Mario Toffia; 09.07.2015