/*
 * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
 * (the "License"). You may not use this work except in compliance with the License, which is
 * available at www.apache.org/licenses/LICENSE-2.0
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied, as more fully set forth in the License.
 *
 * See the NOTICE file distributed with this work for information regarding copyright ownership.
 */

package com.google.common.util.concurrent;

import static java.util.concurrent.TimeUnit.MICROSECONDS;
import static java.util.concurrent.TimeUnit.MILLISECONDS;

import com.google.common.util.concurrent.RateLimiter.SleepingTicker;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

/**
 * Provides a fake {@link RateLimiter} to facilitate testing. Note that in Guava 14.0 the
 * {@link RateLimiter$SleepingTicker} class is package private, so this fake rate limiter has to
 * be in the same package to be able to extend it. Later versions of Guava makes it public, so this
 * can be moved to a package belongs to alluxio when updating to a newer version of Guava.
 */
public final class MockRateLimiter {
  private final RateLimiter mRateLimiter;
  private final FakeSleepingTicker mTicker;

  public MockRateLimiter(double permitsPerSecond) {
    mTicker = new FakeSleepingTicker();
    mRateLimiter = RateLimiter.create(mTicker, permitsPerSecond);
  }

  public RateLimiter getGuavaRateLimiter() {
    return mRateLimiter;
  }

  public void sleepMillis(int millis) {
    mTicker.sleepMillis(millis);
  }

  public List<String> readEventsAndClear() {
    return mTicker.readEventsAndClear();
  }

  /**
   * The sleeping ticker gathers events and presents them as strings.
   * R0.6 means a delay of 0.6 seconds caused by the (R)ateLimiter
   * U1.0 means the (U)ser caused the ticker to sleep for a second.
   */
  private static class FakeSleepingTicker extends SleepingTicker {
    private long mInstant = 0L;
    private final List<String> mEvents = new ArrayList<>();

    @Override
    public long read() {
      return mInstant;
    }

    private void sleepMillis(int millis) {
      sleepMicros("U", MILLISECONDS.toMicros(millis));
    }

    private void sleepMicros(String caption, long micros) {
      mInstant += MICROSECONDS.toNanos(micros);
      mEvents.add(caption + String.format(Locale.ROOT, "%3.2f", (micros / 1000000.0)));
    }

    @Override
    public void sleepMicrosUninterruptibly(long micros) {
      sleepMicros("R", micros);
    }

    private List<String> readEventsAndClear() {
      try {
        return new ArrayList<>(mEvents);
      } finally {
        mEvents.clear();
      }
    }

    @Override
    public String toString() {
      return mEvents.toString();
    }
  }
}

@@ -1331,243 +1331,614 @@
 %0A%0A  
-public MockRateLimiter(double permitsPerSecond) %7B%0A    mTicker = new FakeSleepingTicker();%0A    mRateLimiter = RateLimiter.create(mTicker, permitsPerSecond);%0A  %7D%0A%0A  public RateLimiter getGuavaRateLimiter() %7B%0A    return mRateLimiter;%0A  %7D%0A
+/**%0A   * Constructs %7B@link MockRateLimiter%7D.%0A   *%0A   * @param permitsPerSecond the rate of the returned %7B@code RateLimiter%7D, measured in%0A   *        how many permits become available per second%0A   */%0A  public MockRateLimiter(double permitsPerSecond) %7B%0A    mTicker = new FakeSleepingTicker();%0A    mRateLimiter = RateLimiter.create(mTicker, permitsPerSecond);%0A  %7D%0A%0A  /**%0A   * Gets Guava RateLimiter.%0A   *%0A   * @return Guava RateLimiter%0A   */%0A  public RateLimiter getGuavaRateLimiter() %7B%0A    return mRateLimiter;%0A  %7D%0A%0A  /**%0A   * Sleeps in milliseconds.%0A   *%0A   * @param millis the number of milliseconds%0A   */
 %0A  p
@@ -2012,16 +2012,90 @@
 );%0A  %7D%0A%0A
+  /**%0A   * Reads events and clears.%0A   * @return the list of events%0A   */%0A
   public

Add javadoc for MockRateLimiter