Skip to content

[testcontainers] Support both TQE 2.x and TQE 3.x versions#86

Open
dkasimovskiy wants to merge 1 commit into
masterfrom
return-tqe2-testcontainers-implementation
Open

[testcontainers] Support both TQE 2.x and TQE 3.x versions#86
dkasimovskiy wants to merge 1 commit into
masterfrom
return-tqe2-testcontainers-implementation

Conversation

@dkasimovskiy

@dkasimovskiy dkasimovskiy commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

В testcontainers добавлена поддержку двух версий TQE (2.x, 3.x).

Консолидация тестов

TQEClusterIntegrationTest + TQEClusterTest (параметризованные
через enum TQEVersion) заменяют старые TQE2ClusterImplTest +
TQE3ClusterImplTest и абстрактные базовые классы.

GrpcRole.PRODUCER теперь принимает унаследованный от TQE 2.x
алиас "publisher", поэтому единый TQEClusterImpl работает
для обеих версий, а TQE2ClusterImpl / TQE3ClusterImpl удалены.
GrpcTestStrategy изолирует различия gRPC API (publish / Producer.produce,
однонаправленная / двунаправленная подписка).

TQEVersion инкапсулирует образ, конфиги, имена ролей, фабрики
builder/cluster и gRPC-стратегию для каждой версии — добавление
будущей TQE 4.x сводится к одной новой константе enum'а.

Примечания

  • Существующая интеграция tdg2 намеренно не затронута.
  • Генерация protobuf мигрирована с плагина xolstice на ascopes;
    proto-файлы перенесены в tqe2/ и tqe3/.
  • GrpcContainerImpl.validateConfigPath теперь использует
    path.toString().endsWith(".yml") (был Path.endsWith,
    сравнение компонентов пути) — проверка расширения теперь
    действительно работает.

I haven't forgotten about:

  • Tests
  • Changelog
  • Documentation
    • JavaDoc was written
  • Commit messages comply with the guideline
  • Cleanup the code for review. See checklist

Related issues:

@dkasimovskiy dkasimovskiy force-pushed the return-tqe2-testcontainers-implementation branch from 4931800 to e323bb8 Compare June 1, 2026 15:49
Comment thread testcontainers/src/test/java/org/testcontainers/containers/tdg/Utils.java Outdated
Comment thread testcontainers/src/main/java/org/testcontainers/containers/tqe/GrpcContainer.java Outdated
@dkasimovskiy dkasimovskiy force-pushed the return-tqe2-testcontainers-implementation branch 3 times, most recently from bcdb62d to 4d5c877 Compare June 4, 2026 14:04
@dkasimovskiy dkasimovskiy requested a review from bitgorbovsky June 5, 2026 14:52
@dkasimovskiy dkasimovskiy marked this pull request as ready for review June 5, 2026 14:57
Comment thread testcontainers/src/main/java/org/testcontainers/containers/tqe/GrpcContainer.java Outdated
dkasimovskiy added a commit that referenced this pull request Jun 8, 2026
- Collapse AbstractTQECluster/{TQE2ClusterImpl,TQE3ClusterImpl} into a
  single TQEClusterImpl (TQE3 startup order is safe for both versions).
- Unify GrpcRole.PRODUCER with "publisher" alias; drop PUBLISHER constant.
- Revert FileTQEConfigurator cosmetic changes: withClusterName/close
  to master variants, image field last in Builder, default cluster name
  generation back in withClusterName (with warn log).
- Rename dataForTestInvalidQueueConfig -> ...ShouldThrow to match
  the pre-existing naming convention.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
dkasimovskiy added a commit that referenced this pull request Jun 8, 2026
….build()

The build() fallback that generates a default cluster name when none was
provided via withClusterName() was inadvertently dropped while addressing
PR #86 review comment #7. Test fixtures (TQEClusterFixture, TQEClusterTest,
FileTQEConfiguratorTest.simpleConfiguration) do not call withClusterName()
explicitly, so removing the fallback made the cluster name "null" appear
in container names (e.g. "/router-null"), which then collided on
parallel/repeated runs.

Restore the defensive fallback in build() so the configurator is always
valid, while keeping the warn-logged fallback in withClusterName() for
explicit callers (per the review comment resolution).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…meterized tests

Add TQE 3.x (message-queue-ee 3.x) integration on top of the existing
TQE 2.x support in testcontainers. Refactor the resulting duplication
into a single parameterized test suite driven by a per-version enum,
versioned cluster and gRPC strategy implementations, and shared
fixtures.

- New TQE 3.x wiring: image, configs, ProducerServiceGrpc client,
  gRPC container, bidirectional subscription.
- Versioned cluster/container builders via FileTQEConfigurator.tqe3Builder
  /tqe2Builder; single TQEClusterImpl (TQE 3.x startup order is safe
  for both versions).
- GrpcRole.PRODUCER accepts "publisher" as alias (TQE 2.x naming) —
  eliminates the version-specific role constant.
- Replace TQE2ClusterImplTest + TQE3ClusterImplTest with
  TQEClusterIntegrationTest + TQEClusterTest parameterized over TQEVersion.
- Extract GrpcTestStrategy interface with TQE2/TQE3 implementations to
  isolate version-specific gRPC API differences.
- TQEVersion encapsulates image, configs, role names, builder/cluster
  factories, and gRPC strategy per version (OCP-friendly — adding a
  future TQE 4.x is a single new enum constant).
- Migrate protobuf generation from xolstice to ascopes plugin; rename
  proto/config resource directories to tqe2/tqe3.
- Fix GrpcContainerImpl.validateConfigPath: path.toString().endsWith()
  instead of Path.endsWith (path-component comparison) so the .yml
  extension check actually works as the error message claims.

Addresses PR #86 review comments.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@dkasimovskiy dkasimovskiy force-pushed the return-tqe2-testcontainers-implementation branch from 296b8c8 to 6c74965 Compare June 8, 2026 14:15
@dkasimovskiy dkasimovskiy changed the title Return tqe2 testcontainers implementation [testcontainers] Support both TQE 2.x and TQE 3.x versions Jun 8, 2026
@dkasimovskiy dkasimovskiy requested a review from bitgorbovsky June 8, 2026 14:40
this.grpcConfigs = new LinkedHashSet<>(grpcConfigs);
}

public Builder withRouterRole(String routerRole) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Судя по всему, пользователю достаточно того, что ему отдали на пользование методы tqe2builder и tqe3builder, а Builder.wthRouterRoles ему давать вообще в руки опасно - очепятается и укажет не то что нибудь.

Поэтому в аргументы метода private Builder(DockerImageName image, Path queueConfig, Collection<Path> grpcConfigs) можно расширить добавить еще и routerRoles, и его прямо на месте передавать, должно получиться так:

  public static Builder tqe2Builder(
      DockerImageName image, Path queueConfig, Collection<Path> grpcConfigs) {
    return builder(image, queueConfig, grpcConfigs, TQE2_ROUTER_ROLE);
  }

  public static Builder tqe3Builder(
      DockerImageName image, Path queueConfig, Collection<Path> grpcConfigs) {
    return builder(image, queueConfig, grpcConfigs, TQE3_ROUTER_ROLE);
  }

this.startupTimeout == null ? DEFAULT_STARTUP_TIMEOUT : this.startupTimeout;
final Duration bootstrapTimeout =
this.bootstrapTimeout == null ? DEFAULT_BOOTSTRAP_TIMEOUT : this.bootstrapTimeout;
if (this.routerRole == null) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Если сделать так, как я предлагаю, без withRouterRole, то эта проверка не нужна - при вызове tqe2builder или tqe3builder роль всегда будет указана.

return FileTQEConfigurator.tqe2Builder(imageName(), queue, grpc);
}

@Override

@bitgorbovsky bitgorbovsky Jun 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Этот метод теперь в объектах перечисления выглядит одинаково, и его можно вынести в код испытания, так как нет различий между 2 и 3 версией.

this.strategy = strategy;
}

public String displayName() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Как будто этот метод не используется

private final String displayName;
private final String producerRoleName;
private final GrpcRole producerRole;
private final boolean requiresConfigure;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Кажется, что теперь это тоже не нужно, т.к. что 2, что 3 версии сперва собирают и запускают кластер тарантула, а потом уже запускают gRPC. Теперь никакиз различий нет, я думаю, этот атрибут можно убрать.

}

@Override
public void subscribe(ManagedChannel channel, String queue, Set<User> result) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А почему именно Set, а не Queue, List или Consumer?
А если нам нужно еще порядок сообщений проверить?

}

@Override
public void subscribe(ManagedChannel channel, String queue, Set<User> result) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тот же самый вопрос про List, Queue или Consumer вместо Set.

* PublisherServiceGrpc} + unidirectional streaming. TQE 3.x uses {@code ProducerGrpc} +
* bidirectional streaming.
*/
interface GrpcTestStrategy {

@bitgorbovsky bitgorbovsky Jun 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я бы переназвал этот интерфейс просто как TQEClient, потому что это не стратегия, по большому счёту, а именно интерфейс клиента к TQE. Название запутывает

/**
* Publishes a batch of users to the given queue over the channel. Synchronous: throws on failure.
*/
void publish(ManagedChannel channel, List<User> users, String queue) throws Exception;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

По хорошему, ManagedChannel - это внутрянка клиента, её не надо выводить в интерфейс.

Нормальный интерфейс клиента к TQE (специально для тестов), должен выглядеть следующим образом:

void publish(List<User> users, String queue) throws Exception;
void subscribe(String queue, Consumer<User> resultAcceptor);

version.configuratorBuilder(version.queueConfig(), Set.of(version.grpcConfig())).build()) {
configurator.queue().values().parallelStream().forEach(Startable::start);
configurator.configure();
if (version.requiresConfigure()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Поскольку разницы в настройке и запуске TQE между версиями теперь нет, можно убрать этот код и всегда делать configure().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants