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.net.http.handlers;
  
  import java.util.Arrays;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  
  import com.google.common.base.Joiner;
  import com.google.common.collect.ImmutableList;
  import com.google.common.collect.ImmutableMap;
  import com.google.common.collect.Iterables;
  import com.google.common.collect.Lists;
  import com.google.gson.Gson;
  import com.google.gson.reflect.TypeToken;
  
  import org.apache.aurora.common.collections.Iterables2;
  import org.apache.aurora.common.stats.TimeSeries;
  import org.apache.aurora.common.stats.TimeSeriesRepository;
  import org.apache.aurora.common.testing.easymock.EasyMockTest;
  import org.junit.Before;
  import org.junit.Test;
  
  import static org.easymock.EasyMock.expect;
  import static org.junit.Assert.assertEquals;
  
  public class TimeSeriesDataSourceTest extends EasyMockTest {
  
    private static final String TIME_COLUMN = TimeSeriesDataSource.TIME_METRIC;
    private static final String TIME_SERIES_1 = "time_series_1";
    private static final String TIME_SERIES_2 = "time_series_2";
  
    private static final List<Number> TIMESTAMPS = Arrays.<Number>asList(1d, 2d, 3d, 4d);
    private static final Map<String, TimeSeries> TS_DATA = ImmutableMap.of(
        TIME_SERIES_1, makeTimeSeries(TIME_SERIES_1, 1, 2, 3, 4),
        TIME_SERIES_2, makeTimeSeries(TIME_SERIES_2, 0, 0, 0, 0)
    );
  
    private final Gson gson = new Gson();
  
    private TimeSeriesDataSource dataSource;
    private TimeSeriesRepository timeSeriesRepo;
  
    @Before
    public void setUp() {
      timeSeriesRepo = createMock(TimeSeriesRepository.class);
      dataSource = new TimeSeriesDataSource(timeSeriesRepo);
    }
  
    @Test
    public void testGetColumns() throws Exception {
      expect(timeSeriesRepo.getAvailableSeries()).andReturn(TS_DATA.keySet());
  
      control.replay();
  
      List<String> columns = gson.fromJson(
          dataSource.getResponse(null, null),
          new TypeToken<List<String>>() { }.getType());
      assertEquals(ImmutableList.copyOf(TS_DATA.keySet()), columns);
    }
  
    @Test
    @SuppressWarnings("unchecked") // Needed because type information lost in vargs.
    public void testGetAllData() throws Exception {
      expect(timeSeriesRepo.getTimestamps()).andReturn(TIMESTAMPS);
      expect(timeSeriesRepo.get(TIME_SERIES_1)).andReturn(TS_DATA.get(TIME_SERIES_1));
      expect(timeSeriesRepo.get(TIME_SERIES_2)).andReturn(TS_DATA.get(TIME_SERIES_2));
  
      control.replay();
  
      String colString = Joiner.on(',').join(
          Arrays.asList(TIME_SERIES_1, TIME_SERIES_2, TIME_COLUMN));
  
      TimeSeriesDataSource.ResponseStruct response = gson.fromJson(
          dataSource.getResponse(colString, null),
          TimeSeriesDataSource.ResponseStruct.class);
  
      assertEquals(ImmutableList.of(TIME_COLUMN, TIME_SERIES_1, TIME_SERIES_2), response.names);
      Iterable<List<Number>> expectedData = Iterables2.zip(0,
          TIMESTAMPS, getSamples(TIME_SERIES_1), getSamples(TIME_SERIES_2));
      checkRows(expectedData, response.data);
    }
  
    @Test
    @SuppressWarnings("unchecked") // Needed because type information lost in vargs.
    public void testFilterByTime() throws Exception {
      expect(timeSeriesRepo.getTimestamps()).andReturn(TIMESTAMPS);
      expect(timeSeriesRepo.get(TIME_SERIES_1)).andReturn(TS_DATA.get(TIME_SERIES_1));
      expect(timeSeriesRepo.get(TIME_SERIES_2)).andReturn(TS_DATA.get(TIME_SERIES_2));
  
      control.replay();
  
      String colString = Joiner.on(',').join(
          Arrays.asList(TIME_SERIES_1, TIME_SERIES_2, TIME_COLUMN));
  
      TimeSeriesDataSource.ResponseStruct response = gson.fromJson(
          dataSource.getResponse(colString, "2"),
          TimeSeriesDataSource.ResponseStruct.class);
  
      Iterable<List<Number>> expectedData = Iterables2.zip(0,
          TIMESTAMPS, getSamples(TIME_SERIES_1), getSamples(TIME_SERIES_2));
      expectedData = Iterables.filter(expectedData, row -> row.get(0).intValue() >= 3);
  
      checkRows(expectedData, response.data);
    }
  
    private void checkRows(Iterable<List<Number>> expected, List<List<Number>> actual) {
      assertEquals(Iterables.size(expected), actual.size());
      Iterator<List<Number>> actualIterator = actual.iterator();
      for (List<Number> expectedRow : expected) {
        Iterator<Number> actualValueIterator = actualIterator.next().iterator();
        for (Number expectedValue : expectedRow) {
          assertEquals("Expected row data " + expected + ", found " + actual,
              expectedValue.doubleValue(),
              actualValueIterator.next().doubleValue(),
              1e-9);
        }
      }
    }
  
    private static Iterable<Number> getSamples(String tsName) {
      return TS_DATA.get(tsName).getSamples();
    }
  
    private static TimeSeries makeTimeSeries(final String name, final Number... values) {
      final List<Number> samples = Lists.newArrayList();
      for (Number value : values) samples.add(value.doubleValue());
  
      return new TimeSeries() {
        @Override public String getName() { return name; }
  
        @Override public Iterable<Number> getSamples() {
          return samples;
        }
      };
    }
  }
  