Phase 1 of EPIC #3731: Java-driven E2E scenarios for reindex + UI tests. Reuses TestSuiteBootstrap as a test-jar dependency. Three execution modes: - embedded (in-JVM, fast, backend-only) - containerized (Testcontainers + prod server image, UI capable) - external (connect to a running stack) Includes 3 backend reindex scenarios (full / incremental / orphan cleanup), 1 Playwright UI scenario (search-after-reindex in Explore), and 2 CI workflows (PR path-filter + nightly cron). Satisfies #3767 and #3792. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.9 KiB
openmetadata-java-playwright
Java-driven end-to-end scenario suite for OpenMetadata. Boots a real server, seeds data via the SDK, and validates backend behaviour — reindex, search, ingestion, governance — with optional Playwright-Java browser checks.
Tracks EPIC #3731. Satisfies open tickets #3767 (e2e suite for SearchIndexingApplication) and #3792 (Playwright nightly suite for search scenarios).
Why a separate module?
| Existing | Gap this module fills |
|---|---|
openmetadata-integration-tests |
API CRUD, isolated entity tests. Can't easily express "seed → trigger reindex → assert engine state → verify in UI" scenarios. |
openmetadata-ui Playwright (TS) |
Frontend perspective, written by UI engineers. Misses backend edge cases that are obvious to backend engineers (orchestrator failure paths, alias swaps, distributed coordination). |
This module is the backend engineer's scenario suite. Same Testcontainers + SDK harness as openmetadata-integration-tests (via test-jar dependency), plus Playwright-Java for the cases that need a browser.
Modes
The module ships with two execution modes, selected by the JPW_MODE environment variable. Backend reindex scenarios use embedded mode (fast, hermetic). UI scenarios use external mode (real UI bundle served).
Embedded (default — backend scenarios)
TestSuiteBootstrap (reused from openmetadata-integration-tests) starts MySQL/PostgreSQL + Elasticsearch/OpenSearch via Testcontainers and boots OpenMetadataApplication in-JVM via DropwizardAppExtension. Tests connect via SDK using JWT-cached SdkClients.adminClient().
- Boot time: ~30–60s
- Debuggable: set a breakpoint in
SearchIndexAppand the IDE debugger will hit it - Limitation: no UI bundle is served — UI scenarios skip via
@DisabledIfEnvironmentVariable(named = "JPW_MODE", matches = "external")running in reverse
External (UI + future distributed/crash scenarios)
Tests connect to an already-running stack. Phase 1 supports this for UI scenarios; later phases will add distributed reindex, crash recovery, and ingestion E2E here.
When JPW_MODE=external is set:
- The embedded
TestSuiteBootstrapskips its boot (no Testcontainers spin-up) - Embedded scenarios are skipped via
@DisabledIfEnvironmentVariable - UI scenarios are enabled via
@EnabledIfEnvironmentVariable ExternalServer.fromEnv()readsOM_URL+OM_ADMIN_TOKENand builds the SDK client
Layout
openmetadata-java-playwright/
src/main/java/org/openmetadata/jpw/
server/ServerHandle.java connection details (URL, SDK client, search engine endpoint)
search/ReindexHelpers.java trigger SearchIndexingApplication + Awaitility wait
search/SearchClient.java stdlib HTTP client to the search engine
search/SearchAssertions.java doc count, alias→index, presence/absence assertions
ui/PlaywrightFixture.java browser session lifecycle + traces
src/test/java/org/openmetadata/jpw/
util/OssTestServer.java builds a ServerHandle from TestSuiteBootstrap
scenarios/search/reindex/ Phase 1 scenarios
The harness lives in src/main/java so the Collate module (collate-java-playwright) can depend on it directly.
Running locally
One-time setup
# Build everything the module needs
mvn -DskipTests clean install -pl :openmetadata-java-playwright -am
# Install Playwright browsers (one-time per machine; UI scenarios need it, backend ones don't)
mvn -pl :openmetadata-java-playwright dependency:build-classpath -Dmdep.outputFile=/tmp/cp.txt -q
java -cp "$(cat /tmp/cp.txt)" com.microsoft.playwright.CLI install chromium
Backend scenarios (embedded mode)
# All backend scenarios, OpenSearch (default)
mvn verify -pl :openmetadata-java-playwright
# Elasticsearch instead
mvn verify -pl :openmetadata-java-playwright \
-DsearchType=elasticsearch \
-DsearchImage=docker.elastic.co/elasticsearch/elasticsearch:9.3.0
# Single scenario
mvn verify -pl :openmetadata-java-playwright -Dit.test=FullReindexFromCleanStateIT
UI scenarios
UI scenarios are transparent — mvn verify -Dit.test='*UIIT' just works. UiTestServer auto-picks the right backing stack:
| If you set... | UI tests run against |
|---|---|
| Nothing (default) | A freshly-built containerized stack (MySQL + OpenSearch + the OM server image built from your local openmetadata-dist tarball). First run ~5 min for the dist build, ~2 min for image build + container boot. Subsequent runs reuse Docker layer cache. |
OM_URL + OM_ADMIN_TOKEN |
Whatever stack those vars point at (e.g. a ./docker/run_local_docker.sh you already have running). |
OM_TEST_IMAGE=openmetadata/server:1.11.4 |
A containerized stack using that pre-built image instead of building one from local code. Useful for testing against released versions. |
# 1) Just run it. First time will build the dist tarball (~5 min) and the image.
mvn verify -pl :openmetadata-java-playwright -Dit.test='*UIIT'
That's it. The test seeds a table via the SDK, triggers SearchIndexingApplication, opens Chromium, navigates to Explore, types the table name, presses Enter, asserts the table appears.
Iterating against a stack you already have running
If you already have ./docker/run_local_docker.sh -m ui -d mysql going, point the test at it and skip the rebuild:
export OM_URL=http://localhost:8585
export OM_ADMIN_TOKEN='<JWT from UI: Settings → Bots → ingestion-bot → Token>'
mvn verify -pl :openmetadata-java-playwright -Dit.test='*UIIT'
UiTestServer detects the env vars and uses them automatically.
Watching the browser
Edit PlaywrightFixture.java line 51, change setHeadless(true) → setHeadless(false).setSlowMo(300). Re-run; Chromium pops up.
Skipping the wasted embedded boot when only running UI tests
By default, when you run mvn verify, the TestSuiteBootstrap LauncherSessionListener fires and boots an embedded MySQL+OpenSearch even if you filter to UI tests. Suppress it with:
mvn verify -pl :openmetadata-java-playwright -Dit.test='*UIIT' -Dskip.embedded.bootstrap=true
Adding a scenario
- Pick (or create) a sub-package under
src/test/java/org/openmetadata/jpw/scenarios/. - Name the class
<Behaviour>IT.javaso failsafe picks it up. - Use
@Execution(SAME_THREAD)if your scenario triggers the SearchIndexingApplication (it's a shared resource). - Build a
ServerHandleonce in@BeforeAllviaOssTestServer.defaultHandle(). - Seed via
*TestFactoryclasses fromopenmetadata-integration-tests(already on the classpath). - Drive search via
ReindexHelpers, assert viaSearchAssertions. - Reference the EPIC sub-issue(s) the scenario protects against in the class Javadoc.
CI
| Workflow | Trigger | What it runs |
|---|---|---|
java-playwright-pr.yml |
Path-filtered PR + run-java-playwright label + dispatch |
Embedded mode, OpenSearch only, fast subset |
java-playwright-nightly.yml |
Cron 0 2 * * * + dispatch |
Embedded mode, ES + OS matrix; expands in Phase 3 to external mode |
Path filter triggers on changes to openmetadata-service/src/.../searchIndex/**, .../search/**, the spec, the SDK search service, the integration-tests bootstrap, and this module itself.
Phasing
- Phase 1 (this PR): skeleton, harness, 3 reindex scenarios, embedded mode, CI wiring.
- Phase 2: scenarios for buckets D (stats), E (ES/OS parity), F (query correctness), G (lifecycle), I (column embeddings), J (permissions). UI scenarios (search after reindex appears in Explore).
- Phase 3: external mode (
docker-compose-e2e.yml+ExternalServer), distributed reindex (#25058, #3750, #3757), crash recovery, perf smoke (#3961). - Phase 4+: ingestion E2E, governance, lineage.