Java Code Examples for org.apache.kafka.common.utils.Time#sleep()

The following examples show how to use org.apache.kafka.common.utils.Time#sleep() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: BrokerFailureDetectorTest.java    From cruise-control with BSD 2-Clause "Simplified" License 6 votes vote down vote up
@Test
public void testLoadFailedBrokersFromZK() throws Exception {
  Time mockTime = getMockTime();
  Queue<Anomaly> anomalies = new PriorityBlockingQueue<>(ANOMALY_DETECTOR_INITIAL_QUEUE_SIZE, anomalyComparator());
  BrokerFailureDetector detector = createBrokerFailureDetector(anomalies, mockTime);

  try {
    detector.startDetection();
    int brokerId = 0;
    killBroker(brokerId);
    long start = System.currentTimeMillis();
    while (anomalies.isEmpty() && System.currentTimeMillis() < start + 30000) {
      // Wait for the anomalies to be drained.
    }
    assertEquals(Collections.singletonMap(brokerId, 100L), detector.failedBrokers());
    // shutdown, advance the clock and create a new detector.
    detector.shutdown();
    mockTime.sleep(100L);
    detector = createBrokerFailureDetector(anomalies, mockTime);
    // start the newly created detector and the broker down time should remain previous time.
    detector.startDetection();
    assertEquals(Collections.singletonMap(brokerId, 100L), detector.failedBrokers());
  } finally {
    detector.shutdown();
  }
}
 
Example 2
Source File: IntegrationTestUtils.java    From ksql-fork-with-deep-learning-function with Apache License 2.0 5 votes vote down vote up
/**
 * @param topic          Kafka topic to write the data records to
 * @param records        Data records to write to Kafka
 * @param producerConfig Kafka producer configuration
 * @param <K>            Key type of the data records
 * @param <V>            Value type of the data records
 */
public static <K, V> void produceKeyValuesSynchronously(
        final String topic, final Collection<KeyValue<K, V>> records, final Properties producerConfig, final Time time)
        throws ExecutionException, InterruptedException {
  for (final KeyValue<K, V> record : records) {
    produceKeyValuesSynchronouslyWithTimestamp(topic,
            Collections.singleton(record),
            producerConfig,
            time.milliseconds());
    time.sleep(1L);
  }
}
 
Example 3
Source File: UserTaskManagerTest.java    From cruise-control with BSD 2-Clause "Simplified" License 5 votes vote down vote up
@Test
public void testExpireSession() throws Exception {
  UUID testUserTaskId = UUID.randomUUID();

  UserTaskManager.UUIDGenerator mockUUIDGenerator = EasyMock.mock(UserTaskManager.UUIDGenerator.class);
  EasyMock.expect(mockUUIDGenerator.randomUUID()).andReturn(testUserTaskId).anyTimes();

  Time mockTime = new MockTime();
  HttpSession mockHttpSession = EasyMock.mock(HttpSession.class);
  EasyMock.expect(mockHttpSession.getLastAccessedTime()).andReturn(mockTime.milliseconds()).anyTimes();
  mockHttpSession.invalidate();

  HttpServletRequest mockHttpServletRequest = prepareRequest(mockHttpSession, null);

  OperationFuture future = new OperationFuture("future");
  UserTaskManager userTaskManager = new UserTaskManager(1000, 1, TimeUnit.HOURS.toMillis(6),
                                                        100, mockTime, mockUUIDGenerator);

  HttpServletResponse mockHttpServletResponse = EasyMock.mock(HttpServletResponse.class);
  mockHttpServletResponse.setHeader(EasyMock.anyString(), EasyMock.anyString());

  EasyMock.replay(mockUUIDGenerator, mockHttpSession, mockHttpServletResponse);
  // test-case: test if the sessions are removed on expiration
  OperationFuture future1 =
      userTaskManager.getOrCreateUserTask(mockHttpServletRequest, mockHttpServletResponse, uuid -> future, 0, true, null).get(0);
  Assert.assertEquals(future, future1);

  mockTime.sleep(1001);
  Thread.sleep(TimeUnit.SECONDS.toMillis(UserTaskManager.USER_TASK_SCANNER_PERIOD_SECONDS + 1));

  OperationFuture future2 = userTaskManager.getFuture(mockHttpServletRequest);
  Assert.assertNull(future2);

  userTaskManager.close();
}
 
Example 4
Source File: SelfHealingNotifierTest.java    From cruise-control with BSD 2-Clause "Simplified" License 4 votes vote down vote up
@Test
public void testOnBrokerFailure() {
  final long failureTime1 = 200L;
  final long failureTime2 = 400L;
  final long startTime = 500L;
  KafkaCruiseControl mockKafkaCruiseControl = EasyMock.mock(KafkaCruiseControl.class);
  Properties props = KafkaCruiseControlUnitTestUtils.getKafkaCruiseControlProperties();
  KafkaCruiseControlConfig kafkaCruiseControlConfig = new KafkaCruiseControlConfig(props);
  EasyMock.expect(mockKafkaCruiseControl.config()).andReturn(kafkaCruiseControlConfig).atLeastOnce();
  EasyMock.replay(mockKafkaCruiseControl);
  Time mockTime = new MockTime(0, startTime, TimeUnit.NANOSECONDS.convert(startTime, TimeUnit.MILLISECONDS));
  TestingBrokerFailureAutoFixNotifier anomalyNotifier = new TestingBrokerFailureAutoFixNotifier(mockTime);
  anomalyNotifier.configure(Collections.singletonMap(SelfHealingNotifier.SELF_HEALING_BROKER_FAILURE_ENABLED_CONFIG, "true"));

  Map<Integer, Long> failedBrokers = new HashMap<>();
  failedBrokers.put(1, failureTime1);
  failedBrokers.put(2, failureTime2);
  Map<String, Object> parameterConfigOverrides = new HashMap<>(4);
  parameterConfigOverrides.put(KAFKA_CRUISE_CONTROL_OBJECT_CONFIG, mockKafkaCruiseControl);
  parameterConfigOverrides.put(FAILED_BROKERS_OBJECT_CONFIG, failedBrokers);
  parameterConfigOverrides.put(ANOMALY_DETECTION_TIME_MS_OBJECT_CONFIG, failureTime1);
  parameterConfigOverrides.put(BROKER_FAILURES_FIXABLE_CONFIG, true);

  AnomalyNotificationResult result = anomalyNotifier.onBrokerFailure(
      kafkaCruiseControlConfig.getConfiguredInstance(AnomalyDetectorConfig.BROKER_FAILURES_CLASS_CONFIG,
                                                     BrokerFailures.class,
                                                     parameterConfigOverrides));
  assertEquals(AnomalyNotificationResult.Action.CHECK, result.action());
  assertEquals(SelfHealingNotifier.DEFAULT_ALERT_THRESHOLD_MS + failureTime1 - mockTime.milliseconds(),
               result.delay());
  assertFalse(anomalyNotifier._alertCalled.get(KafkaAnomalyType.BROKER_FAILURE));

  // Sleep to 1 ms before alert.
  mockTime.sleep(result.delay() - 1);
  result = anomalyNotifier.onBrokerFailure(
      kafkaCruiseControlConfig.getConfiguredInstance(AnomalyDetectorConfig.BROKER_FAILURES_CLASS_CONFIG,
                                                     BrokerFailures.class,
                                                     parameterConfigOverrides));
  assertEquals(AnomalyNotificationResult.Action.CHECK, result.action());
  assertEquals(1, result.delay());
  assertFalse(anomalyNotifier._alertCalled.get(KafkaAnomalyType.BROKER_FAILURE));

  // Sleep 1 ms
  mockTime.sleep(1);
  anomalyNotifier.resetAlert(KafkaAnomalyType.BROKER_FAILURE);
  result = anomalyNotifier.onBrokerFailure(
      kafkaCruiseControlConfig.getConfiguredInstance(AnomalyDetectorConfig.BROKER_FAILURES_CLASS_CONFIG,
                                                     BrokerFailures.class,
                                                     parameterConfigOverrides));
  assertEquals(AnomalyNotificationResult.Action.CHECK, result.action());
  assertEquals(SelfHealingNotifier.DEFAULT_AUTO_FIX_THRESHOLD_MS + failureTime1 - mockTime.milliseconds(),
               result.delay());
  assertTrue(anomalyNotifier._alertCalled.get(KafkaAnomalyType.BROKER_FAILURE));

  // Sleep to 1 ms before alert.
  mockTime.sleep(result.delay() - 1);
  anomalyNotifier.resetAlert(KafkaAnomalyType.BROKER_FAILURE);
  result = anomalyNotifier.onBrokerFailure(
      kafkaCruiseControlConfig.getConfiguredInstance(AnomalyDetectorConfig.BROKER_FAILURES_CLASS_CONFIG,
                                                     BrokerFailures.class,
                                                     parameterConfigOverrides));
  assertEquals(AnomalyNotificationResult.Action.CHECK, result.action());
  assertEquals(1, result.delay());
  assertFalse(anomalyNotifier._alertCalled.get(KafkaAnomalyType.BROKER_FAILURE));
  assertFalse(anomalyNotifier._autoFixTriggered.get(KafkaAnomalyType.BROKER_FAILURE));

  // Sleep 1 ms
  mockTime.sleep(1);
  anomalyNotifier.resetAlert(KafkaAnomalyType.BROKER_FAILURE);
  result = anomalyNotifier.onBrokerFailure(
      kafkaCruiseControlConfig.getConfiguredInstance(AnomalyDetectorConfig.BROKER_FAILURES_CLASS_CONFIG,
                                                     BrokerFailures.class,
                                                     parameterConfigOverrides));
  assertEquals(AnomalyNotificationResult.Action.FIX, result.action());
  assertEquals(-1L, result.delay());
  assertTrue(anomalyNotifier._alertCalled.get(KafkaAnomalyType.BROKER_FAILURE));
  assertTrue(anomalyNotifier._autoFixTriggered.get(KafkaAnomalyType.BROKER_FAILURE));
  assertFalse(anomalyNotifier._alertCalled.get(KafkaAnomalyType.GOAL_VIOLATION));
  assertFalse(anomalyNotifier._alertCalled.get(KafkaAnomalyType.METRIC_ANOMALY));
  assertFalse(anomalyNotifier._alertCalled.get(KafkaAnomalyType.DISK_FAILURE));
  assertFalse(anomalyNotifier._alertCalled.get(KafkaAnomalyType.TOPIC_ANOMALY));
}
 
Example 5
Source File: SelfHealingNotifierTest.java    From cruise-control with BSD 2-Clause "Simplified" License 4 votes vote down vote up
@Test
public void testSelfHealingDisabled() {
  final long startTime = 500L;
  Time mockTime = new MockTime(startTime);
  KafkaCruiseControl mockKafkaCruiseControl = EasyMock.mock(KafkaCruiseControl.class);
  Properties props = KafkaCruiseControlUnitTestUtils.getKafkaCruiseControlProperties();
  KafkaCruiseControlConfig kafkaCruiseControlConfig = new KafkaCruiseControlConfig(props);
  EasyMock.expect(mockKafkaCruiseControl.config()).andReturn(kafkaCruiseControlConfig).atLeastOnce();
  EasyMock.replay(mockKafkaCruiseControl);
  TestingBrokerFailureAutoFixNotifier anomalyNotifier = new TestingBrokerFailureAutoFixNotifier(mockTime);

  Map<String, String> selfHealingExplicitlyDisabled = new HashMap<>(4);
  selfHealingExplicitlyDisabled.put(SelfHealingNotifier.SELF_HEALING_BROKER_FAILURE_ENABLED_CONFIG, "false");
  selfHealingExplicitlyDisabled.put(SelfHealingNotifier.SELF_HEALING_GOAL_VIOLATION_ENABLED_CONFIG, "false");
  selfHealingExplicitlyDisabled.put(SelfHealingNotifier.SELF_HEALING_METRIC_ANOMALY_ENABLED_CONFIG, "false");
  selfHealingExplicitlyDisabled.put(SelfHealingNotifier.SELF_HEALING_DISK_FAILURE_ENABLED_CONFIG, "false");
  selfHealingExplicitlyDisabled.put(SelfHealingNotifier.SELF_HEALING_TOPIC_ANOMALY_ENABLED_CONFIG, "false");
  // Set to verify the overriding of specific config over general config
  selfHealingExplicitlyDisabled.put(SelfHealingNotifier.SELF_HEALING_ENABLED_CONFIG, "true");
  anomalyNotifier.configure(selfHealingExplicitlyDisabled);

  // (1) Test broker failure anomaly can be detected by notifier.
  final long failureTime1 = 200L;
  final long failureTime2 = 400L;
  Map<Integer, Long> failedBrokers = new HashMap<>();
  failedBrokers.put(1, failureTime1);
  failedBrokers.put(2, failureTime2);
  final long anomalyDetectionTime = 200L;
  final BrokerEntity brokerWithMetricAnomaly = new BrokerEntity("local", 1);

  mockTime.sleep(SelfHealingNotifier.DEFAULT_AUTO_FIX_THRESHOLD_MS + failureTime1);
  anomalyNotifier.resetAlert(KafkaAnomalyType.BROKER_FAILURE);
  Map<String, Object> parameterConfigOverrides = new HashMap<>(9);
  parameterConfigOverrides.put(KAFKA_CRUISE_CONTROL_OBJECT_CONFIG, mockKafkaCruiseControl);
  parameterConfigOverrides.put(FAILED_BROKERS_OBJECT_CONFIG, failedBrokers);
  parameterConfigOverrides.put(BROKER_FAILURES_FIXABLE_CONFIG, true);
  parameterConfigOverrides.put(ANOMALY_DETECTION_TIME_MS_OBJECT_CONFIG, anomalyDetectionTime);
  parameterConfigOverrides.put(METRIC_ANOMALY_FIXABLE_OBJECT_CONFIG, false);
  parameterConfigOverrides.put(METRIC_ANOMALY_BROKER_ENTITIES_OBJECT_CONFIG,
                               Collections.singletonMap(brokerWithMetricAnomaly, anomalyDetectionTime));
  parameterConfigOverrides.put(FAILED_DISKS_OBJECT_CONFIG,
                               Collections.singletonMap(1, Collections.singletonMap(BAD_LOGDIR, failureTime1)));
  parameterConfigOverrides.put(SELF_HEALING_TARGET_TOPIC_REPLICATION_FACTOR_CONFIG, SELF_HEALING_TARGET_REPLICATION_FACTOR);
  parameterConfigOverrides.put(BAD_TOPICS_BY_REPLICATION_FACTOR_CONFIG,
                               Collections.singletonMap(SELF_HEALING_TARGET_REPLICATION_FACTOR,
                                                        Collections.singleton(TOPIC_REPLICATION_FACTOR_ANOMALY_ENTRY)));
  AnomalyNotificationResult result = anomalyNotifier.onBrokerFailure(
      kafkaCruiseControlConfig.getConfiguredInstance(AnomalyDetectorConfig.BROKER_FAILURES_CLASS_CONFIG,
                                                     BrokerFailures.class,
                                                     parameterConfigOverrides));
  assertEquals(AnomalyNotificationResult.Action.IGNORE, result.action());
  assertTrue(anomalyNotifier._alertCalled.get(KafkaAnomalyType.BROKER_FAILURE));
  assertFalse(anomalyNotifier._autoFixTriggered.get(KafkaAnomalyType.BROKER_FAILURE));

  // (2) Test goal violation anomaly can be detected by notifier.
  anomalyNotifier.resetAlert(KafkaAnomalyType.GOAL_VIOLATION);
  result = anomalyNotifier.onGoalViolation(
      kafkaCruiseControlConfig.getConfiguredInstance(AnomalyDetectorConfig.GOAL_VIOLATIONS_CLASS_CONFIG,
                                                     GoalViolations.class,
                                                     parameterConfigOverrides));
  assertEquals(AnomalyNotificationResult.Action.IGNORE, result.action());
  assertTrue(anomalyNotifier._alertCalled.get(KafkaAnomalyType.GOAL_VIOLATION));
  assertFalse(anomalyNotifier._autoFixTriggered.get(KafkaAnomalyType.GOAL_VIOLATION));

  // (3) Test metric anomaly can be detected by notifier.
  anomalyNotifier.resetAlert(KafkaAnomalyType.METRIC_ANOMALY);
  result = anomalyNotifier.onMetricAnomaly(kafkaCruiseControlConfig.getConfiguredInstance(AnomalyDetectorConfig.METRIC_ANOMALY_CLASS_CONFIG,
                                                                                          KafkaMetricAnomaly.class,
                                                                                          parameterConfigOverrides));
  assertEquals(AnomalyNotificationResult.Action.IGNORE, result.action());
  assertTrue(anomalyNotifier._alertCalled.get(KafkaAnomalyType.METRIC_ANOMALY));
  assertFalse(anomalyNotifier._autoFixTriggered.get(KafkaAnomalyType.METRIC_ANOMALY));

  // (4) Test disk failure anomaly can be detected by notifier.
  anomalyNotifier.resetAlert(KafkaAnomalyType.DISK_FAILURE);
  result = anomalyNotifier.onDiskFailure(kafkaCruiseControlConfig.getConfiguredInstance(AnomalyDetectorConfig.DISK_FAILURES_CLASS_CONFIG,
                                                                                        DiskFailures.class,
                                                                                        parameterConfigOverrides));
  assertEquals(AnomalyNotificationResult.Action.IGNORE, result.action());
  assertTrue(anomalyNotifier._alertCalled.get(KafkaAnomalyType.DISK_FAILURE));
  assertFalse(anomalyNotifier._autoFixTriggered.get(KafkaAnomalyType.DISK_FAILURE));

  // (5) Test topic anomaly can be detected by notifier.
  anomalyNotifier.resetAlert(KafkaAnomalyType.TOPIC_ANOMALY);
  TopicReplicationFactorAnomaly topicReplicationFactorAnomaly = new TopicReplicationFactorAnomaly();
  topicReplicationFactorAnomaly.configure(parameterConfigOverrides);
  result = anomalyNotifier.onTopicAnomaly(topicReplicationFactorAnomaly);
  assertEquals(AnomalyNotificationResult.Action.IGNORE, result.action());
  assertTrue(anomalyNotifier._alertCalled.get(KafkaAnomalyType.TOPIC_ANOMALY));
  assertFalse(anomalyNotifier._autoFixTriggered.get(KafkaAnomalyType.TOPIC_ANOMALY));
}
 
Example 6
Source File: ExecutorTest.java    From cruise-control with BSD 2-Clause "Simplified" License 4 votes vote down vote up
@Test
public void testTimeoutAndForceExecutionStop() throws InterruptedException, OngoingExecutionException {
  createTopics(0);
  // The proposal tries to move the leader. We fake the replica list to be unchanged so there is no replica
  // movement, but only leader movement.
  ExecutionProposal proposal =
      new ExecutionProposal(TP1, 0, new ReplicaPlacementInfo(1),
                            Arrays.asList(new ReplicaPlacementInfo(0), new ReplicaPlacementInfo(1)),
                            Arrays.asList(new ReplicaPlacementInfo(0), new ReplicaPlacementInfo(1)));

  KafkaCruiseControlConfig configs = new KafkaCruiseControlConfig(getExecutorProperties());
  Time time = new MockTime();
  MetadataClient mockMetadataClient = EasyMock.mock(MetadataClient.class);
  // Fake the metadata to never change so the leader movement will timeout.
  Node node0 = new Node(0, "host0", 100);
  Node node1 = new Node(1, "host1", 100);
  Node[] replicas = new Node[2];
  replicas[0] = node0;
  replicas[1] = node1;
  PartitionInfo partitionInfo = new PartitionInfo(TP1.topic(), TP1.partition(), node1, replicas, replicas);
  Cluster cluster = new Cluster("id", Arrays.asList(node0, node1), Collections.singleton(partitionInfo),
                                Collections.emptySet(), Collections.emptySet());
  MetadataClient.ClusterAndGeneration clusterAndGeneration = new MetadataClient.ClusterAndGeneration(cluster, 0);
  EasyMock.expect(mockMetadataClient.refreshMetadata()).andReturn(clusterAndGeneration).anyTimes();
  EasyMock.expect(mockMetadataClient.cluster()).andReturn(clusterAndGeneration.cluster()).anyTimes();
  LoadMonitor mockLoadMonitor = getMockLoadMonitor();
  AnomalyDetector mockAnomalyDetector = getMockAnomalyDetector(RANDOM_UUID);
  UserTaskManager.UserTaskInfo mockUserTaskInfo = getMockUserTaskInfo();
  // This tests runs two consecutive executions. First one completes w/o error, but the second one with error.
  UserTaskManager mockUserTaskManager = getMockUserTaskManager(RANDOM_UUID, mockUserTaskInfo, Arrays.asList(false, true));
  EasyMock.replay(mockMetadataClient, mockLoadMonitor, mockAnomalyDetector, mockUserTaskInfo, mockUserTaskManager);

  Collection<ExecutionProposal> proposalsToExecute = Collections.singletonList(proposal);
  Executor executor = new Executor(configs, time, new MetricRegistry(), mockMetadataClient, DEMOTION_HISTORY_RETENTION_TIME_MS,
                                   REMOVAL_HISTORY_RETENTION_TIME_MS, null, mockUserTaskManager,
                                   mockAnomalyDetector);
  executor.setExecutionMode(false);
  executor.executeProposals(proposalsToExecute,
                            Collections.emptySet(),
                            null,
                            mockLoadMonitor,
                            null,
                            null,
                            null,
                            null,
                            null,
                            null,
                            true,
                            RANDOM_UUID,
                            ExecutorTest.class::getSimpleName);
  waitUntilTrue(() -> (executor.state().state() == ExecutorState.State.LEADER_MOVEMENT_TASK_IN_PROGRESS && !executor.inExecutionTasks().isEmpty()),
                "Leader movement task did not start within the time limit",
                EXECUTION_DEADLINE_MS, EXECUTION_SHORT_CHECK_MS);

  // Sleep over ExecutorConfig#DEFAULT_LEADER_MOVEMENT_TIMEOUT_MS with some margin for inter-thread synchronization.
  time.sleep(ExecutorConfig.DEFAULT_LEADER_MOVEMENT_TIMEOUT_MS + 1L);
  // The execution should finish.
  waitUntilTrue(() -> (!executor.hasOngoingExecution() && executor.state().state() == ExecutorState.State.NO_TASK_IN_PROGRESS),
                "Proposal execution did not finish within the time limit",
                EXECUTION_DEADLINE_MS, EXECUTION_REGULAR_CHECK_MS);

  // The proposal tries to move replicas.
  proposal = new ExecutionProposal(TP1, 0, new ReplicaPlacementInfo(1),
                                   Arrays.asList(new ReplicaPlacementInfo(0), new ReplicaPlacementInfo(1)),
                                   Arrays.asList(new ReplicaPlacementInfo(1), new ReplicaPlacementInfo(0)));
  proposalsToExecute = Collections.singletonList(proposal);
  executor.executeProposals(proposalsToExecute,
                            Collections.emptySet(),
                            null,
                            mockLoadMonitor,
                            null,
                            null,
                            null,
                            null,
                            null,
                            null,
                            true,
                            RANDOM_UUID,
                            ExecutorTest.class::getSimpleName);
  waitUntilTrue(() -> (executor.state().state() == ExecutorState.State.INTER_BROKER_REPLICA_MOVEMENT_TASK_IN_PROGRESS),
                "Inter-broker replica movement task did not start within the time limit",
                EXECUTION_DEADLINE_MS, EXECUTION_SHORT_CHECK_MS);
  // Force execution to stop.
  executor.userTriggeredStopExecution(true);
  // The execution should finish.
  waitUntilTrue(() -> (!executor.hasOngoingExecution() && executor.state().state() == ExecutorState.State.NO_TASK_IN_PROGRESS),
                "Proposal execution did not finish within the time limit",
                EXECUTION_DEADLINE_MS, EXECUTION_REGULAR_CHECK_MS);
  EasyMock.verify(mockMetadataClient, mockLoadMonitor, mockAnomalyDetector, mockUserTaskInfo, mockUserTaskManager);
}
 
Example 7
Source File: AbstractAuditorTest.java    From li-apache-kafka-clients with BSD 2-Clause "Simplified" License 4 votes vote down vote up
@Test
public void testTick() {
  Time time = new MockTime();
  TestingAuditor auditor = new TestingAuditor(time);
  Map<String, String> config = new HashMap<>();
  config.put(TestingAuditor.BUCKET_MS, "30000");
  config.put(AbstractAuditor.REPORTING_DELAY_MS, "6000");
  config.put(AbstractAuditor.REPORTING_INTERVAL_MS, "60000");
  auditor.configure(config);
  auditor.start();

  assertEquals(auditor.nextTick(), 60000, "The cutting over time should be 60000");

  auditor.record(auditor.auditToken("key", "value"), TOPIC, 0L, 1L, 10L, AuditType.SUCCESS);
  auditor.record(auditor.auditToken("key", "value"), TOPIC, 30000L, 1L, 10L, AuditType.SUCCESS);
  auditor.record(auditor.auditToken("key", "value"), TOPIC, auditor.nextTick(), 1L, 10L, AuditType.SUCCESS);
  auditor.record(auditor.auditToken("key", "value"), TOPIC, auditor.nextTick(), 1L, 10L, AuditType.SUCCESS);

  assertEquals(auditor.currentStats().stats().get(new AuditKey(TOPIC, 0L, AuditType.SUCCESS)).messageCount(), 1,
      "There should be one message in the current stats");
  assertEquals(auditor.currentStats().stats().get(new AuditKey(TOPIC, 1L, AuditType.SUCCESS)).messageCount(), 1,
      "There should be one message in the current stats");
  assertEquals(auditor.nextStats().stats().get(new AuditKey(TOPIC, 2L, AuditType.SUCCESS)).messageCount(), 2,
      "There should be two messages in bucket 2 in the next stats");

  // Advance the clock to 1 ms before next tick.
  time.sleep(59999);
  long ticks = auditor.ticks();
  auditor.interrupt();
  long startMs = System.currentTimeMillis();
  while (auditor.ticks() != ticks + 1 && System.currentTimeMillis() < startMs + 5000) { }
  assertEquals(auditor.currentStats().stats().get(new AuditKey(TOPIC, 0L, AuditType.SUCCESS)).messageCount(), 1,
      "There should be one message in the current stats");
  assertEquals(auditor.currentStats().stats().get(new AuditKey(TOPIC, 1L, AuditType.SUCCESS)).messageCount(), 1,
      "There should be one message in the current stats");
  assertEquals(auditor.nextStats().stats().get(new AuditKey(TOPIC, 2L, AuditType.SUCCESS)).messageCount(), 2,
      "There should be two messages in bucket 2 in the next stats");

  // Advance the clock again to the nextTick + REPORTING_DELAY_MS - 1. The tick should not happen due to the logging delay.
  time.sleep(6000);
  ticks = auditor.ticks();
  auditor.interrupt();
  startMs = System.currentTimeMillis();
  while (auditor.ticks() != ticks + 1 && System.currentTimeMillis() < startMs + 5000) { }
  assertEquals(auditor.currentStats().stats().get(new AuditKey(TOPIC, 0L, AuditType.SUCCESS)).messageCount(), 1,
      "There should be one message in the current stats");
  assertEquals(auditor.currentStats().stats().get(new AuditKey(TOPIC, 1L, AuditType.SUCCESS)).messageCount(), 1,
      "There should be one message in the current stats");
  assertEquals(auditor.nextStats().stats().get(new AuditKey(TOPIC, 2L, AuditType.SUCCESS)).messageCount(), 2,
      "There should be two messages in bucket 2 in the next stats");

  // Advance the clock again, now it should tick.
  time.sleep(1);
  ticks = auditor.ticks();
  auditor.interrupt();
  startMs = System.currentTimeMillis();
  while (auditor.ticks() != ticks + 1 && System.currentTimeMillis() < startMs + 5000) { }
  assertEquals(auditor.currentStats().stats().get(new AuditKey(TOPIC, 2L, AuditType.SUCCESS)).messageCount(), 2,
      "There should be one message in the current stats");
  assertTrue(auditor.nextStats().stats().isEmpty(), "The next stats should be empty now.");

  auditor.close();
}