Parent Epic
#35476 — QA EPIC: OpenSearch Migration
Unblocked by
PR #35609 — Vendor-neutral SearchAPI and phase-aware router
Description
Validates Phase 2 application-level read behavior that was previously not testable because the dotCMS query layer had not been migrated. PR #35609 delivered SearchAPIImpl — a phase-aware router that delegates search() and searchRaw() to OSSearchAPIImpl in phases 2 and 3. This sub-task covers the three new Phase 2 read scenarios added to the test plan.
Test plan reference: docs/backend/OPENSEARCH_MIGRATION_TEST_PLAN.md — Scenario C, cases C-6, C-7, C-8
Test Cases
C-6 — Application-level search() reads from OS in Phase 2
| Step |
Action |
Expected Result |
| 1 |
Start dotCMS in Phase 2. Create and publish a content item. Wait for dual-write to complete. |
Item appears in both ES (Kibana) and OS (OS Dashboards). |
| 2 |
Perform a content search from the dotCMS UI or via GET /api/content/search/-query/+identifier:<id> -live false. |
Content item returned. SearchAPIImpl routes the call to OSSearchAPIImpl. |
| 3 |
Check dotCMS log for confirmation the OS path was taken. |
No ES read attempted for search(). Log shows Phase 2 OS routing active. |
C-7 — searchRaw() returns ContentSearchResponse (not ES type) in Phase 2
| Step |
Action |
Expected Result |
| 1 |
In Phase 2, call GET /api/v1/page/render/{url} for a page that uses $ESContent.raw(query) in a Velocity template. |
Page renders. Response includes content data. No ClassCastException in logs. |
| 2 |
Verify ContentSearchResponse accessors: hits(), tookMillis(), aggregations(). |
All accessors return non-null, well-formed values. hits().totalHits().value() matches OS document count. |
C-8 — OS read failure in Phase 2 falls back to ES automatically
| Step |
Action |
Expected Result |
| 1 |
Start dotCMS in Phase 2 with OS running. Confirm search works. |
Search returns results from OS. |
| 2 |
Stop OS: docker compose stop opensearch. Execute a content search in dotCMS. |
PhaseRouter ES fallback activates. Search returns correct results from ES. Log shows ERROR-level OS failure followed by successful ES fallback. |
| 3 |
Confirm no exception surfaced to the caller or UI. |
Normal search response. No 500 error. |
| 4 |
Restart OS: docker compose start opensearch. Execute another search. |
Log confirms OS read path restored. Subsequent searches return to OS. |
Setup
FEATURE_FLAG_OPEN_SEARCH_PHASE=2
OS_ENDPOINTS=http://localhost:9201
OS_AUTH_BASIC_USER=admin
OS_AUTH_BASIC_PASSWORD=admin
OS_TLS_ENABLED=false
Start dotCMS. Confirm startup log shows Migration Phase: PHASE_2_DUAL_WRITE_OS_READS.
Acceptance Criteria
Parent Epic
#35476 — QA EPIC: OpenSearch Migration
Unblocked by
PR #35609 — Vendor-neutral SearchAPI and phase-aware router
Description
Validates Phase 2 application-level read behavior that was previously not testable because the dotCMS query layer had not been migrated. PR #35609 delivered
SearchAPIImpl— a phase-aware router that delegatessearch()andsearchRaw()toOSSearchAPIImplin phases 2 and 3. This sub-task covers the three new Phase 2 read scenarios added to the test plan.Test plan reference:
docs/backend/OPENSEARCH_MIGRATION_TEST_PLAN.md— Scenario C, cases C-6, C-7, C-8Test Cases
C-6 — Application-level
search()reads from OS in Phase 2GET /api/content/search/-query/+identifier:<id> -live false.SearchAPIImplroutes the call toOSSearchAPIImpl.search(). Log shows Phase 2 OS routing active.C-7 —
searchRaw()returnsContentSearchResponse(not ES type) in Phase 2GET /api/v1/page/render/{url}for a page that uses$ESContent.raw(query)in a Velocity template.ClassCastExceptionin logs.ContentSearchResponseaccessors:hits(),tookMillis(),aggregations().hits().totalHits().value()matches OS document count.C-8 — OS read failure in Phase 2 falls back to ES automatically
docker compose stop opensearch. Execute a content search in dotCMS.docker compose start opensearch. Execute another search.Setup
Start dotCMS. Confirm startup log shows
Migration Phase: PHASE_2_DUAL_WRITE_OS_READS.Acceptance Criteria
$ESContent.raw()renders without ClassCastException; neutral DTO accessors return valid data