test(opensearch): phase-aware test bootstrap to run the indexing flow under a migration phase (#36266)#36268
Conversation
…36266) Add per-checkin migration-phase control to ContentletDataGen so tests can direct a generated contentlet to ElasticSearch, OpenSearch, or both during the ES->OS migration: - migrationPhase(MigrationPhase): phase-oriented primary API - targetStore(ES|OS|BOTH): store-oriented convenience over the phase override - per-checkin scope: wraps the checkin in persist(), captures and restores the prior FEATURE_FLAG_OPEN_SEARCH_PHASE value (restored even on throw) - backward compatible: no override -> respects the globally-active phase - applied to both persist(...) overloads and nextPersistedAndPublish() Add ContentletDataGenPhaseControlIT (registered in OpenSearchUpgradeSuite), which asserts placement by document _id directly on each provider's working index. ES content-write scenarios skip in the single-cluster opensearch-upgrade profile (the legacy ES client cannot content-bulk-write to OS 3.x); the OS-only placement and per-checkin restore tests run everywhere. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Claude finished @fabrizzio-dotCMS's task in 1m 10s —— View job Rollback Safety Analysis
Result: ✅ Safe to RollbackThis PR is test-only — all 5 changed files live under Files changed:
Category-by-category verdict:
Rolling back to the previous release after merging this PR is fully safe — N-1 never sees these test classes or the Maven profile at runtime. Label applied: AI: Safe To Rollback |
🤖 Bedrock Review —
|
🤖 Bedrock Review —
|
…er a migration phase (#36266) Replace the per-checkin ContentletDataGen instrumentation with a separate, phase-aware bootstrap helper wired into the test init, so the whole indexing flow (not just contentlets) runs under a chosen ES->OS migration phase. - MigrationPhaseStoreBootstrap: ensureStoresForCurrentPhase() validates OS reachability (fails hard in phases 1/2/3, stricter than production on purpose) and creates/registers the index set; assertOpenSearchReachable() exposed for the create/publish path. - IntegrationTestInitService.init(): phase-gated bootstrap; phase 0 is a no-op so existing single-store runs are unchanged. - Revert ContentletDataGen to its pre-PR baseline (no targetStore/migrationPhase). - Replace ContentletDataGenPhaseControlIT with MigrationPhaseStoreBootstrapIT, asserting store placement via the ordinary data-gen under the active phase. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🤖 Bedrock Review —
|
…uite battery under a migration phase (#36266) Adds a Maven profile that runs the regular MainSuite/Junit5Suite battery against a single OpenSearch 3.x cluster under a chosen ES->OS migration phase, so the impact of a phase on the existing test flow is measurable and repeatable (instead of an ad-hoc exported env var). ./mvnw verify -pl :dotcms-integration -Dcoreit.test.skip=false \ -Dopensearch.phase.test=true -Dopensearch.phase=3 Injects DOT_FEATURE_FLAG_OPEN_SEARCH_PHASE into the failsafe fork (read by Config -> MigrationPhase.current()); IntegrationTestInitService.init() bootstraps the OS index set for that phase. Single cluster => phase 3 is the meaningful one (phases 1/2 need two separate ES and OS clusters). Includes inherit the base MainSuite config. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🤖 Bedrock Review —
|
Proposed Changes
Closes #36266.
Integration tests don't go through the production startup path
(
InitServlet.init() → ContentletIndexAPI.checkAndInitializeIndex() → IndexStartupValidator), soan OpenSearch index set is never created — and an unreachable OS service is never detected — unless
a test bootstraps it explicitly. This blocked running the existing test flow under an ES→OS
migration phase and having content (and everything else that gets indexed, not just contentlets)
land in OpenSearch the way it lands in ElasticSearch.
This PR adds a small, separate phase-aware bootstrap helper and wires it into the test init, so
the whole indexing flow can run under a chosen migration phase with no per-data-gen
instrumentation. The migration phase is already global config that the phase router reads on every
index operation — setting it and bootstrapping the stores is all that's needed.
MigrationPhaseStoreBootstrap(new test util)ensureStoresForCurrentPhase()— for phases that involve OpenSearch (1/2/3), validates OSreachability and fails hard with a clear message if the cluster is unreachable, then
creates/registers the index set (
checkAndInitializeIndex()+ cache clear). Phase 0 = ES only,OS untouched.
assertOpenSearchReachable(phase)— standalone fail-fast reachability check.client.info()rather than the fullIndexStartupValidator.validate()on purpose: the latter also asserts endpoint separation, which fails by design in the
single-cluster
opensearch-upgradeprofile.haltMigration()→ES fallback), but a migration test that silently degraded to ES would mask the very problem it
exists to catch.
IntegrationTestInitService.init()FEATURE_FLAG_OPEN_SEARCH_PHASEselects a phase ≥ 1,init()callsensureStoresForCurrentPhase(). Phase 0 (the default) is a no-op, so existing single-storeruns are unchanged.
ContentletDataGen— revertedmigrationPhase()/targetStore()instrumentation was removed.Phase control belongs upstream (global config + init), not bolted onto a single data-gen, so it
now covers the full indexing flow rather than just contentlets created by one generator.
MigrationPhaseStoreBootstrapIT(new IT, registered inOpenSearchUpgradeSuite)Bootstraps both stores in setup (phase 1 +
ensureStoresForCurrentPhase()) and asserts placement byquerying the document
_id(identifier_languageId_variantId) directly on each provider's workingindex — noise-free, sidesteps the
inferIndexToHitbootstrap gap. Content is created through theordinary
ContentletDataGen(no override); the phase router does the routing.phase3_indexesIntoOpenSearchOnlyphase1_dualWriteIndexesIntoBothStoresHow to test
To run the existing MainSuite battery under a phase (single-cluster ⇒ only phase 3 is
meaningful), use the new
opensearch-phase-suiteMaven profile:Notes / known limitation
The phase-1 dual-write test skips itself in the single-cluster
opensearch-upgradeprofile viaassumeFalse(esSameAsOs()): the legacy ESRestHighLevelClientcannot parse an OpenSearch 3.xcontent bulk-write response (
NullPointerExceptioninDocWriteResponse), so ES content writes onlywork against a truly separate ES cluster. The phase-3 OpenSearch-only path is unaffected.
🤖 Generated with Claude Code