dotCMS / dotCMS/core

Phase Sweep MainSuite 1b fails at OS Phase 3: #37276 index tests are not phase-aware and blank the indicies pointer table

Open
#37,432 0 comments 0 reactions 1 assignee View on GitHub

@fabrizzio-dotCMS is already working on this.

Since Sep 7, 2026.

dotCMS : Upgrade OKR : Customer Support OpenSearch Team : Scout Type : Defect
Dominant language
Java
Stars
970
Forks
486
Avg merge
3d 33m
Merged PRs (30d)
170

Description

Problem Statement

The weekly Scheduled OpenSearch Phase Sweep fails in the Integration Tests - MainSuite 1b [OS Phase 3] shard. The two integration test classes added by PR #37320 (for issue #37276) are not phase-aware: they hardcode setPhase(0) and setPhase(1), which is false in a job whose environment was bootstrapped at Phase 3.

At Phase 3, pointES is gated off, so the indicies table carries no Elasticsearch pointers at all. Flipping FEATURE_FLAG_OPEN_SEARCH_PHASE mid-JVM does not retroactively provision ES indices, so the ES leg resolves null index names.

Three distinct symptoms, all deterministic across the four Failsafe retries:

Test Phase forced Failure
ContentletIndexPartialFailurePhaseTest.test_dualWritePhase_shadowFailureDoesNotReachCaller 1 NullPointerException: index must not be null (line 101)
ContentletIndexProviderSkipTest.test_shadowProviderSkip_stillCompletesTheRemoval 1 DotRuntimeException: ... the primary provider (ContentletIndexOperationsES) resolved no active index ... The removal was NOT performed. (line 119)
ContentletIndexPartialFailurePhaseTest.test_ordinaryWrites_areUnaffectedByTheEscalation ambient (3) Passes run 1, then NullPointerException: index must not be null on runs 2–4 (line 71)

The NPE stack is identical in every case:

java.lang.NullPointerException: index must not be null
  at org.elasticsearch.client.core.CountRequest.indices(CountRequest.java:92)
  at ContentFactoryIndexOperationsES.getCountRequest(ContentFactoryIndexOperationsES.java:454)
  at ContentFactoryIndexOperationsES.indexCount(ContentFactoryIndexOperationsES.java:446)
  at ESContentFactoryImpl.indexCount(ESContentFactoryImpl.java:1607)

The production code is doing exactly what #37276 changed it to do — raising instead of silently swallowing an unresolvable index. The test premise is wrong for a Phase 3 environment, not the code.

The second, worse half: a test can blank the cluster's index pointer record

ContentletIndexProviderSkipTest.test_primaryProviderPointersUnavailable_isNotReportedAsRemoved captures a backup with loadIndicies() and restores it in a finally:

final IndiciesInfo backup = APILocator.getIndiciesAPI().loadIndicies();
try {
    new DotConnect().setSQL("delete from indicies").loadResult();
    ...
} finally {
    APILocator.getIndiciesAPI().point(backup);   // backup is all-null at Phase 3
    CacheLocator.getIndiciesCache().clearCache();
}

At Phase 3 that backup is already all-null, so the restore persists nulls into the indicies table and then flushes the cache. Observed 32 ms into the first execution of the class:

07:04:46.585  Setting property: FEATURE_FLAG_OPEN_SEARCH_PHASE to 0
07:04:46.617  IndiciesAPIImpl - Indices configuration updated by user: system —
              working: null, live: null, reindex_working: null, reindex_live: null, site_search: null

From that moment the pointer record is gone for the rest of the fork. That is why test_ordinaryWrites_areUnaffectedByTheEscalation passes on run 1 and fails runs 2–4: Failsafe reruns in the same JVM, after the pollution. Surefire reports it as a flake; it is not — it is state leakage from a sibling test.

Note that IndiciesAPI.point() accepted an all-null IndiciesInfo without complaint. A single call was enough to blank the index pointer record for the whole instance.

Steps to Reproduce

Failing run: https://github.com/dotCMS/core/actions/runs/34016181947 (scheduled, main @ 439be9daafd2)

Locally:

  1. Run the MainSuite 1b integration battery under migration Phase 3:
    just test-integration-phase-all 3
    
    or scope it: ./mvnw verify -pl :dotcms-integration -Dcoreit.test.skip=false -Dit.test=ContentletIndexPartialFailurePhaseTest+ContentletIndexProviderSkipTest with DOT_FEATURE_FLAG_OPEN_SEARCH_PHASE=3.
  2. test_dualWritePhase_shadowFailureDoesNotReachCaller fails on the first run with NullPointerException: index must not be null.
  3. test_shadowProviderSkip_stillCompletesTheRemoval fails with The removal was NOT performed.
  4. After ContentletIndexProviderSkipTest runs, query the indicies table — every pointer column is null, and any subsequent ES-path indexCount in the same JVM raises the same NPE.

Regression window: last green sweep was 2026-08-30 (run 33296639562). Commits 78689432e9 (2026-08-31) and 36b77be50b (2026-09-01), both from PR #37320, introduced these classes and registered them in MainSuite1b lines 103–104. They were written against a default (Phase 0/1) environment and had never been exercised by the Phase 3 sweep before.

Acceptance Criteria

  • ContentletIndexPartialFailurePhaseTest and ContentletIndexProviderSkipTest pass — or skip cleanly — when the ambient migration phase is 3, rather than failing the shard.
  • Tests asserting ES-primary behaviour declare that requirement explicitly (a phase assumption such as assumeFalse(esSameAsOs()), matching the existing idiom in the suite) instead of assuming ES pointers exist after flipping the Config flag.
  • ContentletIndexProviderSkipTest never persists an all-null IndiciesInfo. The restore is skipped when the captured backup carries no pointers, and the test asserts that the restore actually took effect.
  • After the full MainSuite 1b run at Phase 3, the indicies table holds the same pointer values it held before the run — no test leaves the pointer record blanked.
  • test_ordinaryWrites_areUnaffectedByTheEscalation produces the same result on every Failsafe retry (no pass-then-fail flake signature caused by sibling state leakage).
  • IndiciesAPI.point() rejects — or at minimum logs a warning for — an IndiciesInfo with no pointers set, so no caller can silently blank the record.
  • The Scheduled OpenSearch Phase Sweep MainSuite 1b [OS Phase 3] shard is green.

dotCMS Version

Latest from main (commit 439be9daafd2, 2026-09-06). Reproduces in CI on the scheduled Phase Sweep workflow.

Severity

Medium - Some functionality impacted

Links

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.