/* * Copyright 2015-present Facebook, Inc. * * 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 com.facebook.buck.event.listener; import static com.facebook.buck.event.TestEventConfigurator.configureTestEventAtTime; import static org.junit.Assert.assertThat; import com.facebook.buck.event.AbstractBuckEvent; import com.facebook.buck.event.BuckEvent; import com.facebook.buck.event.PerfEventId; import com.facebook.buck.event.SimplePerfEvent; import com.facebook.buck.event.external.events.BuckEventExternalInterface; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableMap; import java.util.ArrayDeque; import java.util.Deque; import java.util.concurrent.TimeUnit; import org.hamcrest.Matchers; import org.junit.Test; public class BuckEventOrdererTest { private static final long THREAD_ONE = 1; private static final long THREAD_TWO = 2; private static final long MAX_SKEW = 10; private Deque<BuckEvent> serializedEvents = new ArrayDeque<>(); private java.util.function.Consumer<BuckEvent> addToSerializedEventsFunction = serializedEvents::add; @Test public void testMergesSingleSetOfSerialEvents() { BuckEvent first = createUniqueEvent(0, TimeUnit.MILLISECONDS, THREAD_ONE); BuckEvent second = createUniqueEvent(5, TimeUnit.MILLISECONDS, THREAD_ONE); try (BuckEventOrderer<BuckEvent> orderer = new BuckEventOrderer<>(addToSerializedEventsFunction, MAX_SKEW, TimeUnit.MILLISECONDS)) { orderer.add(first); orderer.add(second); } assertThat(serializedEvents, Matchers.contains(first, second)); } @Test public void testReordersEventsWithinSkewWindow() { BuckEvent first = createUniqueEvent(0, TimeUnit.MILLISECONDS, THREAD_ONE); BuckEvent second = createUniqueEvent(5, TimeUnit.MILLISECONDS, THREAD_ONE); try (BuckEventOrderer<BuckEvent> orderer = new BuckEventOrderer<>(addToSerializedEventsFunction, MAX_SKEW, TimeUnit.MILLISECONDS)) { orderer.add(second); orderer.add(first); } assertThat(serializedEvents, Matchers.contains(first, second)); } @Test public void testPreservesInsertionOrderForSameTimestamp() { BuckEvent first = createUniqueEvent(0, TimeUnit.MILLISECONDS, THREAD_ONE); BuckEvent second = createUniqueEvent(0, TimeUnit.MILLISECONDS, THREAD_ONE); BuckEvent third = createUniqueEvent(0, TimeUnit.MILLISECONDS, THREAD_ONE); try (BuckEventOrderer<BuckEvent> orderer = new BuckEventOrderer<>(addToSerializedEventsFunction, MAX_SKEW, TimeUnit.MILLISECONDS)) { orderer.add(first); orderer.add(second); orderer.add(third); } assertThat(serializedEvents, Matchers.contains(first, second, third)); } @Test public void testPreservesInsertionOrderForSameTimestampWithReorder() { BuckEvent first = createUniqueEvent(1, TimeUnit.MILLISECONDS, THREAD_ONE); BuckEvent second = createUniqueEvent(2, TimeUnit.MILLISECONDS, THREAD_ONE); BuckEvent third = createUniqueEvent(2, TimeUnit.MILLISECONDS, THREAD_ONE); BuckEvent fourth = createUniqueEvent(2, TimeUnit.MILLISECONDS, THREAD_ONE); try (BuckEventOrderer<BuckEvent> orderer = new BuckEventOrderer<>(addToSerializedEventsFunction, MAX_SKEW, TimeUnit.MILLISECONDS)) { orderer.add(second); orderer.add(third); orderer.add(fourth); orderer.add(first); } assertThat(serializedEvents, Matchers.contains(first, second, third, fourth)); } @Test public void testPreservesInsertionOrderForSameTimestampWithReverseReorder() { BuckEvent first = createUniqueEvent(0, TimeUnit.MILLISECONDS, THREAD_ONE); BuckEvent second = createUniqueEvent(0, TimeUnit.MILLISECONDS, THREAD_ONE); BuckEvent third = createUniqueEvent(0, TimeUnit.MILLISECONDS, THREAD_ONE); BuckEvent fourth = createUniqueEvent(5, TimeUnit.MILLISECONDS, THREAD_ONE); try (BuckEventOrderer<BuckEvent> orderer = new BuckEventOrderer<>(addToSerializedEventsFunction, MAX_SKEW, TimeUnit.MILLISECONDS)) { orderer.add(fourth); orderer.add(first); orderer.add(second); orderer.add(third); } assertThat(serializedEvents, Matchers.contains(first, second, third, fourth)); } @Test public void testMergesTwoSetsOfSerialEvents() { BuckEvent first = createUniqueEvent(0, TimeUnit.MILLISECONDS, THREAD_ONE); BuckEvent second = createUniqueEvent(1, TimeUnit.MILLISECONDS, THREAD_TWO); BuckEvent third = createUniqueEvent(2, TimeUnit.MILLISECONDS, THREAD_ONE); BuckEvent fourth = createUniqueEvent(3, TimeUnit.MILLISECONDS, THREAD_TWO); try (BuckEventOrderer<BuckEvent> orderer = new BuckEventOrderer<>(addToSerializedEventsFunction, MAX_SKEW, TimeUnit.MILLISECONDS)) { orderer.add(second); orderer.add(fourth); orderer.add(first); orderer.add(third); } assertThat(serializedEvents, Matchers.contains(first, second, third, fourth)); } @Test public void testMergesTwoInterleavedEventSeries() { BuckEvent first = createUniqueEvent(0, TimeUnit.MILLISECONDS, THREAD_ONE); BuckEvent second = createUniqueEvent(1, TimeUnit.MILLISECONDS, THREAD_TWO); BuckEvent third = createUniqueEvent(2, TimeUnit.MILLISECONDS, THREAD_ONE); BuckEvent fourth = createUniqueEvent(3, TimeUnit.MILLISECONDS, THREAD_TWO); try (BuckEventOrderer<BuckEvent> orderer = new BuckEventOrderer<>(addToSerializedEventsFunction, MAX_SKEW, TimeUnit.MILLISECONDS)) { orderer.add(second); orderer.add(first); orderer.add(fourth); orderer.add(third); } assertThat(serializedEvents, Matchers.contains(first, second, third, fourth)); } @Test public void testMergesSingleEventAtStartCorrectly() { BuckEvent first = createUniqueEvent(0, TimeUnit.MILLISECONDS, THREAD_ONE); BuckEvent second = createUniqueEvent(1, TimeUnit.MILLISECONDS, THREAD_TWO); BuckEvent third = createUniqueEvent(2, TimeUnit.MILLISECONDS, THREAD_ONE); try (BuckEventOrderer<BuckEvent> orderer = new BuckEventOrderer<>(addToSerializedEventsFunction, MAX_SKEW, TimeUnit.MILLISECONDS)) { orderer.add(second); orderer.add(first); orderer.add(third); } assertThat(serializedEvents, Matchers.contains(first, second, third)); } @Test public void testMergesSingleEventAtEndCorrectly() { BuckEvent first = createUniqueEvent(0, TimeUnit.MILLISECONDS, THREAD_ONE); BuckEvent second = createUniqueEvent(1, TimeUnit.MILLISECONDS, THREAD_TWO); BuckEvent third = createUniqueEvent(2, TimeUnit.MILLISECONDS, THREAD_ONE); try (BuckEventOrderer<BuckEvent> orderer = new BuckEventOrderer<>(addToSerializedEventsFunction, MAX_SKEW, TimeUnit.MILLISECONDS)) { orderer.add(first); orderer.add(third); orderer.add(second); } assertThat(serializedEvents, Matchers.contains(first, second, third)); } @Test public void testPutsEventInSinkAsSoonAsPossible() { try (BuckEventOrderer<BuckEvent> orderer = new BuckEventOrderer<>(addToSerializedEventsFunction, MAX_SKEW, TimeUnit.MILLISECONDS)) { orderer.add(createUniqueEvent(0, TimeUnit.MILLISECONDS, THREAD_ONE)); orderer.add(createUniqueEvent(5, TimeUnit.MILLISECONDS, THREAD_ONE)); orderer.add(createUniqueEvent(MAX_SKEW + 1, TimeUnit.MILLISECONDS, THREAD_TWO)); assertThat( FluentIterable.from(serializedEvents).transform(BuckEventExternalInterface::getTimestamp), Matchers.contains(0L)); orderer.add(createUniqueEvent(5 + MAX_SKEW + 1, TimeUnit.MILLISECONDS, THREAD_ONE)); assertThat( FluentIterable.from(serializedEvents).transform(BuckEventExternalInterface::getTimestamp), Matchers.contains(0L, 5L)); } assertThat( FluentIterable.from(serializedEvents).transform(BuckEventExternalInterface::getTimestamp), Matchers.contains(0L, 5L, MAX_SKEW + 1, 5 + MAX_SKEW + 1)); } private static int seqNo = 0; private BuckEvent createUniqueEvent(long timeInMs, TimeUnit timeUnit, long threadId) { return configureTestEventAtTime( (AbstractBuckEvent) SimplePerfEvent.started( PerfEventId.of("BuckEventOrdererTest"), ImmutableMap.of( "seqNo", seqNo++, "time", timeInMs, "thread", threadId)), timeInMs, timeUnit, threadId); } }