invalidGrpcConfigs =
+ Arrays.asList(
+ // unknown host
+ """
+ core_port: 1111
+ grpc_listen:
+ - uri: 'tcp://0.0.0.0:18182'
+
+ %s:
+ enabled: true
+ tarantool:
+ user: test-super
+ pass: test
+ connections:
+ routers:
+ - "unknown:3301"
+
+ consumer:
+ enabled: true
+ tarantool:
+ user: test-super
+ pass: test
+ connections:
+ storage:
+ - "master:3301"
+ """
+ .formatted(version.producerRoleName()),
+ // no consumers and producers
+ """
+ core_port: 1111
+ grpc_listen:
+ - uri: 'tcp://0.0.0.0:18182'
+
+ %s:
+ enabled: false
+ tarantool:
+ user: test-super
+ pass: test
+ connections:
+ routers:
+ - "router:3301"
+
+ consumer:
+ enabled: false
+ tarantool:
+ user: test-super
+ pass: test
+ connections:
+ storage:
+ - "master:3301"
+ """
+ .formatted(version.producerRoleName()),
+ // no core_port parameter
+ """
+ grpc_listen:
+ - uri: 'tcp://0.0.0.0:18182'
+
+ %s:
+ enabled: true
+ tarantool:
+ user: test-super
+ pass: test
+ connections:
+ routers:
+ - "router:3301"
+
+ consumer:
+ enabled: true
+ tarantool:
+ user: test-super
+ pass: test
+ connections:
+ storage:
+ - "master:3301"
+ """
+ .formatted(version.producerRoleName()),
+ // no listen.uri parameter
+ """
+ core_port: 1111
+
+ %s:
+ enabled: true
+ tarantool:
+ user: test-super
+ pass: test
+ connections:
+ routers:
+ - "router:3301"
+
+ consumer:
+ enabled: true
+ tarantool:
+ user: test-super
+ pass: test
+ connections:
+ storage:
+ - "master:3301"
+ """
+ .formatted(version.producerRoleName()));
+
+ return invalidGrpcConfigs.stream()
+ .map(
+ s -> {
+ final Path testConfigPath =
+ TQETestHelper.TEST_TEMP_DIR.resolve(UUID.randomUUID() + ".yml");
+ try {
+ Files.writeString(testConfigPath, s);
+ return Arguments.of(version, testConfigPath);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ });
+ }
+
+ @ParameterizedTest
+ @MethodSource("dataForTestInvalidGrpcConfig")
+ void testInvalidGrpcConfig(TQEVersion version, Path grpcConfig) {
+ Assertions.assertThrows(
+ ContainerLaunchException.class,
+ () -> {
+ try (TQEConfigurator configurator =
+ version
+ .configuratorBuilder(version.queueConfig(), Set.of(grpcConfig))
+ .withStartupTimeout(Duration.ofSeconds(5))
+ .build();
+ TQECluster cluster = version.createCluster(configurator)) {
+ cluster.start();
+ }
+ });
+ }
+}
diff --git a/testcontainers/src/test/java/org/testcontainers/containers/integration/tqe/TQETestHelper.java b/testcontainers/src/test/java/org/testcontainers/containers/integration/tqe/TQETestHelper.java
new file mode 100644
index 00000000..88b96e5e
--- /dev/null
+++ b/testcontainers/src/test/java/org/testcontainers/containers/integration/tqe/TQETestHelper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2025 VK DIGITAL TECHNOLOGIES LIMITED LIABILITY COMPANY
+ * All Rights Reserved.
+ */
+
+package org.testcontainers.containers.integration.tqe;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import org.rnorth.ducttape.unreliables.Unreliables;
+
+final class TQETestHelper {
+
+ static final Path TEST_TEMP_DIR;
+
+ static {
+ try {
+ TEST_TEMP_DIR = Files.createTempDirectory("tqe-test-");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private TQETestHelper() {}
+
+ static Path loadConfig(String resourcePath) {
+ try {
+ return Paths.get(
+ Objects.requireNonNull(TQETestHelper.class.getClassLoader().getResource(resourcePath))
+ .toURI());
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static ManagedChannel createReadyChannel(InetSocketAddress address) {
+ return Unreliables.retryUntilSuccess(
+ 60,
+ TimeUnit.SECONDS,
+ () -> {
+ ManagedChannel ch =
+ ManagedChannelBuilder.forAddress(address.getHostName(), address.getPort())
+ .usePlaintext()
+ .maxInboundMessageSize(16 * 1024 * 1024)
+ .keepAliveTime(30, TimeUnit.SECONDS)
+ .keepAliveTimeout(5, TimeUnit.SECONDS)
+ .keepAliveWithoutCalls(true)
+ .build();
+
+ ch.getState(true);
+ Unreliables.retryUntilTrue(
+ 5,
+ TimeUnit.SECONDS,
+ () -> {
+ io.grpc.ConnectivityState state = ch.getState(false);
+ if (state == io.grpc.ConnectivityState.READY) {
+ return true;
+ }
+ ch.resetConnectBackoff();
+ Thread.sleep(100);
+ return false;
+ });
+ return ch;
+ });
+ }
+}
diff --git a/testcontainers/src/test/java/org/testcontainers/containers/integration/tqe/TQEVersion.java b/testcontainers/src/test/java/org/testcontainers/containers/integration/tqe/TQEVersion.java
new file mode 100644
index 00000000..15c22df4
--- /dev/null
+++ b/testcontainers/src/test/java/org/testcontainers/containers/integration/tqe/TQEVersion.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2025 VK DIGITAL TECHNOLOGIES LIMITED LIABILITY COMPANY
+ * All Rights Reserved.
+ */
+
+package org.testcontainers.containers.integration.tqe;
+
+import java.nio.file.Path;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import org.testcontainers.containers.tqe.GrpcContainer.GrpcRole;
+import org.testcontainers.containers.tqe.TQE2ClusterImpl;
+import org.testcontainers.containers.tqe.TQE3ClusterImpl;
+import org.testcontainers.containers.tqe.TQECluster;
+import org.testcontainers.containers.tqe.configuration.FileTQEConfigurator;
+import org.testcontainers.containers.tqe.configuration.TQEConfigurator;
+import org.testcontainers.utility.DockerImageName;
+
+/**
+ * Encapsulates all version-specific aspects of a TQE test: image, configs, gRPC role names,
+ * builder/cluster factories, and the gRPC strategy.
+ *
+ * Adding a new TQE version (e.g. TQE 4.x) is an Open/Closed-friendly change: add a new constant,
+ * override the abstract methods — no test code needs to change.
+ */
+enum TQEVersion {
+ TQE2("TQE 2.x", "publisher", GrpcRole.PUBLISHER, false, TQE2GrpcTestStrategy.INSTANCE) {
+ @Override
+ public DockerImageName imageName() {
+ return IMAGE_TQE2;
+ }
+
+ @Override
+ public Path queueConfig() {
+ return QUEUE_CONFIG_TQE2;
+ }
+
+ @Override
+ public Path grpcConfig() {
+ return GRPC_CONFIG_TQE2;
+ }
+
+ @Override
+ public FileTQEConfigurator.Builder configuratorBuilder(Path queue, Set grpc) {
+ return FileTQEConfigurator.tqe2Builder(imageName(), queue, grpc);
+ }
+
+ @Override
+ public TQECluster createCluster(TQEConfigurator configurator) {
+ return new TQE2ClusterImpl(configurator);
+ }
+ },
+
+ TQE3("TQE 3.x", "producer", GrpcRole.PRODUCER, true, TQE3GrpcTestStrategy.INSTANCE) {
+ @Override
+ public DockerImageName imageName() {
+ return IMAGE_TQE3;
+ }
+
+ @Override
+ public Path queueConfig() {
+ return QUEUE_CONFIG_TQE3;
+ }
+
+ @Override
+ public Path grpcConfig() {
+ return GRPC_CONFIG_TQE3;
+ }
+
+ @Override
+ public FileTQEConfigurator.Builder configuratorBuilder(Path queue, Set grpc) {
+ return FileTQEConfigurator.tqe3Builder(imageName(), queue, grpc);
+ }
+
+ @Override
+ public TQECluster createCluster(TQEConfigurator configurator) {
+ return new TQE3ClusterImpl(configurator);
+ }
+ };
+
+ private static final DockerImageName IMAGE_TQE2 =
+ DockerImageName.parse(
+ System.getenv().getOrDefault("TARANTOOL_REGISTRY", "")
+ + "tarantool/message-queue-ee:2.5.3");
+
+ private static final DockerImageName IMAGE_TQE3 =
+ DockerImageName.parse(
+ System.getenv().getOrDefault("TARANTOOL_REGISTRY", "")
+ + "tarantool/message-queue-ee:v3.5.0");
+
+ private static final Path QUEUE_CONFIG_TQE2 =
+ TQETestHelper.loadConfig("tqe2/simple-config/simple-queue.yml");
+ private static final Path GRPC_CONFIG_TQE2 =
+ TQETestHelper.loadConfig("tqe2/simple-config/simple-grpc.yml");
+ private static final Path QUEUE_CONFIG_TQE3 =
+ TQETestHelper.loadConfig("tqe3/simple-config/simple-queue.yml");
+ private static final Path GRPC_CONFIG_TQE3 =
+ TQETestHelper.loadConfig("tqe3/simple-config/simple-grpc.yml");
+
+ private final String displayName;
+ private final String producerRoleName;
+ private final GrpcRole producerRole;
+ private final boolean requiresConfigure;
+ private final GrpcTestStrategy strategy;
+
+ TQEVersion(
+ String displayName,
+ String producerRoleName,
+ GrpcRole producerRole,
+ boolean requiresConfigure,
+ GrpcTestStrategy strategy) {
+ this.displayName = displayName;
+ this.producerRoleName = producerRoleName;
+ this.producerRole = producerRole;
+ this.requiresConfigure = requiresConfigure;
+ this.strategy = strategy;
+ }
+
+ public String displayName() {
+ return displayName;
+ }
+
+ public String producerRoleName() {
+ return producerRoleName;
+ }
+
+ public GrpcRole producerRole() {
+ return producerRole;
+ }
+
+ /**
+ * Whether manual orchestration of {@code configurator.configure()} is required between starting
+ * the queue and the gRPC containers. TQE 2.x auto-configures inside {@code
+ * startTarantoolCluster()}; TQE 3.x defers it to {@code startGrpcEndpoints()}. Tests that drive
+ * the configurator directly (without a cluster) use this flag.
+ */
+ public boolean requiresConfigure() {
+ return requiresConfigure;
+ }
+
+ public GrpcTestStrategy strategy() {
+ return strategy;
+ }
+
+ public abstract DockerImageName imageName();
+
+ public abstract Path queueConfig();
+
+ public abstract Path grpcConfig();
+
+ public abstract FileTQEConfigurator.Builder configuratorBuilder(Path queue, Set grpc);
+
+ public abstract TQECluster createCluster(TQEConfigurator configurator);
+
+ static Stream all() {
+ return Stream.of(values());
+ }
+
+ @Override
+ public String toString() {
+ return displayName;
+ }
+}
diff --git a/testcontainers/src/test/proto/tqe2/messages/message.proto b/testcontainers/src/test/proto/tqe2/messages/message.proto
new file mode 100644
index 00000000..595f4740
--- /dev/null
+++ b/testcontainers/src/test/proto/tqe2/messages/message.proto
@@ -0,0 +1,53 @@
+syntax = "proto3";
+
+package tarantool.queue_ee;
+
+option go_package = "gitlab.vkteam.ru/tarantool/tqe/message-queue.git/v2/server/protocol";
+option java_package = "tarantool.queue_ee.v2";
+option java_outer_classname = "Message";
+
+// Пара ключ-значение
+message Pair {
+ // Ключ пары
+ string key = 1;
+
+ // Значение пары
+ string value = 2;
+}
+
+// Сообщение в очереди
+message QueueMessage {
+ // Идентификатор сообщения
+ // Заполняется автоматически при записи сообщения в очередь
+ uint64 id = 1;
+
+ // Название очереди в которую необходимо опубликовать сообщение
+ string queue = 2;
+
+ // Ключ маршрутизации сообщения (тип сообщения)
+ // необходим для фильтрации сообщений из очереди на консьюмерах
+ optional string routing_key = 3;
+
+ // Ключ шардирования
+ // необходим для распределения данных в системе
+ optional string sharding_key = 4;
+
+ // Ключ дедупликации
+ // необходим для проверки повторных сообщений,
+ // если не указан, то проверка не производится
+ optional string deduplication_key = 5;
+
+ // Произвольные данные в бинарном формате, содержит тело сообщения
+ bytes payload = 6;
+
+ // Произвольные данные в бинарном формате,
+ // содержит дополнительные для сообщения данные,
+ // необходимые для отладки и трассировки
+ map metadata = 7 [deprecated = true];
+
+ // Время вставки сообщения в очередь в наносекундах
+ int64 timestamp = 8;
+
+ // Произвольные данные в формате списка из пар ключ-значения
+ repeated Pair metadata_pairs = 9;
+}
diff --git a/testcontainers/src/test/proto/tqe2/services/consumer.proto b/testcontainers/src/test/proto/tqe2/services/consumer.proto
new file mode 100644
index 00000000..dc24e94f
--- /dev/null
+++ b/testcontainers/src/test/proto/tqe2/services/consumer.proto
@@ -0,0 +1,58 @@
+syntax = "proto3";
+
+package tarantool.queue_ee;
+
+import "messages/message.proto";
+
+option go_package = "gitlab.vkteam.ru/tarantool/tqe/message-queue.git/v2/server/protocol";
+option java_package = "tarantool.queue_ee.v2";
+option java_outer_classname = "Consumer";
+
+// Сервер подписок на сообщения брокера очередей
+service ConsumerService {
+ // Подписка на сообщения с фильтром
+ rpc Subscribe(SubscriptionRequest) returns (stream SubscriptionNotifications);
+}
+
+// Запрос на подписку
+message SubscriptionRequest {
+ // Название очереди
+ string queue = 1;
+
+ // Ключ маршрутизации сообщения (тип сообщения)
+ // необходим для фильтрации сообщений из очереди
+ // Если не указан, то подписка происходит на все типы сообщений в очереди
+ optional string routing_key = 2;
+
+ // Опциональная строка указатель на последнее полученное сообщение.
+ // Необходимо для возможности получения истории сообщений
+ // или восстановления работы консьюмера после сбоя
+ // Значение не указано - подписка с текущего момента
+ // Значение пустая строка - подписка с начала очереди
+ // Значение указано - подписка с указанного сообщения в очереди
+ optional string cursor = 3;
+
+ // Ключ шардирования
+ // необходим для распределения данных в системе
+ // Если не указан, то подписка происходит на все типы сообщений в очереди
+ optional string sharding_key = 4;
+
+ // Ключи шардирования позволяют производить фильтрацию по нескольким ключам
+ // шардирования в рамках одной подписки
+ repeated string sharding_keys = 5;
+}
+
+// Сообщение в стриме подписки
+message SubscriptionNotifications {
+ // Новые сообщения в очереди с курсорами
+ repeated SubscriptionNotification notifications = 1;
+}
+
+// Уведомление клиента о новых сообщение в очереди
+message SubscriptionNotification {
+ // Строка-указатель сообщения
+ string cursor = 1;
+
+ // Сообщение
+ QueueMessage message = 2;
+}
diff --git a/testcontainers/src/test/proto/tqe2/services/publisher.proto b/testcontainers/src/test/proto/tqe2/services/publisher.proto
new file mode 100644
index 00000000..949e50f2
--- /dev/null
+++ b/testcontainers/src/test/proto/tqe2/services/publisher.proto
@@ -0,0 +1,263 @@
+syntax = "proto3";
+
+package tarantool.queue_ee;
+
+import "messages/message.proto";
+
+option go_package = "gitlab.vkteam.ru/tarantool/tqe/message-queue.git/v2/server/protocol";
+option java_package = "tarantool.queue_ee.v2";
+option java_outer_classname = "Publisher";
+
+// Сервер публикации сообщений брокера очередей
+service PublisherService {
+ // Публикация сообщения в очередь
+ rpc Publish(PublishRequest) returns (PublishResponse);
+ // Публикация сообщений в очередь через двусторонний стрим
+ rpc PublishStream(stream PublishStreamRequest) returns (stream PublishStreamResponse);
+
+ // Публикация набора сообщений в очередь
+ rpc PublishBatch(PublishBatchRequest) returns (PublishBatchResponse);
+ // Публикация набора сообщений в очередь через двусторонний стрим
+ rpc PublishBatchStream(
+ stream PublishBatchStreamRequest
+ ) returns (
+ stream PublishBatchStreamResponse
+ );
+
+ // Публикация сообщения на указанные шарды очереди
+ rpc Broadcast(BroadcastRequest) returns (BroadcastResponse);
+}
+
+// Режим дедупликации сообщения
+enum Deduplication {
+ DEDUPLICATION_UNSPECIFIED = 0;
+ DEDUPLICATION_BASIC = 1;
+ DEDUPLICATION_EXTENDED = 2;
+ DEDUPLICATION_KEEP_FIRST = 3;
+ DEDUPLICATION_KEEP_LATEST = 4;
+}
+
+// Запрос на публикацию сообщения в очередь
+message PublishRequest {
+ // Название очереди в которой необходимо опубликовать сообщение
+ string queue = 1;
+
+ // Ключ маршрутизации сообщения (тип сообщения)
+ // необходим для фильтрации сообщений из очереди на консьюмерах
+ optional string routing_key = 2;
+
+ // Ключ шардирования
+ // необходим для распределения данных в системе
+ optional string sharding_key = 3;
+
+ // Ключ дедупликации
+ // необходим для проверки повторных сообщений,
+ // если не указан, то проверка не производится
+ optional string deduplication_key = 4;
+
+ // Произвольные данные в бинарном формате, содержит тело сообщения
+ bytes payload = 5;
+
+ // Произвольные данные в бинарном формате,
+ // содержит дополнительные для сообщения данные,
+ // необходимые для отладки и трассировки
+ map metadata = 6 [deprecated = true];
+
+ // Произвольные данные в формате списка из пар ключ-значения
+ repeated Pair metadata_pairs = 7;
+
+ // Режим дедупликации сообщения
+ Deduplication deduplication = 8;
+}
+
+// Запрос на публикация набора сообщений в очередь
+message PublishBatchRequest {
+ // Название очереди в которой необходимо опубликовать сообщения
+ string queue = 1;
+
+ // Ключ шардирования
+ // необходим для распределения данных в системе
+ optional string sharding_key = 2;
+
+ // Набор сообщений
+ repeated BatchRequestMessage messages = 3;
+
+ // Содержит дополнительные данные необходимые для отладки и трассировки
+ map metadata = 4 [deprecated = true];
+
+ // Произвольные данные в формате списка из пар ключ-значения
+ repeated Pair metadata_pairs = 5;
+
+ // Режим дедупликации сообщения
+ Deduplication deduplication = 8;
+}
+
+// Набор сообщений
+message BatchRequestMessage {
+ // Ключ маршрутизации сообщения (тип сообщения)
+ // необходим для фильтрации сообщений из очереди на консьюмерах
+ optional string routing_key = 1;
+
+ // Ключ дедупликации
+ // Необходим для проверки повторных сообщений,
+ // если не указан, то проверка не производится
+ optional string deduplication_key = 2;
+
+ // Произвольные данные в бинарном формате, содержит тело сообщения
+ bytes payload = 3;
+
+ // Произвольные данные в бинарном формате,
+ // содержит дополнительные для сообщения данные,
+ // необходимые для отладки и трассировки
+ map metadata = 4 [deprecated = true];
+
+ // Произвольные данные в формате списка из пар ключ-значения
+ repeated Pair metadata_pairs = 5;
+}
+
+// Ответ на публикацию набора сообщений
+message PublishBatchResponse {
+ // Идентификаторы сообщений
+ repeated uint64 ids = 1;
+ // Содержит дополнительные данные необходимые для отладки и трассировки
+ map metadata = 2 [deprecated = true];
+ // Флаги наличия дубликатов
+ repeated bool is_duplicates = 3;
+}
+
+// Ответ на публикацию сообщения
+message PublishResponse {
+ // Идентификатор сообщения добавленного в очередь
+ // (возможно не нужно)
+ uint64 id = 1;
+ // Содержит дополнительные данные необходимые для отладки и трассировки
+ map metadata = 2 [deprecated = true];
+ // Если true, то был дубликат сообщения
+ bool is_duplicate = 3;
+}
+
+// Зарос на публикацию сообщения через двусторонний стрим
+message PublishStreamRequest {
+ // Идентификатор запроса на публикацию сообщения
+ uint64 request_id = 1;
+
+ // Запрос на публикацию сообщения
+ PublishRequest request = 2;
+}
+
+// Ответ на публикацию сообщения через двусторонний стрим
+message PublishStreamResponse {
+ // Идентификатор запроса на публикацию сообщения
+ uint64 request_id = 1;
+
+ oneof result {
+ // Сообщение об успешной публикации
+ PublishResponse success = 2;
+ // Сообщение об ошибке публикации
+ Error error = 3;
+ }
+}
+
+// Запрос на публикацию набора сообщений через двусторонний стрим
+message PublishBatchStreamRequest {
+ // Идентификатор запроса на публикацию сообщения
+ uint64 request_id = 1;
+
+ // Запрос на публикацию набора сообщений
+ PublishBatchRequest request = 2;
+}
+
+// Ответ на публикацию набора сообщений через двусторонний стрим
+message PublishBatchStreamResponse {
+ // Идентификатор запроса на публикацию сообщения
+ uint64 request_id = 1;
+
+ oneof result {
+ // Сообщение об успешной публикации
+ PublishBatchResponse success = 2;
+ // Сообщение об ошибке публикации
+ Error error = 3;
+ }
+}
+
+// Запрос на рассылку сообщения на указанные шарды
+message BroadcastRequest {
+ // Название очереди, в которую необходимо опубликовать сообщение
+ string queue = 1;
+
+ // Ключ маршрутизации сообщения (тип сообщения)
+ // необходим для фильтрации сообщений из очереди на консьюмерах
+ optional string routing_key = 2;
+
+ // Ключ дедупликации
+ // необходим для проверки повторных сообщений,
+ // если не указан, то проверка не производится
+ optional string deduplication_key = 3;
+
+ // Произвольные данные в бинарном формате, содержит тело сообщения
+ bytes payload = 4;
+
+ // Произвольные данные в бинарном формате,
+ // содержит дополнительные для сообщения данные,
+ // необходимые для отладки и трассировки
+ map metadata = 5 [deprecated = true];
+
+ // Список с названиями репликасетов, на которые нужно опубликовать сообщение.
+ // По умолчанию рассылка происходит на все шарды.
+ repeated string replicasets = 6;
+
+ // Максимальное время на рассылку сообщения
+ optional uint64 timeout = 7;
+
+ // Произвольные данные в формате списка из пар ключ-значения
+ repeated Pair metadata_pairs = 8;
+
+ // Режим дедупликации сообщения
+ Deduplication deduplication = 9;
+}
+
+// Сообщение об успешной публикации
+message Success {
+ // Идентификатор сообщения добавленного в очередь
+ uint64 id = 1;
+ // Флаги наличия дубликатов
+ bool is_duplicate = 2;
+}
+
+// Сообщение об ошибке публикации
+message Error {
+ // Код ошибки
+ uint32 code = 1;
+ // Сообщение об ошибке
+ string message = 2;
+}
+
+// Ответ репликасета на публикацию сообщения
+message ReplicasetResponse {
+ // Сообщение с результатами публикации сообщения
+ oneof result {
+ // Сообщение об успешной публикации
+ Success success = 1;
+
+ // Сообщение об ошибке публикации
+ Error error = 2;
+ }
+}
+
+// Ответ на рассылку сообщения
+message BroadcastResponse {
+ // Код завершения рассылки:
+ // 0 - Успешная публикация
+ // 1 - Ошибка на роутере
+ // 2 - Ошибка на репликасете
+ uint32 code = 1;
+
+ // Сообщение об ошибке
+ optional string error = 2;
+
+ // Набор ответов с шардов
+ map replicasets = 3;
+
+ // Содержит дополнительные данные необходимые для отладки и трассировки
+ map metadata = 4 [deprecated = true];
+}
diff --git a/testcontainers/src/test/proto/messages/cursor.proto b/testcontainers/src/test/proto/tqe3/messages/cursor.proto
similarity index 100%
rename from testcontainers/src/test/proto/messages/cursor.proto
rename to testcontainers/src/test/proto/tqe3/messages/cursor.proto
diff --git a/testcontainers/src/test/proto/messages/message.proto b/testcontainers/src/test/proto/tqe3/messages/message.proto
similarity index 100%
rename from testcontainers/src/test/proto/messages/message.proto
rename to testcontainers/src/test/proto/tqe3/messages/message.proto
diff --git a/testcontainers/src/test/proto/services/consumer.proto b/testcontainers/src/test/proto/tqe3/services/consumer.proto
similarity index 100%
rename from testcontainers/src/test/proto/services/consumer.proto
rename to testcontainers/src/test/proto/tqe3/services/consumer.proto
diff --git a/testcontainers/src/test/proto/services/producer.proto b/testcontainers/src/test/proto/tqe3/services/producer.proto
similarity index 100%
rename from testcontainers/src/test/proto/services/producer.proto
rename to testcontainers/src/test/proto/tqe3/services/producer.proto
diff --git a/testcontainers/src/test/resources/tqe2/simple-config/simple-grpc.yml b/testcontainers/src/test/resources/tqe2/simple-config/simple-grpc.yml
new file mode 100644
index 00000000..d8044bac
--- /dev/null
+++ b/testcontainers/src/test/resources/tqe2/simple-config/simple-grpc.yml
@@ -0,0 +1,21 @@
+core_port: 1111
+grpc_listen:
+ - uri: 'tcp://0.0.0.0:18182'
+
+publisher:
+ enabled: true
+ tarantool:
+ user: test-super
+ pass: test
+ connections:
+ routers:
+ - "router:3301"
+
+consumer:
+ enabled: true
+ tarantool:
+ user: test-super
+ pass: test
+ connections:
+ storage:
+ - "master:3301"
diff --git a/testcontainers/src/test/resources/tqe2/simple-config/simple-queue.yml b/testcontainers/src/test/resources/tqe2/simple-config/simple-queue.yml
new file mode 100644
index 00000000..63397f99
--- /dev/null
+++ b/testcontainers/src/test/resources/tqe2/simple-config/simple-queue.yml
@@ -0,0 +1,66 @@
+# Credentials
+credentials:
+ users:
+ test-super:
+ password: 'test'
+ roles: [ super ]
+ admin:
+ password: 'secret-cluster-cookie'
+ roles: [ super ]
+ replicator:
+ password: 'secret'
+ roles: [ replication ]
+ storage:
+ roles: [ sharding ]
+ password: storage
+
+# advertise configs for all nodes
+iproto:
+ advertise:
+ peer:
+ login: replicator
+ sharding:
+ login: storage
+ password: storage
+
+roles: [ roles.metrics-export ]
+# queues configs
+roles_cfg:
+ app.roles.queue:
+ queues:
+ - name: test
+ deduplication_mode: keep_latest
+ disabled_filters_by: [ sharding_key ]
+ roles.metrics-export:
+ http:
+ - listen: 8081
+ endpoints:
+ - format: prometheus
+ path: '/metrics'
+
+groups:
+ routers:
+ replicasets:
+ r-1:
+ sharding:
+ roles: [ router ]
+ roles: [ app.roles.api ]
+ instances:
+ router:
+ iproto:
+ listen:
+ - uri: router:3301
+ storages:
+ replicasets:
+ shard-1:
+ replication:
+ failover: manual
+ sharding:
+ roles: [ storage ]
+ roles: [ app.roles.queue ]
+ leader: master
+ instances:
+ master:
+ iproto:
+ listen:
+ - uri: master:3301
diff --git a/testcontainers/src/test/resources/tqe/simple-config/simple-grpc.yml b/testcontainers/src/test/resources/tqe3/simple-config/simple-grpc.yml
similarity index 84%
rename from testcontainers/src/test/resources/tqe/simple-config/simple-grpc.yml
rename to testcontainers/src/test/resources/tqe3/simple-config/simple-grpc.yml
index 2c4c609f..9353580b 100644
--- a/testcontainers/src/test/resources/tqe/simple-config/simple-grpc.yml
+++ b/testcontainers/src/test/resources/tqe3/simple-config/simple-grpc.yml
@@ -1,6 +1,6 @@
core_port: 1111
grpc_listen:
-- uri: 'tcp://0.0.0.0:18182'
+ - uri: 'tcp://0.0.0.0:18182'
producer:
enabled: true
@@ -13,7 +13,7 @@ producer:
retry_delay: 5s
connections:
routers:
- - "router:3301"
+ - "router:3301"
consumer:
enabled: true
@@ -26,4 +26,4 @@ consumer:
retry_delay: 5s
connections:
storage:
- - "master:3301"
+ - "master:3301"
diff --git a/testcontainers/src/test/resources/tqe/simple-config/simple-queue.yml b/testcontainers/src/test/resources/tqe3/simple-config/simple-queue.yml
similarity index 100%
rename from testcontainers/src/test/resources/tqe/simple-config/simple-queue.yml
rename to testcontainers/src/test/resources/tqe3/simple-config/simple-queue.yml