Локальный запуск DataSpace Core в Unit-тестах#
О документе#
Документ содержит описание локального запуска DataSpace Core в Unit-тестах.
Расшифровку основных понятий см. в перечне «Термины и определения».
Общие сведения#
Модуль dataspace-core-local-runner предоставляет возможность запускать локально DataSpace Core в JUnit 5 тестах. Данная функциональность реализована через JUnit Extensions.
Далее описан способ подключения данной функциональности в maven-модуль.
Зависимости#
В модуле, в котором предполагается запуск локального DataSpace Core в JUnit-тестах, в секцию dependencies файла pom.xml необходимо подключить ряд зависимостей:
Зависимость на dataspace-core-local-runner:
<dependency> <groupId>sbp.com.sbt.dataspace</groupId> <artifactId>dataspace-core-local-runner</artifactId> <scope>test</scope> </dependency>Зависимость на starter test для подключения JUnit. Если используется spring > 2.4.0, можно удалить
exclusion:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency>Зависимости на SDK и JPA-классы:
<dependency> <groupId>${groupId}</groupId> <artifactId>${modelName}-model-sdk</artifactId> <version>${version}</version> </dependency> <dependency> <groupId>${groupId}</groupId> <artifactId>${modelName}-model-jpa</artifactId> <version>${version}</version> </dependency>В примере:
${groupId}— groupId сгенерированных модулей SDK и JPA-классов;${modelName}— имя модели.
Плагины#
В pom.xml в секцию build того модуля, в котором предполагается запуск локального DataSpace Core в JUnit тестах, необходимо подключить ряд плагинов:
Инициализация root.dir:
<plugin> <groupId>org.commonjava.maven.plugins</groupId> <artifactId>directory-maven-plugin</artifactId> <version>0.3</version> <executions> <execution> <id>dir</id> <phase>initialize</phase> <goals> <goal>highest-basedir</goal> </goals> <configuration> <property>root.dir</property> </configuration> </execution> </executions> </plugin>Копирование файла dataspace-core-local-runner.properties с настройками локального запуска DataSpace Core с фильтрацией placeholder (структуру файла dataspace-core-local-runner.properties см. в разделе «Исходный код»):
<plugin> <artifactId>maven-resources-plugin</artifactId> <executions> <execution> <id>copy-properties</id> <phase>process-resources</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> <outputDirectory>${project.basedir}/src/test/resources</outputDirectory> <resources> <resource> <directory>${root.dir}/config/standalone</directory> <filtering>true</filtering> </resource> </resources> </configuration> </execution> </executions> </plugin>Плагин для резервирования порта для DataSpace Core (опционально):
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <version>1.10</version> <executions> <execution> <id>reserve-dataspace-port</id> <goals> <goal>reserve-network-port</goal> </goals> <phase>generate-resources</phase> <configuration> <portNames> <portName>local.core.port</portName> </portNames> </configuration> </execution> </executions> </plugin>Плагин для копирования JAR-файлов в рабочую директорию локального DataSpace Core:
<plugin> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>copy-core</id> <phase>compile</phase> <goals> <goal>copy</goal> </goals> <configuration> <artifactItems> <artifactItem> <groupId>sbp.com.sbt.dataspace</groupId> <artifactId>dataspace-core-module</artifactId> </artifactItem> </artifactItems> <outputDirectory>${project.build.directory}/local-core</outputDirectory> </configuration> </execution> <execution> <id>copy-model</id> <phase>compile</phase> <goals> <goal>copy</goal> </goals> <configuration> <artifactItems> <artifactItem> <groupId>${groupId}</groupId> <artifactId>${modelName}-model-jpa</artifactId> </artifactItem> <artifactItem> <groupId>${groupId}</groupId> <artifactId>${modelName}-model-sdk</artifactId> </artifactItem> <artifactItem> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </artifactItem> </artifactItems> <outputDirectory>${project.build.directory}/local-core/resources</outputDirectory> </configuration> </execution> </executions> </plugin>
В примере: ${groupId} — groupId сгенерированных модулей SDK и JPA-классов; ${modelName} — имя модели. Если в секции parent проекта не используется dataspace-bom, то к артефакту h2 необходимо добавить секцию <version>1.4.200</version>.
Исходный код#
В папке с тестами (src/test) необходимо создать ряд файлов:
В папке ${root.dir}/config/standalone необходимо создать файл свойств dataspace-core-local-runner.properties:
core-version=${dataspace-core.version} working-directory=${project.build.directory}/local-core loader-path=${project.build.directory}/local-core/resources port=${local.core.port} adminPort=${local.core.admin.port} debugPort=${local.core.debug.port} spring-active-profiles=local-h2-profile overridden-spring-properties=--dataspace-core.model.packagesToScan=${groupId}В примере выше:
${dataspace-core.version}— версия DataSpace Core. По умолчанию берется из dataspace-bom, возможно переопределить в плагине maven-dependency-plugin.${project.build.directory}— стандартный maven-параметр.${local.core.port}— порт. Возможно задать вручную, через плагин build-helper-maven-plugin (указав цель reserve-network-port) или через параметр-D. Если свойство не указано, будет взят свободный порт.${local.core.admin.port}— service.server.port, создается аналогично${local.core.port}.${local.core.debug.port}— debug port, создается аналогично${local.core.port}.${groupId}— group-id сгенерированных JPA-классов из зависимости model-jpa.
В папке src/test/java/* создать класс
BaseTest.java:package ${groupId}; import org.junit.jupiter.api.extension.ExtendWith; import sbp.com.sbt.dataspace.core.local.runner.DataSpaceCoreLocalRunner; import sbp.com.sbt.dataspace.core.local.runner.junit5.JUnit5DataSpaceCoreLocalRunnerExtension; import sbp.com.sbt.dataspace.grasp.DataspaceCoreSearchClient; import sbp.sbt.sdk.DataspaceCorePacketClient; import sbp.com.sbt.dataspace.grasp.DataspaceCoreHistoryClient; @ExtendWith({JUnit5DataSpaceCoreLocalRunnerExtension.class}) public class BaseTest { private static int servicePort = Integer.parseInt(DataSpaceCoreLocalRunner.getRunnerProperties().getPort()); protected static DataspaceCorePacketClient dataspaceCorePacketClient = new DataspaceCorePacketClient("http://localhost:" + servicePort); protected static DataspaceCoreSearchClient dataspaceCoreSearchClient = new DataspaceCoreSearchClient("http://localhost:" + servicePort); protected static DataspaceCoreHistoryClient dataspaceCoreHistoryClient = new DataspaceCoreHistoryClient("http://localhost:" + servicePort); }
Использование#
После подключения всех необходимых зависимостей и плагинов, а также создания файлов, можно приступать к написанию тестов с использованием локального DataSpace Core. Для этого необходимо создать класс тестов и унаследовать его от BaseTest.java. Для каждого теста будет запущен локальный DataSpace Core с H2 In-Memory базой данных и пролиты Liquibase-скрипты. При необходимости можно выполнить локальный запуск тестов на внешней БД PostgreSQL.
package ${groupId};
import com.sun.tools.jdi.Packet;
import org.junit.jupiter.api.Test;
import ${groupId}.packet.packet.Packet;
/**
* Пример теста с использованием локального запуска DataSpace Core
*/
public class ModelTest extends BaseTest {
/**
* Демонстрационный тест.
* Создание SimpleEntity и получение SimpleEntity по id.
* @throws Throwable
*/
@Test
public void demoTest() throws Throwable {
String code="123456";
// Создаем пакет действий. Именно его мы будем отправлять на выполнение сервису.
Packet packet = new Packet();
// Добавляем в пакет команду создания сущности SimpleEntity. Устанавливаем поле code
SimpleEntityRef simpleEntityRef = packet.simpleEntity.create(param -> {
param.setCode(code);
});
//Отправляем пакет на исполнение
dataspaceCorePacketClient.execute(packet);
//Создаем другой пакет действий, так как один и тот же пакет нельзя выполнить несколько раз
Packet packetGet = new Packet();
//Добавляем в пакет команду получение сущности по ссылке. Говорим, что хотим вычитать поле code
SimpleEntityGet simpleEntityGet = packetGet.simpleEntity.get(simpleEntityRef, param -> {
param.withCode();
});
//Отправляем пакет на выполнение
dataspaceCorePacketClient.execute(packetGet);
Assertions.assertEquals(code, simpleEntityGet.getCode());
}
}
Внимание!
По умолчанию DataSpace Core запускается командой
java -cp ... .jar, но если определена пользовательская переменная средыJAVA_HOME, запуск будет осуществляться"%JAVA_HOME%/bin/java" -cp ... .jar.
Логирование#
Во время работы локальный DataSpace Core генерирует лог-записи. Данные лог-записи можно найти в папке logs рядом с запускаемым модулем. Необходимо убедиться, что в запускаемом файле local-run.sh указан параметр „-Dlogging.config=»classpath:logConfig/logback.xml»“
Debug#
DataSpace Core запускается с опцией для debug.
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=_debugPort_
В примере выше debugPort — значение debugPort=${local.core.debug.port} из файла dataspace-core-local-runner.properties. Если параметр в файле не указан, необходимо в логе смотреть строку «-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=».
TCP-сервер H2#
DataSpace Core содержит встроенный TCP-сервер для поддержки внешних подключений к H2.
Включение сервера осуществляется параметром dataspace-core.h2.tcp-port, значение которого определяет порт входящих подключений.
Пример настройки:
В файле local-run.sh добавляется настройка параметра
--dataspace-core.h2.tcp-port=9090, где9090— номер порта входящих подключений.После старта модуля для профиля
local-h2-profileстанет доступно подключение с параметрами:
JDBC URL: jdbc:h2:tcp://localhost:9090/mem:test;
DB SCHEMA/NAME: mem:test;
пользователь: sa;
используемая версия драйвера: 1.4.200.
Локальный запуск тестов на внешней БД PostgreSQL#
В файл свойств dataspace-core-local-runner.properties (каталог ${root.dir}/config/standalone), в свойство overridden-spring-properties необходимо добавить параметры:
--spring.datasource.url=${url} --spring.datasource.username=${username} --spring.datasource.password=${password} --spring.datasource.driver-class-name=org.postgresql.Driver --spring.jpa.database-platform=sbp.com.sbt.dataspace.DataspacePostgreSQLDialect --dataspace.datasource.primary.dbschema=${defaultSchemaName} --spring.liquibase.parameters.tablespace_t=${tablespace_t} --spring.liquibase.parameters.tablespace_i=${tablespace_i} --spring.liquibase.parameters.tablespace_l=${tablespace_l}
При этом defaultSchemaName (схема по умолчанию) нужно указывать только в свойстве dataspace.datasource.primary.dbschema.
Внимание!
После изменения dataspace-core-local-runner.properties необходимо выполнять сборку проекта.
Частые проблемы#
Тесты не дожидаются запуска DataSpace Core#
При запуске тестов с локальным запуском DataSpace Core выполнение тестов останавливается и ожидает запуска DataSpace Core.
Чтобы ожидание не оказалось бесконечным происходит retry-count попыток подключиться к модулю через каждые 5 секунд. По умолчанию retry-count равен «30». Таким образом если модуль не успевает запуститься за 150 секунд, тесты запускаются на не запущенном модуле и отрабатывают с ошибками.
Подобная ситуация происходит на слабом или перегруженном оборудовании. Чтобы предоставить больше времени на запуск модуля DataSpace Core, необходимо увеличить значение retry-count.
Для этого в файле (предполагается, что проект «из коробки») config/standalone/dataspace-core-local-runner.properties необходимо добавить большее значение параметра (например, retry-count=60).
Понять, что DataSpace Core смог запуститься, но ему не хватило времени, поможет лог, который появляется в папке target/local-core/logs/dataspace-core-module.log.
Ошибка SysConfigException. Конфигурация схемы БД и модуля различаются#
См. раздел «Ошибка SysConfigException. Конфигурация схемы БД и модуля различаются» документа Руководство по системному администрированию.