|  | @@ -63,6 +63,7 @@ import static org.hamcrest.Matchers.contains;
 | 
	
		
			
				|  |  |  import static org.hamcrest.Matchers.containsInAnyOrder;
 | 
	
		
			
				|  |  |  import static org.hamcrest.Matchers.empty;
 | 
	
		
			
				|  |  |  import static org.hamcrest.Matchers.equalTo;
 | 
	
		
			
				|  |  | +import static org.hamcrest.Matchers.greaterThan;
 | 
	
		
			
				|  |  |  import static org.hamcrest.Matchers.not;
 | 
	
		
			
				|  |  |  import static org.hamcrest.Matchers.nullValue;
 | 
	
		
			
				|  |  |  import static org.hamcrest.core.IsInstanceOf.instanceOf;
 | 
	
	
		
			
				|  | @@ -160,7 +161,7 @@ public class FollowersCheckerTests extends ESTestCase {
 | 
	
		
			
				|  |  |      public void testFailsNodeThatDoesNotRespond() {
 | 
	
		
			
				|  |  |          final Settings settings = randomSettings();
 | 
	
		
			
				|  |  |          testBehaviourOfFailingNode(settings, () -> null,
 | 
	
		
			
				|  |  | -            "followers check retry count exceeded",
 | 
	
		
			
				|  |  | +            "followers check retry count exceeded [timeouts=" + FOLLOWER_CHECK_RETRY_COUNT_SETTING.get(settings) + ", failures=0]",
 | 
	
		
			
				|  |  |              (FOLLOWER_CHECK_RETRY_COUNT_SETTING.get(settings) - 1) * FOLLOWER_CHECK_INTERVAL_SETTING.get(settings).millis()
 | 
	
		
			
				|  |  |                  + FOLLOWER_CHECK_RETRY_COUNT_SETTING.get(settings) * FOLLOWER_CHECK_TIMEOUT_SETTING.get(settings).millis(),
 | 
	
		
			
				|  |  |              () -> new StatusInfo(HEALTHY, "healthy-info"));
 | 
	
	
		
			
				|  | @@ -171,18 +172,61 @@ public class FollowersCheckerTests extends ESTestCase {
 | 
	
		
			
				|  |  |          testBehaviourOfFailingNode(settings, () -> {
 | 
	
		
			
				|  |  |                  throw new ElasticsearchException("simulated exception");
 | 
	
		
			
				|  |  |              },
 | 
	
		
			
				|  |  | -            "followers check retry count exceeded",
 | 
	
		
			
				|  |  | +            "followers check retry count exceeded [timeouts=0, failures=" + FOLLOWER_CHECK_RETRY_COUNT_SETTING.get(settings) + "]",
 | 
	
		
			
				|  |  |              (FOLLOWER_CHECK_RETRY_COUNT_SETTING.get(settings) - 1) * FOLLOWER_CHECK_INTERVAL_SETTING.get(settings).millis(),
 | 
	
		
			
				|  |  |              () -> new StatusInfo(HEALTHY, "healthy-info"));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    public void testFailsNodeThatRejectsCheckAndDoesNotRespond() {
 | 
	
		
			
				|  |  | +        final Settings settings = randomSettings();
 | 
	
		
			
				|  |  | +        final int retryCount = FOLLOWER_CHECK_RETRY_COUNT_SETTING.get(settings);
 | 
	
		
			
				|  |  | +        final int timeoutCount = between(0, retryCount);
 | 
	
		
			
				|  |  | +        final int failureCount = retryCount - timeoutCount;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        testBehaviourOfFailingNode(
 | 
	
		
			
				|  |  | +            settings,
 | 
	
		
			
				|  |  | +            new Supplier<Empty>() {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                private int timeoutsRemaining;
 | 
	
		
			
				|  |  | +                private int failuresRemaining;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                @Override
 | 
	
		
			
				|  |  | +                public Empty get() {
 | 
	
		
			
				|  |  | +                    if (timeoutsRemaining == 0 && failuresRemaining == 0) {
 | 
	
		
			
				|  |  | +                        // node was added, reset counters
 | 
	
		
			
				|  |  | +                        timeoutsRemaining = timeoutCount;
 | 
	
		
			
				|  |  | +                        failuresRemaining = failureCount;
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    if (timeoutsRemaining == 0) {
 | 
	
		
			
				|  |  | +                        assertThat(failuresRemaining--, greaterThan(0));
 | 
	
		
			
				|  |  | +                        throw new ElasticsearchException("simulated exception");
 | 
	
		
			
				|  |  | +                    } else if (failuresRemaining == 0) {
 | 
	
		
			
				|  |  | +                        assertThat(timeoutsRemaining--, greaterThan(0));
 | 
	
		
			
				|  |  | +                        return null;
 | 
	
		
			
				|  |  | +                    } else if (randomBoolean()) {
 | 
	
		
			
				|  |  | +                        assertThat(failuresRemaining--, greaterThan(0));
 | 
	
		
			
				|  |  | +                        throw new ElasticsearchException("simulated exception");
 | 
	
		
			
				|  |  | +                    } else {
 | 
	
		
			
				|  |  | +                        assertThat(timeoutsRemaining--, greaterThan(0));
 | 
	
		
			
				|  |  | +                        return null;
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            },
 | 
	
		
			
				|  |  | +            "followers check retry count exceeded [timeouts=" + timeoutCount + ", failures=" + failureCount + "]",
 | 
	
		
			
				|  |  | +            (retryCount - 1) * FOLLOWER_CHECK_INTERVAL_SETTING.get(settings).millis()
 | 
	
		
			
				|  |  | +                + timeoutCount * FOLLOWER_CHECK_TIMEOUT_SETTING.get(settings).millis(),
 | 
	
		
			
				|  |  | +            () -> new StatusInfo(HEALTHY, "healthy-info"));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      public void testFailureCounterResetsOnSuccess() {
 | 
	
		
			
				|  |  |          final Settings settings = randomSettings();
 | 
	
		
			
				|  |  |          final int retryCount = FOLLOWER_CHECK_RETRY_COUNT_SETTING.get(settings);
 | 
	
		
			
				|  |  |          final int maxRecoveries = randomIntBetween(3, 10);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          // passes just enough checks to keep it alive, up to maxRecoveries, and then fails completely
 | 
	
		
			
				|  |  | -        testBehaviourOfFailingNode(settings, new Supplier<Empty>() {
 | 
	
		
			
				|  |  | +        testBehaviourOfFailingNode(
 | 
	
		
			
				|  |  | +            settings,
 | 
	
		
			
				|  |  | +            new Supplier<Empty>() {
 | 
	
		
			
				|  |  |                  private int checkIndex;
 | 
	
		
			
				|  |  |                  private int recoveries;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -196,9 +240,37 @@ public class FollowersCheckerTests extends ESTestCase {
 | 
	
		
			
				|  |  |                      throw new ElasticsearchException("simulated exception");
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              },
 | 
	
		
			
				|  |  | -            "followers check retry count exceeded",
 | 
	
		
			
				|  |  | -            (FOLLOWER_CHECK_RETRY_COUNT_SETTING.get(settings) * (maxRecoveries + 1) - 1)
 | 
	
		
			
				|  |  | -                * FOLLOWER_CHECK_INTERVAL_SETTING.get(settings).millis(), () -> new StatusInfo(HEALTHY, "healthy-info"));
 | 
	
		
			
				|  |  | +            "followers check retry count exceeded [timeouts=0, failures=" + retryCount + "]",
 | 
	
		
			
				|  |  | +            (retryCount * (maxRecoveries + 1) - 1) * FOLLOWER_CHECK_INTERVAL_SETTING.get(settings).millis(),
 | 
	
		
			
				|  |  | +            () -> new StatusInfo(HEALTHY, "healthy-info"));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public void testTimeoutCounterResetsOnSuccess() {
 | 
	
		
			
				|  |  | +        final Settings settings = randomSettings();
 | 
	
		
			
				|  |  | +        final int retryCount = FOLLOWER_CHECK_RETRY_COUNT_SETTING.get(settings);
 | 
	
		
			
				|  |  | +        final int maxRecoveries = randomIntBetween(3, 10);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // passes just enough checks to keep it alive, up to maxRecoveries, and then fails completely
 | 
	
		
			
				|  |  | +        testBehaviourOfFailingNode(
 | 
	
		
			
				|  |  | +            settings,
 | 
	
		
			
				|  |  | +            new Supplier<Empty>() {
 | 
	
		
			
				|  |  | +                private int checkIndex;
 | 
	
		
			
				|  |  | +                private int recoveries;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                @Override
 | 
	
		
			
				|  |  | +                public Empty get() {
 | 
	
		
			
				|  |  | +                    checkIndex++;
 | 
	
		
			
				|  |  | +                    if (checkIndex % retryCount == 0 && recoveries < maxRecoveries) {
 | 
	
		
			
				|  |  | +                        recoveries++;
 | 
	
		
			
				|  |  | +                        return Empty.INSTANCE;
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    return null;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            },
 | 
	
		
			
				|  |  | +            "followers check retry count exceeded [timeouts=" + retryCount + ", failures=0]",
 | 
	
		
			
				|  |  | +            (retryCount * (maxRecoveries + 1) - 1) * FOLLOWER_CHECK_INTERVAL_SETTING.get(settings).millis() +
 | 
	
		
			
				|  |  | +                (retryCount * (maxRecoveries + 1) - maxRecoveries) * FOLLOWER_CHECK_TIMEOUT_SETTING.get(settings).millis(),
 | 
	
		
			
				|  |  | +            () -> new StatusInfo(HEALTHY, "healthy-info"));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      public void testFailsNodeThatIsDisconnected() {
 |