1818import org .elasticsearch .cluster .node .DiscoveryNodes ;
1919import org .elasticsearch .cluster .routing .IndexRoutingTable ;
2020import org .elasticsearch .cluster .routing .RoutingTable ;
21+ import org .elasticsearch .cluster .routing .ShardRouting ;
2122import org .elasticsearch .common .Strings ;
2223import org .elasticsearch .common .UUIDs ;
24+ import org .elasticsearch .common .settings .Settings ;
2325import org .elasticsearch .core .Tuple ;
2426import org .elasticsearch .index .Index ;
2527import org .elasticsearch .index .shard .ShardId ;
3537import java .util .Set ;
3638import java .util .concurrent .Executor ;
3739
40+ import static org .elasticsearch .cluster .node .DiscoveryNode .STATELESS_ENABLED_SETTING_NAME ;
3841import static org .elasticsearch .cluster .routing .ShardRoutingState .STARTED ;
3942import static org .elasticsearch .cluster .routing .TestShardRouting .shardRoutingBuilder ;
4043import static org .hamcrest .Matchers .equalTo ;
44+ import static org .hamcrest .Matchers .nullValue ;
4145import static org .mockito .Mockito .mock ;
4246
4347public class DownsampleShardPersistentTaskExecutorTests extends ESTestCase {
@@ -57,7 +61,12 @@ public void setup() {
5761 "metrics-app1" ,
5862 List .of (new Tuple <>(start , end ))
5963 );
60- executor = new DownsampleShardPersistentTaskExecutor (mock (Client .class ), DownsampleShardTask .TASK_NAME , mock (Executor .class ));
64+ executor = new DownsampleShardPersistentTaskExecutor (
65+ mock (Client .class ),
66+ DownsampleShardTask .TASK_NAME ,
67+ Settings .EMPTY ,
68+ mock (Executor .class )
69+ );
6170 }
6271
6372 public void testGetAssignment () {
@@ -124,7 +133,69 @@ public void testGetAssignmentMissingIndex() {
124133 assertThat (result .getExplanation (), equalTo ("a node to fail and stop this persistent task" ));
125134 }
126135
136+ public void testGetStatelessAssignment () {
137+ executor = new DownsampleShardPersistentTaskExecutor (
138+ mock (Client .class ),
139+ DownsampleShardTask .TASK_NAME ,
140+ Settings .builder ().put (STATELESS_ENABLED_SETTING_NAME , "true" ).build (),
141+ mock (Executor .class )
142+ );
143+ var backingIndex = initialClusterState .metadata ().getProject (projectId ).dataStreams ().get ("metrics-app1" ).getWriteIndex ();
144+ var searchNode = newNode (Set .of (DiscoveryNodeRole .SEARCH_ROLE ));
145+ var indexNode = newNode (Set .of (DiscoveryNodeRole .INDEX_ROLE ));
146+ var shardId = new ShardId (backingIndex , 0 );
147+ var clusterState = ClusterState .builder (initialClusterState )
148+ .nodes (new DiscoveryNodes .Builder ().add (indexNode ).add (searchNode ).build ())
149+ .putRoutingTable (
150+ projectId ,
151+ RoutingTable .builder ()
152+ .add (
153+ IndexRoutingTable .builder (backingIndex )
154+ .addShard (shardRoutingBuilder (shardId , indexNode .getId (), true , STARTED ).withRecoverySource (null ).build ())
155+ )
156+ .build ()
157+ )
158+ .build ();
159+
160+ var params = new DownsampleShardTaskParams (
161+ new DownsampleConfig (new DateHistogramInterval ("1h" )),
162+ shardId .getIndexName (),
163+ 1 ,
164+ 1 ,
165+ shardId ,
166+ Strings .EMPTY_ARRAY ,
167+ Strings .EMPTY_ARRAY ,
168+ Strings .EMPTY_ARRAY
169+ );
170+ var result = executor .getAssignment (params , Set .of (indexNode , searchNode ), clusterState );
171+ assertThat (result .getExecutorNode (), nullValue ());
172+
173+ // Assign a copy of the shard to a search node
174+ clusterState = ClusterState .builder (clusterState )
175+ .putRoutingTable (
176+ projectId ,
177+ RoutingTable .builder ()
178+ .add (
179+ IndexRoutingTable .builder (backingIndex )
180+ .addShard (shardRoutingBuilder (shardId , indexNode .getId (), true , STARTED ).withRecoverySource (null ).build ())
181+ .addShard (
182+ shardRoutingBuilder (shardId , searchNode .getId (), false , STARTED ).withRecoverySource (null )
183+ .withRole (ShardRouting .Role .SEARCH_ONLY )
184+ .build ()
185+ )
186+ )
187+ .build ()
188+ )
189+ .build ();
190+ result = executor .getAssignment (params , Set .of (indexNode , searchNode ), clusterState );
191+ assertThat (result .getExecutorNode (), equalTo (searchNode .getId ()));
192+ }
193+
127194 private static DiscoveryNode newNode () {
195+ return newNode (DiscoveryNodeRole .roles ());
196+ }
197+
198+ private static DiscoveryNode newNode (Set <DiscoveryNodeRole > nodes ) {
128199 return DiscoveryNodeUtils .create (
129200 "node_" + UUIDs .randomBase64UUID (random ()),
130201 buildNewFakeTransportAddress (),
0 commit comments