Локальный запуск 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, значение которого определяет порт входящих подключений.

Пример настройки:

  1. В файле local-run.sh добавляется настройка параметра --dataspace-core.h2.tcp-port=9090, где 9090 — номер порта входящих подключений.

  2. После старта модуля для профиля 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. Конфигурация схемы БД и модуля различаются» документа Руководство по системному администрированию.