Yunyung commented on code in PR #19658: URL: https://github.com/apache/kafka/pull/19658#discussion_r2081198851
########## raft/src/test/java/org/apache/kafka/raft/KafkaRaftClientTest.java: ########## @@ -4569,6 +4574,55 @@ public void testObserverFetchWithNoLocalId(boolean withKip853Rpc) throws Excepti assertEquals(3, context.log.lastFetchedEpoch()); } + @Test + public void testExponentialElectionBackoffMs() { + Random mockedRandom = Mockito.mock(Random.class); + int electionBackoffMaxMs = 1000; + + // test the bound of the first call to random.nextInt + for (int retries = 1; retries < 11; retries++) { + binaryExponentialElectionBackoffMs(electionBackoffMaxMs, retries, mockedRandom); + ArgumentCaptor<Integer> nextIntCaptor = ArgumentCaptor.forClass(Integer.class); + Mockito.verify(mockedRandom).nextInt(Mockito.eq(1), nextIntCaptor.capture()); + int actualBound = nextIntCaptor.getValue(); + int expectedBound = (int) (2 * Math.pow(2, retries - 1)); + assertEquals(expectedBound, actualBound, "Incorrect bound for retries=" + retries); + Mockito.clearInvocations(mockedRandom); + } + // after the 10th retry, the bound of the first call to random.nextInt will remain capped to + // (RETRY_BACKOFF_BASE_MS * 2 << 10)=2048 to prevent overflow + int firstNextIntMaxBound = 2048; + for (int retries = 11; retries < 13; retries++) { + binaryExponentialElectionBackoffMs(electionBackoffMaxMs, retries, mockedRandom); + ArgumentCaptor<Integer> nextIntCaptor = ArgumentCaptor.forClass(Integer.class); + Mockito.verify(mockedRandom).nextInt(Mockito.eq(1), nextIntCaptor.capture()); + int actualBound = nextIntCaptor.getValue(); + assertEquals(firstNextIntMaxBound, actualBound); + Mockito.clearInvocations(mockedRandom); + } + + // test that the return value of the method is capped to QUORUM_ELECTION_BACKOFF_MAX_MS_CONFIG + jitter + int jitterMs = 50; + // any bound >= (1000 + jitter)/(RETRY_BACKOFF_BASE_MS)=21 will result in returning this cap + for (int firstNextInt : Arrays.asList(21, 1000, firstNextIntMaxBound)) { + Mockito.when(mockedRandom.nextInt(1, firstNextIntMaxBound)).thenReturn(firstNextInt); + Mockito.when(mockedRandom.nextInt(RETRY_BACKOFF_BASE_MS)).thenReturn(jitterMs); + + int returnedBackoffMs = binaryExponentialElectionBackoffMs(electionBackoffMaxMs, 11, mockedRandom); + + // verify nextInt was called on both expected bounds + ArgumentCaptor<Integer> nextIntCaptor = ArgumentCaptor.forClass(Integer.class); + Mockito.verify(mockedRandom).nextInt(Mockito.eq(1), nextIntCaptor.capture()); + Mockito.verify(mockedRandom).nextInt(nextIntCaptor.capture()); + List<Integer> allCapturedBounds = nextIntCaptor.getAllValues(); + assertEquals(firstNextIntMaxBound, allCapturedBounds.get(0)); + assertEquals(RETRY_BACKOFF_BASE_MS, allCapturedBounds.get(1)); + + // finally verify the backoff returned is capped to electionBackoffMaxMs + jitterMs + assertEquals(electionBackoffMaxMs + jitterMs, returnedBackoffMs); + } Review Comment: Add Mockito.clearInvocations(mockedRandom); -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: jira-unsubscr...@kafka.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org