@@ -246,7 +246,19 @@ protected String forecast(String jobId, TimeValue duration, TimeValue expiresIn,
246246
247247 protected void waitForecastToFinish (String jobId , String forecastId ) throws Exception {
248248 // Forecasts can take an eternity to complete in the FIPS JVM
249- waitForecastStatus (inFipsJvm () ? 300 : 90 , jobId , forecastId , ForecastRequestStats .ForecastRequestStatus .FINISHED );
249+ int timeoutSeconds = inFipsJvm () ? 300 : 90 ;
250+ // First wait for the forecast document to exist and be in a non-terminal state
251+ // This handles the race condition where the document may be SCHEDULED or STARTED initially
252+ waitForecastStatus (
253+ timeoutSeconds ,
254+ jobId ,
255+ forecastId ,
256+ ForecastRequestStats .ForecastRequestStatus .SCHEDULED ,
257+ ForecastRequestStats .ForecastRequestStatus .STARTED ,
258+ ForecastRequestStats .ForecastRequestStatus .FINISHED
259+ );
260+ // Then wait specifically for FINISHED status
261+ waitForecastStatus (timeoutSeconds , jobId , forecastId , ForecastRequestStats .ForecastRequestStatus .FINISHED );
250262 }
251263
252264 protected void waitForecastStatus (String jobId , String forecastId , ForecastRequestStats .ForecastRequestStatus ... status )
@@ -261,6 +273,10 @@ protected void waitForecastStatus(
261273 ForecastRequestStats .ForecastRequestStatus ... status
262274 ) throws Exception {
263275 assertBusy (() -> {
276+ // Refresh the index to ensure recently indexed forecast stats documents are visible
277+ indicesAdmin ().prepareRefresh (AnomalyDetectorsIndex .jobResultsAliasedName (jobId ))
278+ .setIndicesOptions (IndicesOptions .LENIENT_EXPAND_OPEN_HIDDEN )
279+ .get ();
264280 ForecastRequestStats forecastRequestStats = getForecastStats (jobId , forecastId );
265281 assertThat (forecastRequestStats , is (notNullValue ()));
266282 assertThat (forecastRequestStats .getStatus (), in (status ));
0 commit comments