1515import org .opensearch .action .admin .cluster .remotestore .stats .RemoteStoreStatsResponse ;
1616import org .opensearch .action .support .PlainActionFuture ;
1717import org .opensearch .cluster .ClusterState ;
18+ import org .opensearch .cluster .coordination .FollowersChecker ;
19+ import org .opensearch .cluster .coordination .LeaderChecker ;
1820import org .opensearch .cluster .node .DiscoveryNode ;
1921import org .opensearch .cluster .routing .ShardRouting ;
2022import org .opensearch .cluster .routing .ShardRoutingState ;
2325import org .opensearch .index .IndexSettings ;
2426import org .opensearch .index .remote .RemoteSegmentTransferTracker ;
2527import org .opensearch .index .remote .RemoteTranslogTransferTracker ;
28+ import org .opensearch .plugins .Plugin ;
2629import org .opensearch .test .InternalTestCluster ;
2730import org .opensearch .test .OpenSearchIntegTestCase ;
28- import org .junit .Before ;
31+ import org .opensearch .test .disruption .NetworkDisruption ;
32+ import org .opensearch .test .transport .MockTransportService ;
2933
3034import java .io .IOException ;
3135import java .util .ArrayList ;
3236import java .util .Arrays ;
37+ import java .util .Collection ;
38+ import java .util .HashSet ;
3339import java .util .List ;
3440import java .util .Locale ;
41+ import java .util .Set ;
3542import java .util .concurrent .TimeUnit ;
3643import java .util .stream .Collectors ;
3744import java .util .stream .Stream ;
@@ -45,12 +52,17 @@ public class RemoteStoreStatsIT extends RemoteStoreBaseIntegTestCase {
4552
4653 private static final String INDEX_NAME = "remote-store-test-idx-1" ;
4754
48- @ Before
55+ @ Override
56+ protected Collection <Class <? extends Plugin >> nodePlugins () {
57+ return Arrays .asList (MockTransportService .TestPlugin .class );
58+ }
59+
4960 public void setup () {
5061 internalCluster ().startNodes (3 );
5162 }
5263
5364 public void testStatsResponseFromAllNodes () {
65+ setup ();
5466
5567 // Step 1 - We create cluster, create an index, and then index documents into. We also do multiple refreshes/flushes
5668 // during this time frame. This ensures that the segment upload has started.
@@ -121,6 +133,7 @@ public void testStatsResponseFromAllNodes() {
121133 }
122134
123135 public void testStatsResponseAllShards () {
136+ setup ();
124137
125138 // Step 1 - We create cluster, create an index, and then index documents into. We also do multiple refreshes/flushes
126139 // during this time frame. This ensures that the segment upload has started.
@@ -181,6 +194,7 @@ public void testStatsResponseAllShards() {
181194 }
182195
183196 public void testStatsResponseFromLocalNode () {
197+ setup ();
184198
185199 // Step 1 - We create cluster, create an index, and then index documents into. We also do multiple refreshes/flushes
186200 // during this time frame. This ensures that the segment upload has started.
@@ -244,6 +258,7 @@ public void testStatsResponseFromLocalNode() {
244258 }
245259
246260 public void testDownloadStatsCorrectnessSinglePrimarySingleReplica () throws Exception {
261+ setup ();
247262 // Scenario:
248263 // - Create index with single primary and single replica shard
249264 // - Disable Refresh Interval for the index
@@ -333,6 +348,7 @@ public void testDownloadStatsCorrectnessSinglePrimarySingleReplica() throws Exce
333348 }
334349
335350 public void testDownloadStatsCorrectnessSinglePrimaryMultipleReplicaShards () throws Exception {
351+ setup ();
336352 // Scenario:
337353 // - Create index with single primary and N-1 replica shards (N = no of data nodes)
338354 // - Disable Refresh Interval for the index
@@ -424,6 +440,7 @@ public void testDownloadStatsCorrectnessSinglePrimaryMultipleReplicaShards() thr
424440 }
425441
426442 public void testStatsOnShardRelocation () {
443+ setup ();
427444 // Scenario:
428445 // - Create index with single primary and single replica shard
429446 // - Index documents
@@ -479,6 +496,7 @@ public void testStatsOnShardRelocation() {
479496 }
480497
481498 public void testStatsOnShardUnassigned () throws IOException {
499+ setup ();
482500 // Scenario:
483501 // - Create index with single primary and two replica shard
484502 // - Index documents
@@ -505,6 +523,7 @@ public void testStatsOnShardUnassigned() throws IOException {
505523 }
506524
507525 public void testStatsOnRemoteStoreRestore () throws IOException {
526+ setup ();
508527 // Creating an index with primary shard count == total nodes in cluster and 0 replicas
509528 int dataNodeCount = client ().admin ().cluster ().prepareHealth ().get ().getNumberOfDataNodes ();
510529 createIndex (INDEX_NAME , remoteStoreIndexSettings (0 , dataNodeCount ));
@@ -552,6 +571,7 @@ public void testStatsOnRemoteStoreRestore() throws IOException {
552571 }
553572
554573 public void testNonZeroPrimaryStatsOnNewlyCreatedIndexWithZeroDocs () throws Exception {
574+ setup ();
555575 // Create an index with one primary and one replica shard
556576 createIndex (INDEX_NAME , remoteStoreIndexSettings (1 , 1 ));
557577 ensureGreen (INDEX_NAME );
@@ -589,6 +609,58 @@ public void testNonZeroPrimaryStatsOnNewlyCreatedIndexWithZeroDocs() throws Exce
589609 }, 5 , TimeUnit .SECONDS );
590610 }
591611
612+ public void testStatsCorrectnessOnFailover () {
613+ Settings clusterSettings = Settings .builder ()
614+ .put (LeaderChecker .LEADER_CHECK_TIMEOUT_SETTING .getKey (), "100ms" )
615+ .put (LeaderChecker .LEADER_CHECK_INTERVAL_SETTING .getKey (), "500ms" )
616+ .put (LeaderChecker .LEADER_CHECK_RETRY_COUNT_SETTING .getKey (), 1 )
617+ .put (FollowersChecker .FOLLOWER_CHECK_TIMEOUT_SETTING .getKey (), "100ms" )
618+ .put (FollowersChecker .FOLLOWER_CHECK_INTERVAL_SETTING .getKey (), "500ms" )
619+ .put (FollowersChecker .FOLLOWER_CHECK_RETRY_COUNT_SETTING .getKey (), 1 )
620+ .put (nodeSettings (0 ))
621+ .build ();
622+ String clusterManagerNode = internalCluster ().startClusterManagerOnlyNode (clusterSettings );
623+ internalCluster ().startDataOnlyNodes (2 , clusterSettings );
624+
625+ // Create an index with one primary and one replica shard
626+ createIndex (INDEX_NAME , remoteStoreIndexSettings (1 , 1 ));
627+ ensureGreen (INDEX_NAME );
628+
629+ // Index some docs and refresh
630+ indexDocs ();
631+ refresh (INDEX_NAME );
632+
633+ String primaryNode = primaryNodeName (INDEX_NAME );
634+ String replicaNode = replicaNodeName (INDEX_NAME );
635+
636+ // Start network disruption - primary node will be isolated
637+ Set <String > nodesInOneSide = Stream .of (clusterManagerNode , replicaNode ).collect (Collectors .toCollection (HashSet ::new ));
638+ Set <String > nodesInOtherSide = Stream .of (primaryNode ).collect (Collectors .toCollection (HashSet ::new ));
639+ NetworkDisruption networkDisruption = new NetworkDisruption (
640+ new NetworkDisruption .TwoPartitions (nodesInOneSide , nodesInOtherSide ),
641+ NetworkDisruption .DISCONNECT
642+ );
643+ internalCluster ().setDisruptionScheme (networkDisruption );
644+ logger .info ("--> network disruption is started" );
645+ networkDisruption .startDisrupting ();
646+ ensureStableCluster (2 , clusterManagerNode );
647+
648+ RemoteStoreStatsResponse response = client (clusterManagerNode ).admin ().cluster ().prepareRemoteStoreStats (INDEX_NAME , "0" ).get ();
649+ final String indexShardId = String .format (Locale .ROOT , "[%s][%s]" , INDEX_NAME , "0" );
650+ List <RemoteStoreStats > matches = Arrays .stream (response .getRemoteStoreStats ())
651+ .filter (stat -> indexShardId .equals (stat .getSegmentStats ().shardId .toString ()))
652+ .collect (Collectors .toList ());
653+ assertEquals (1 , matches .size ());
654+ RemoteSegmentTransferTracker .Stats segmentStats = matches .get (0 ).getSegmentStats ();
655+ assertEquals (0 , segmentStats .refreshTimeLagMs );
656+
657+ networkDisruption .stopDisrupting ();
658+ internalCluster ().clearDisruptionScheme ();
659+ ensureStableCluster (3 , clusterManagerNode );
660+ ensureGreen (INDEX_NAME );
661+ logger .info ("Test completed" );
662+ }
663+
592664 private void indexDocs () {
593665 for (int i = 0 ; i < randomIntBetween (5 , 10 ); i ++) {
594666 if (randomBoolean ()) {
0 commit comments