Я пытаюсь выяснить, как реализовать тест интеграции нескольких пакетов в OSGi с помощью JUnit.
С тестом интеграции я подразумеваю создание экземпляра набора для автоматической проверки функциональности в этой подсистеме.
Мы запускаем Equinox и используем Eclipse в качестве инструментальной цепочки. Eclipse предлагает вариант "Запускать как JUnit Plug-in", который поддерживает платформу OSGi и создает пакеты конфигурации, поэтому я предполагаю, что это путь к следующему примеру, но я не нашел способ внедрить ссылки DS в мои тесты. Я видел использование ServiceTracker в качестве программного средства для доступа к различным пакетам услуг, но это бьет цель иметь DS, не так ли?
Я только начинаю работать с OSGI, поэтому я полагаю, что я просто пропустил часть головоломки, которая позволила бы мне объединить мои тесты с несколькими пучками.
Любые идеи?
Спасибо, Джерард.
* РЕДАКТИРОВАТЬ: РЕШЕНИЕ *
После дальнейшего изучения этой проблемы я, наконец, понял, как установить эти тесты интеграции с несколькими путями с помощью функции плагина JUnit:
Для внедрения динамических служб необходимо создать файл определения службы, в котором должны быть объявлены вложенные зависимости, как это обычно делается при работе с DS.
Этот файл идет (обычно) в каталоге OSGI-INF/
. например OSGI-INF/service.xml
service.xml должен объявить необходимые зависимости для этого теста, но не предлагает собственную услугу:
service.xml
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="MyTest" activate="startup" deactivate="shutdown">
<implementation class="com.test.functionaltest.MyTester"/>
<reference name="OtherService" interface="com.product.service.FooService" policy="static" cardinality="1..1" bind="onServiceUp" unbind="onServiceDown"/>
</scr:component>
Это даст указание DS ввести зависимость от FooService с помощью объявленного метода onServiceUp. onServiceDown должен быть реализован так, как он вызывается во время фазы останова OSGi после запуска тестов.
com.test.functionaltest.MyTester содержит методы тестирования, которые должны выполняться, следуя типичным практикам JUnit.
До сих пор все это "по книге". Тем не менее, если Junit запущен, он будет генерировать исключение NullPointerException при доступе к ссылке на FooService. Причина этого заключается в том, что инфраструктура OSGi находится в состоянии гонки с использованием контекста Running JUnit, и обычно победитель теста Junit выигрывает эту гонку, выполняя тесты до того, как вводится ссылка на требуемую услугу.
Чтобы решить эту проблему, потребовалось, чтобы тест Junit дождался, когда OSGi выполнит свою работу. Я обратился к этой проблеме с помощью CountDownLatch, который инициализируется количеством зависимых сервисов, необходимых в тесте. Затем каждый метод инъекции зависимости рассчитывается, и когда все будет сделано, начнется тест. Код выглядит следующим образом:
private static CountDownLatch dependencyLatch = new CountDownLatch(1);// 1 = number of dependencies required
static FooService fooService = null;
public void onFooServiceUp(FooService service) {
fooService = service;
dependencyLatch.countDown();
}
Обратите внимание, что ссылка fooService
должна быть статической, чтобы разрешить совместное использование ссылки на службу между OSGi и контекстами выполнения JUnit. CountDownLatch обеспечивает механизм синхронизации на высоком уровне для безопасной публикации этой общей ссылки.
Затем перед выполнением теста следует добавить проверку зависимостей:
@Before
public void dependencyCheck() {
// Wait for OSGi dependencies
try {
dependencyLatch.await(10, TimeUnit.SECONDS);
// Dependencies fulfilled
} catch (InterruptedException ex) {
fail("OSGi dependencies unfulfilled");
}
}
Таким образом, инфраструктура Junit ожидает, что служба OSGi DS будет вводить зависимости или терпеть неудачу после таймаута.
Мне потребовалось некоторое время, чтобы полностью понять это. Надеюсь, это сэкономит головную боль другим программистам в будущем.