package com.spotify.heroic; import static org.junit.Assert.assertEquals; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.spotify.heroic.common.DateRange; import com.spotify.heroic.common.Series; import com.spotify.heroic.metric.FetchData; import com.spotify.heroic.metric.FetchQuotaWatcher; import com.spotify.heroic.metric.MetricCollection; import com.spotify.heroic.metric.MetricType; import com.spotify.heroic.metric.Point; import com.spotify.heroic.metric.WriteMetric; import eu.toolchain.async.AsyncFuture; import eu.toolchain.async.ClockSource; import eu.toolchain.async.RetryPolicy; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.function.Consumer; import org.junit.Before; import org.junit.Test; public abstract class AbstractConsumerIT extends AbstractSingleNodeIT { public static final RetryPolicy RETRY_POLICY = RetryPolicy.timed(1000, RetryPolicy.exponential(10, 100)); protected boolean expectAtLeastOneCommit = false; protected Consumer<WriteMetric.Request> consumer; protected abstract Consumer<WriteMetric.Request> setupConsumer(); @Before public void basicSetup() { this.consumer = setupConsumer(); this.expectAtLeastOneCommit = false; } @Test public void consumeOneMessage() throws Exception { final Series s1 = Series.of("s1", ImmutableMap.of("host", "localhost")); final MetricCollection mc = MetricCollection.points(ImmutableList.of(new Point(10, 42), new Point(20, 43))); WriteMetric.Request request = new WriteMetric.Request(s1, mc); consumer.accept(request); tryUntil(() -> { AsyncFuture<FetchData> fetchData = instance.inject(coreComponent -> { FetchData.Request fetchDataRequest = new FetchData.Request(MetricType.POINT, s1, new DateRange(0, 100), QueryOptions.defaults()); return coreComponent .metricManager() .useDefaultGroup() .fetch(fetchDataRequest, FetchQuotaWatcher.NO_QUOTA); }); FetchData data = fetchData.get(); assertEquals(ImmutableList.of(mc), data.getGroups()); return null; }); } @Test public void consumeManyMessages() throws Exception { expectAtLeastOneCommit = true; final Series s1 = Series.of("s1", ImmutableMap.of("host", "localhost")); List<Point> consumedPoints = new ArrayList<>(); for (int count = 1; count <= 10; count++) { Point p = new Point(count, 42); final MetricCollection mc = MetricCollection.points(ImmutableList.of(p)); consumedPoints.add(p); WriteMetric.Request request = new WriteMetric.Request(s1, mc); consumer.accept(request); Thread.sleep(100); } tryUntil(() -> { AsyncFuture<FetchData> fetchData = instance.inject(coreComponent -> { FetchData.Request fetchDataRequest = new FetchData.Request(MetricType.POINT, s1, new DateRange(0, 100), QueryOptions.defaults()); return coreComponent .metricManager() .useDefaultGroup() .fetch(fetchDataRequest, FetchQuotaWatcher.NO_QUOTA); }); FetchData data = fetchData.get(); assertEquals(ImmutableList.of(MetricCollection.points(consumedPoints)), data.getGroups()); return null; }); } public void tryUntil(Callable<Void> callable) throws Exception { RetryPolicy.Instance instance = RETRY_POLICY.apply(ClockSource.SYSTEM); List<Throwable> supressed = new ArrayList<>(); while (true) { try { callable.call(); } catch (AssertionError e) { RetryPolicy.Decision decision = instance.next(); if (!decision.shouldRetry()) { supressed.forEach(e::addSuppressed); throw e; } supressed.add(e); Thread.sleep(decision.backoff()); continue; } break; } } }