apache / apache/seatunnel

[Improve][E2E] Make SeaTunnelContainer reusable across test classes to speed up E2E tests

Open
#10,784 8 comments 0 reactions 0 assignees View on GitHub
help wanted improve Test
Dominant language
Java
Stars
9.7k
Forks
2.4k
Avg merge
3d 13h
Merged PRs (30d)
203

Description

### Search before asking

- [x] I had searched in the [issues](https://github.com/apache/seatunnel/issues) and found no similar feature requirement.

## Background

E2E tests in SeaTunnel are slow. A significant portion of the overhead comes from the fact that **each test class creates and destroys its own `SeaTunnelContainer`** via `ContainerTestingExtension.beforeAll/afterAll`.

The full startup sequence runs for every single test class:

```
ContainerTestingExtension.beforeAll()
→ SeaTunnelContainer.startUp()
→ new GenericContainer(...).start() // Docker cold start: 30–60s
→ waitForLogMessage("received new worker register") // Hazelcast cluster ready
→ copyAllConnectorJarToContainer(...) // copy connector JARs into container
```

On teardown:
```
ContainerTestingExtension.afterAll()
→ SeaTunnelContainer.tearDown()
→ server.close() // container destroyed
```

This means a test suite with 20 test classes pays the 30–60s Docker startup cost **20 times**.

## Proposed Solution

Introduce a **singleton/reusable `SeaTunnelContainer`** that is started once per JVM and shared across all test classes, similar to the [Testcontainers Singleton Pattern](https://java.testcontainers.org/test_framework_integration/manual_lifecycle_control/#singleton-containers).

Key changes required:

### 1. Singleton container lifecycle

Move `SeaTunnelContainer` to a static singleton with a JVM shutdown hook instead of per-class `beforeAll/afterAll`:

```java
class SharedSeaTunnelContainer {
static final SeaTunnelContainer INSTANCE;
static {
INSTANCE = new SeaTunnelContainer();
INSTANCE.startUp();
Runtime.getRuntime().addShutdownHook(new Thread(() -> INSTANCE.tearDown()));
}
}
```

### 2. Connector JAR pre-loading

Currently each test class copies only the connector JARs it needs. With a shared container, all required connectors must be copied **once at startup** (or support hot-copy to the container's connectors directory without restart, since Zeta supports dynamic connector loading).

### 3. Cleanup between test classes

`tearDown` currently deletes the volume and destroys the container. For a shared container, cleanup should only remove per-job artifacts (e.g., volume files written by a specific job), not destroy the container itself.

### 4. Adapt `ContainerTestingExtension`

Change the extension to inject the shared container instance instead of creating a new one in `beforeAll`.

## Key Files

| File | Change needed |
|------|--------------|
| [`SeaTunnelContainer.java`](https://github.com/apache/seatunnel/blob/dev/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/container/seatunnel/SeaTunnelContainer.java) | Add singleton pattern, fix `tearDown` to not destroy container |
| [`ContainerTestingExtension.java`](https://github.com/apache/seatunnel/blob/dev/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/junit/ContainerTestingExtension.java) | Inject shared container instead of creating per-class |
| [`TestSuiteBase.java`](https://github.com/apache/seatunnel/blob/dev/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/TestSuiteBase.java) | No change expected |

## Expected Impact

- **Before**: N test classes × ~45s Docker startup = N × 45s overhead
- **After**: 1 startup × ~45s + N × ~0s (container already running)
- For a module with 20 test classes: **~15 minutes saved** per CI run

## Non-goals

- This issue does not cover Embedded Zeta or in-process execution
- Streaming/checkpoint E2E tests are still expected to run against the shared container (no scope reduction)
- This does not affect connector-specific external system containers (MySQL, Kafka, etc.), which remain per-class

## Acceptance Criteria

- [ ] `SeaTunnelContainer` can be started once and reused across multiple test classes
- [ ] Connector JARs are loaded at container startup (not per test class)
- [ ] Per-job artifacts are cleaned up between test classes without container restart
- [ ] Existing E2E tests pass without modification to individual test classes
- [ ] CI wall-clock time for at least one E2E module is measurably reduced

### Are you willing to submit a PR?

- [ ] Yes I am willing to submit a PR!

### Code of Conduct

- [x] I agree to follow this project's [Code of Conduct](https://www.apache.org/foundation/policies/conduct)

Contributor guide

No contributing guide indexed for this repository

Research direction

Read SeaTunnelContainer.java and ContainerTestingExtension.java to trace the current per-class startup, connector copying, cleanup, and teardown lifecycle. Run an E2E module to establish its current behavior and timing. Done means the container and connector JARs are reused across test classes, per-job artifacts are cleaned without restart, existing E2E tests pass, and CI time is measurably reduced.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, java
Domain
devops, performance, testing
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.