content: /**
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.aurora.common.stats;
  
  import java.util.concurrent.atomic.AtomicLong;
  
  import com.google.common.base.Supplier;
  
  import org.apache.aurora.common.util.testing.FakeTicker;
  import org.easymock.IMocksControl;
  import org.junit.After;
  import org.junit.Before;
  import org.junit.Test;
  
  import static org.easymock.EasyMock.createControl;
  import static org.easymock.EasyMock.expect;
  import static org.easymock.EasyMock.expectLastCall;
  import static org.hamcrest.CoreMatchers.is;
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertNotNull;
  import static org.junit.Assert.assertThat;
  
  /**
   * @author William Farner
   */
  public class RateTest {
  
    private static final int ONE_SEC = 1000000000;
    private static final double EPSILON = 1E-6;
  
    private IMocksControl control;
    private FakeTicker ticker;
  
    private Stat<Integer> input;
  
    @Before
    @SuppressWarnings("unchecked")
    public void setUp() {
      control = createControl();
  
      ticker = new FakeTicker();
      input = control.createMock(Stat.class);
    }
  
    @After
    public void verify() {
      Stats.flush();
      control.verify();
    }
  
    @Test
    public void testInputsRegistered() {
      expect(input.getName()).andReturn("test");
      expectLastCall().atLeastOnce();
  
      control.replay();
  
      Rate.of(input);
      assertNotNull(Stats.getVariable("test"));
    }
  
    @Test
    public void testNoHistory() throws Exception {
      expectCalls(0);
  
      control.replay();
  
      assertResults();
    }
  
    @Test
    public void testFlat() throws Exception {
      expectCalls(10, 10);
  
      control.replay();
  
      assertResults(0);
    }
  
    @Test
    public void testFixedRate() throws Exception {
      expectCalls(10, 20, 30, 40);
  
      control.replay();
  
      assertResults(10, 10, 10);
    }
  
    @Test
    public void testVariableRate() throws Exception {
      expectCalls(10, 20, 50, 150);
  
      control.replay();
  
      assertResults(10, 30, 100);
    }
  
    @Test
    public void testVariableRateAtomicLong() throws Exception {
      AtomicLong value = new AtomicLong();
      Rate<AtomicLong> rate = Rate.of("test", value).withTicker(ticker).build();
  
      ticker.waitNanos(ONE_SEC);
      value.set(10);
      assertEquals(0d, rate.sample(), EPSILON);
  
      ticker.waitNanos(ONE_SEC);
      value.set(20);
      assertEquals(10d, rate.sample(), EPSILON);
  
      ticker.waitNanos(ONE_SEC);
      value.set(50);
      assertEquals(30d, rate.sample(), EPSILON);
  
      ticker.waitNanos(ONE_SEC);
      value.set(100);
      assertEquals(50d, rate.sample(), EPSILON);
  
      control.replay();
    }
  
    @Test
    public void testNegativeRate() throws Exception {
      expectCalls(40, 30, 20, 10);
  
      control.replay();
  
      assertResults(-10, -10, -10);
    }
  
    @Test
    public void testZeroDelta() throws Exception {
      expectCalls(10, 10, 10);
  
      control.replay();
  
      assertResults(0, 0);
    }
  
    @Test
    public void testLongWindow() throws Exception {
      expectCalls(10, 10, 0, 10, 10);
  
      control.replay();
  
      assertResults(Rate.of(input).withWindowSize(3).withTicker(ticker).build(), 0, -5, 0, 0);
    }
  
    @Test
    public void testRateOfRate() throws Exception {
      expectCalls(10, 20, 30, 40, 50, 60);
  
      control.replay();
  
      Rate<Integer> rate = Rate.of(input).withTicker(ticker).build();
      Rate<Double> rateOfRate = Rate.of(rate).withTicker(ticker).build();
  
      assertThat(rate.sample(), is(0d));
      assertThat(rateOfRate.sample(), is(0d));
      ticker.waitNanos(ONE_SEC);
      assertThat(rate.sample(), is(10d));
      assertThat(rateOfRate.sample(), is(10d));
      ticker.waitNanos(ONE_SEC);
      assertThat(rate.sample(), is(10d));
      assertThat(rateOfRate.sample(), is(0d));
      ticker.waitNanos(ONE_SEC);
      assertThat(rate.sample(), is(10d));
      assertThat(rateOfRate.sample(), is(0d));
      ticker.waitNanos(ONE_SEC);
      assertThat(rate.sample(), is(10d));
      assertThat(rateOfRate.sample(), is(0d));
      ticker.waitNanos(ONE_SEC);
      assertThat(rate.sample(), is(10d));
      assertThat(rateOfRate.sample(), is(0d));
    }
  
    @Test
    public void testScaleFactor() throws Exception {
      expectCalls(10, 20, 30, 40);
  
      control.replay();
  
      assertResults(Rate.of(input).withTicker(ticker).withScaleFactor(10).build(), 100, 100, 100);
    }
  
    @Test
    public void testFractionalScaleFactor() throws Exception {
      expectCalls(10, 20, 30, 40);
  
      control.replay();
  
      assertResults(Rate.of(input).withTicker(ticker).withScaleFactor(0.1).build(), 1, 1, 1);
    }
  
    @Test
    public void testSupplier() throws Exception {
      Supplier<Long> supplier = new Supplier<Long>() {
        long value = 0;
        @Override public Long get() {
          value += 10;
          return value;
        }
      };
  
      control.replay();
      assertResults(Rate.of("test", supplier).withTicker(ticker).build(), 10, 10, 10);
    }
  
    private void expectCalls(int... samples) {
      expect(input.getName()).andReturn("test");
      expectLastCall().atLeastOnce();
      for (int sample : samples) {
        expect(input.read()).andReturn(sample);
      }
    }
  
    private void assertResults(double... results) throws Exception {
      assertResults(Rate.of(input).withTicker(ticker).build(), results);
    }
  
    private void assertResults(Rate rate, double... results) throws Exception {
      // First result is always zero.
      assertEquals(0d, rate.sample().doubleValue(), EPSILON);
      ticker.waitNanos(ONE_SEC);
  
      for (double result : results) {
        assertEquals(result, rate.sample().doubleValue(), EPSILON);
        ticker.waitNanos(ONE_SEC);
      }
    }
  }
  