2929import org .elasticsearch .cluster .project .ProjectResolver ;
3030import org .elasticsearch .cluster .routing .allocation .DataTier ;
3131import org .elasticsearch .cluster .service .ClusterService ;
32+ import org .elasticsearch .cluster .service .ClusterStateTaskExecutorUtils ;
3233import org .elasticsearch .cluster .service .MasterServiceTaskQueue ;
3334import org .elasticsearch .common .compress .CompressedXContent ;
3435import org .elasticsearch .common .settings .IndexScopedSettings ;
5657import org .elasticsearch .xpack .core .downsample .DownsampleShardIndexerStatus ;
5758import org .elasticsearch .xpack .core .downsample .DownsampleShardPersistentTaskState ;
5859import org .elasticsearch .xpack .core .ilm .LifecycleSettings ;
60+ import org .hamcrest .Matchers ;
5961import org .junit .After ;
6062import org .junit .Before ;
6163import org .mockito .Answers ;
6264import org .mockito .Mock ;
6365import org .mockito .MockitoAnnotations ;
6466import org .mockito .stubbing .Answer ;
6567
66- import java .io .IOException ;
6768import java .util .List ;
6869import java .util .Map ;
6970import java .util .Set ;
@@ -173,12 +174,11 @@ public void setUp() throws Exception {
173174 doAnswer (mockBroadcastResponse ).when (indicesAdminClient ).refresh (any (), any ());
174175 doAnswer (mockBroadcastResponse ).when (indicesAdminClient ).flush (any (), any ());
175176
176- // Mocks for updating downsampling metadata
177177 doAnswer (invocation -> {
178178 var updateTask = invocation .getArgument (1 , TransportDownsampleAction .DownsampleClusterStateUpdateTask .class );
179- updateTask .listener .onResponse (randomBoolean () ? AcknowledgedResponse .TRUE : AcknowledgedResponse . FALSE );
179+ updateTask .listener .onResponse (AcknowledgedResponse .TRUE );
180180 return null ;
181- }).when (taskQueue ).submitTask (startsWith ("update -downsample-metadata " ), any (), any ());
181+ }).when (taskQueue ).submitTask (startsWith ("create -downsample-index " ), any (), any ());
182182
183183 // Mocks for mapping retrieval & merging
184184 when (indicesService .createIndexMapperServiceForValidation (any ())).thenReturn (mapperService );
@@ -219,11 +219,6 @@ public void testDownsampling() {
219219
220220 when (projectResolver .getProjectMetadata (any (ClusterState .class ))).thenReturn (projectMetadata );
221221
222- doAnswer (invocation -> {
223- var updateTask = invocation .getArgument (1 , TransportDownsampleAction .DownsampleClusterStateUpdateTask .class );
224- updateTask .listener .onResponse (AcknowledgedResponse .TRUE );
225- return null ;
226- }).when (taskQueue ).submitTask (startsWith ("create-downsample-index" ), any (), any ());
227222 Answer <Void > mockPersistentTask = invocation -> {
228223 ActionListener <PersistentTasksCustomMetadata .PersistentTask <?>> listener = invocation .getArgument (4 );
229224 PersistentTasksCustomMetadata .PersistentTask <?> task1 = mock (PersistentTasksCustomMetadata .PersistentTask .class );
@@ -243,6 +238,7 @@ public void testDownsampling() {
243238 listener .onResponse (AcknowledgedResponse .TRUE );
244239 return null ;
245240 }).when (indicesAdminClient ).updateSettings (any (), any ());
241+ assertSuccessfulUpdateDownsampleStatus (clusterState );
246242
247243 PlainActionFuture <AcknowledgedResponse > listener = new PlainActionFuture <>();
248244 action .masterOperation (
@@ -273,6 +269,7 @@ public void testDownsamplingWithShortCircuitAfterCreation() {
273269 .build ();
274270
275271 when (projectResolver .getProjectMetadata (any (ClusterState .class ))).thenReturn (projectMetadata );
272+ assertSuccessfulUpdateDownsampleStatus (clusterState );
276273
277274 PlainActionFuture <AcknowledgedResponse > listener = new PlainActionFuture <>();
278275 action .masterOperation (
@@ -291,7 +288,7 @@ public void testDownsamplingWithShortCircuitAfterCreation() {
291288 verifyIndexFinalisation ();
292289 }
293290
294- public void testDownsamplingWithShortCircuitDuringCreation () throws IOException {
291+ public void testDownsamplingWithShortCircuitDuringCreation () {
295292 var projectMetadata = ProjectMetadata .builder (projectId )
296293 .put (createSourceIndexMetadata (sourceIndex , primaryShards , replicaShards ))
297294 .build ();
@@ -315,6 +312,7 @@ public void testDownsamplingWithShortCircuitDuringCreation() throws IOException
315312 )
316313 .build ()
317314 );
315+ assertSuccessfulUpdateDownsampleStatus (clusterService .state ());
318316
319317 PlainActionFuture <AcknowledgedResponse > listener = new PlainActionFuture <>();
320318 action .masterOperation (
@@ -333,6 +331,76 @@ public void testDownsamplingWithShortCircuitDuringCreation() throws IOException
333331 verifyIndexFinalisation ();
334332 }
335333
334+ public void testDownsamplingWhenTargetIndexGetsDeleted () {
335+ var projectMetadata = ProjectMetadata .builder (projectId )
336+ .put (createSourceIndexMetadata (sourceIndex , primaryShards , replicaShards ))
337+ .build ();
338+
339+ var clusterState = ClusterState .builder (ClusterState .EMPTY_STATE )
340+ .putProjectMetadata (projectMetadata )
341+ .blocks (ClusterBlocks .builder ().addIndexBlock (projectId , sourceIndex , IndexMetadata .INDEX_WRITE_BLOCK ))
342+ .build ();
343+
344+ when (projectResolver .getProjectMetadata (any (ClusterState .class ))).thenReturn (projectMetadata );
345+
346+ Answer <Void > mockPersistentTask = invocation -> {
347+ ActionListener <PersistentTasksCustomMetadata .PersistentTask <?>> listener = invocation .getArgument (4 );
348+ PersistentTasksCustomMetadata .PersistentTask <?> task1 = mock (PersistentTasksCustomMetadata .PersistentTask .class );
349+ when (task1 .getId ()).thenReturn (randomAlphaOfLength (10 ));
350+ DownsampleShardPersistentTaskState runningTaskState = new DownsampleShardPersistentTaskState (
351+ DownsampleShardIndexerStatus .COMPLETED ,
352+ null
353+ );
354+ when (task1 .getState ()).thenReturn (runningTaskState );
355+ listener .onResponse (task1 );
356+ return null ;
357+ };
358+ doAnswer (mockPersistentTask ).when (persistentTaskService ).sendStartRequest (anyString (), anyString (), any (), any (), any ());
359+ doAnswer (mockPersistentTask ).when (persistentTaskService ).waitForPersistentTaskCondition (any (), anyString (), any (), any (), any ());
360+ doAnswer (invocation -> {
361+ var listener = invocation .getArgument (1 , TransportDownsampleAction .UpdateDownsampleIndexSettingsActionListener .class );
362+ listener .onResponse (AcknowledgedResponse .TRUE );
363+ return null ;
364+ }).when (indicesAdminClient ).updateSettings (any (), any ());
365+
366+ doAnswer (invocation -> {
367+ var updateTask = invocation .getArgument (1 , TransportDownsampleAction .DownsampleClusterStateUpdateTask .class );
368+ ClusterStateTaskExecutorUtils .executeHandlingResults (
369+ clusterState ,
370+ TransportDownsampleAction .STATE_UPDATE_TASK_EXECUTOR ,
371+ List .of (updateTask ),
372+ task1 -> {},
373+ TransportDownsampleAction .DownsampleClusterStateUpdateTask ::onFailure
374+ );
375+ return null ;
376+ }).when (taskQueue ).submitTask (startsWith ("update-downsample-metadata" ), any (), any ());
377+ IllegalStateException error = safeAwaitFailure (
378+ IllegalStateException .class ,
379+ AcknowledgedResponse .class ,
380+ listener -> action .masterOperation (
381+ task ,
382+ new DownsampleAction .Request (
383+ ESTestCase .TEST_REQUEST_TIMEOUT ,
384+ sourceIndex ,
385+ targetIndex ,
386+ TimeValue .ONE_HOUR ,
387+ new DownsampleConfig (new DateHistogramInterval ("5m" ), randomSamplingMethod ())
388+ ),
389+ clusterState ,
390+ listener
391+ )
392+ );
393+ assertThat (
394+ error .getMessage (),
395+ Matchers .startsWith ("Failed to update downsample status because [" + targetIndex + "] does not exist" )
396+ );
397+ verify (downsampleMetrics , never ()).recordOperation (anyLong (), eq (DownsampleMetrics .ActionStatus .SUCCESS ));
398+ verify (downsampleMetrics ).recordOperation (anyLong (), eq (DownsampleMetrics .ActionStatus .FAILED ));
399+ verify (indicesAdminClient ).refresh (any (), any ());
400+ verify (indicesAdminClient , never ()).flush (any (), any ());
401+ verify (indicesAdminClient , never ()).forceMerge (any (), any ());
402+ }
403+
336404 private void verifyIndexFinalisation () {
337405 verify (downsampleMetrics ).recordOperation (anyLong (), eq (DownsampleMetrics .ActionStatus .SUCCESS ));
338406 verify (indicesAdminClient ).refresh (any (), any ());
@@ -476,4 +544,21 @@ public void testGetSupportedMetrics() {
476544 assertThat (supported .defaultMetric (), is ("max" ));
477545 assertThat (supported .supportedMetrics (), is (List .of (metricType .supportedAggs ())));
478546 }
547+
548+ private void assertSuccessfulUpdateDownsampleStatus (ClusterState clusterState ) {
549+ var projectMetadata = ProjectMetadata .builder (clusterState .metadata ().getProject (projectId ))
550+ .put (createSourceIndexMetadata (targetIndex , primaryShards , replicaShards ))
551+ .build ();
552+
553+ var updatedClusterState = ClusterState .builder (clusterState ).putProjectMetadata (projectMetadata ).build ();
554+ doAnswer (invocation -> {
555+ var updateTask = invocation .getArgument (1 , TransportDownsampleAction .DownsampleClusterStateUpdateTask .class );
556+ ClusterStateTaskExecutorUtils .executeAndAssertSuccessful (
557+ updatedClusterState ,
558+ TransportDownsampleAction .STATE_UPDATE_TASK_EXECUTOR ,
559+ List .of (updateTask )
560+ );
561+ return null ;
562+ }).when (taskQueue ).submitTask (startsWith ("update-downsample-metadata" ), any (), any ());
563+ }
479564}
0 commit comments