/*
* 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;
import static org.junit.Assert.assertThat;
import com.facebook.buck.timing.SettableFakeClock;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.eventbus.Subscribe;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import org.hamcrest.Matchers;
import org.junit.Test;
public class SimplePerfEventTest {
private void assertPerfEvent(
BuckEvent event,
PerfEventId id,
SimplePerfEvent.Type type,
ImmutableMap<String, String> info) {
assertThat(event, Matchers.instanceOf(SimplePerfEvent.class));
SimplePerfEvent perfEvent = (SimplePerfEvent) event;
assertThat(perfEvent.getEventId(), Matchers.equalTo(id));
assertThat(perfEvent.getEventType(), Matchers.equalTo(type));
assertThat(
Maps.transformValues(perfEvent.getEventInfo(), Object::toString),
Matchers.equalTo((Map<String, String>) info));
}
@Test
public void testManuallyCreatedStartEvents() {
PerfEventId testEventId = PerfEventId.of("Test");
assertPerfEvent(
SimplePerfEvent.started(testEventId),
testEventId,
SimplePerfEvent.Type.STARTED,
ImmutableMap.of());
assertPerfEvent(
SimplePerfEvent.started(testEventId, "k1", "v1"),
testEventId,
SimplePerfEvent.Type.STARTED,
ImmutableMap.of("k1", "v1"));
assertPerfEvent(
SimplePerfEvent.started(testEventId, "k1", "v1", "k2", "v2"),
testEventId,
SimplePerfEvent.Type.STARTED,
ImmutableMap.of("k1", "v1", "k2", "v2"));
assertPerfEvent(
SimplePerfEvent.started(testEventId, ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3")),
testEventId,
SimplePerfEvent.Type.STARTED,
ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3"));
}
private SimplePerfEvent.Started newStartedEvent(PerfEventId testEventId) {
return SimplePerfEvent.started(testEventId, "XX", "YY");
}
@Test
public void testManuallyCreatedUpdateEvents() {
PerfEventId testEventId = PerfEventId.of("Test");
// Info from the started event does not get folded into the update/finished ones.
assertPerfEvent(
newStartedEvent(testEventId).createUpdateEvent(ImmutableMap.of()),
testEventId,
SimplePerfEvent.Type.UPDATED,
ImmutableMap.of());
assertPerfEvent(
newStartedEvent(testEventId).createUpdateEvent("k1", "v1"),
testEventId,
SimplePerfEvent.Type.UPDATED,
ImmutableMap.of("k1", "v1"));
assertPerfEvent(
newStartedEvent(testEventId).createUpdateEvent("k1", "v1", "k2", "v2"),
testEventId,
SimplePerfEvent.Type.UPDATED,
ImmutableMap.of("k1", "v1", "k2", "v2"));
assertPerfEvent(
newStartedEvent(testEventId)
.createUpdateEvent(ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3")),
testEventId,
SimplePerfEvent.Type.UPDATED,
ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3"));
}
@Test
public void testManuallyCreatedFinshedEvents() {
PerfEventId testEventId = PerfEventId.of("Test");
assertPerfEvent(
newStartedEvent(testEventId).createFinishedEvent(ImmutableMap.of()),
testEventId,
SimplePerfEvent.Type.FINISHED,
ImmutableMap.of());
assertPerfEvent(
newStartedEvent(testEventId).createFinishedEvent("k1", "v1"),
testEventId,
SimplePerfEvent.Type.FINISHED,
ImmutableMap.of("k1", "v1"));
assertPerfEvent(
newStartedEvent(testEventId).createFinishedEvent("k1", "v1", "k2", "v2"),
testEventId,
SimplePerfEvent.Type.FINISHED,
ImmutableMap.of("k1", "v1", "k2", "v2"));
assertPerfEvent(
newStartedEvent(testEventId)
.createFinishedEvent(ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3")),
testEventId,
SimplePerfEvent.Type.FINISHED,
ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3"));
}
@Test(expected = IllegalStateException.class)
public void testThrowsOnDoubleFinish() {
SimplePerfEvent.Started started = newStartedEvent(PerfEventId.of("test"));
started.createFinishedEvent();
started.createFinishedEvent();
}
private static class SimplePerfEventListener {
private ImmutableList.Builder<SimplePerfEvent> perfEventBuilder = ImmutableList.builder();
public ImmutableList<SimplePerfEvent> getPerfEvents() {
return perfEventBuilder.build();
}
@Subscribe
public void buckEvent(SimplePerfEvent perfEvent) {
perfEventBuilder.add(perfEvent);
}
}
@Test
public void testScopedEvents() {
PerfEventId testEventId = PerfEventId.of("Unicorn");
SimplePerfEventListener listener = new SimplePerfEventListener();
BuckEventBus eventBus = BuckEventBusFactory.newInstance();
eventBus.register(listener);
// This does absolutely nothing, but shouldn't crash either.
try (SimplePerfEvent.Scope scope = SimplePerfEvent.scope(Optional.empty(), testEventId)) {
scope.appendFinishedInfo("finished", "info");
scope.update(ImmutableMap.of("update", "updateValue"));
}
try (SimplePerfEvent.Scope scope = SimplePerfEvent.scope(eventBus, testEventId)) {
scope.appendFinishedInfo("finished", "info");
scope.update(ImmutableMap.of("update", "updateValue"));
scope.update(ImmutableMap.of("update", "laterUpdate"));
}
ImmutableList<SimplePerfEvent> perfEvents = listener.getPerfEvents();
assertThat(perfEvents, Matchers.hasSize(4));
assertPerfEvent(
perfEvents.get(0), testEventId, SimplePerfEvent.Type.STARTED, ImmutableMap.of());
assertPerfEvent(
perfEvents.get(1),
testEventId,
SimplePerfEvent.Type.UPDATED,
ImmutableMap.of("update", "updateValue"));
assertPerfEvent(
perfEvents.get(2),
testEventId,
SimplePerfEvent.Type.UPDATED,
ImmutableMap.of("update", "laterUpdate"));
assertPerfEvent(
perfEvents.get(3),
testEventId,
SimplePerfEvent.Type.FINISHED,
ImmutableMap.of("finished", "info"));
}
@Test
public void testMinimumTimeScope() throws Exception {
PerfEventId ignoredEventId = PerfEventId.of("IgnoreMe");
PerfEventId loggedEventId = PerfEventId.of("LogMe");
PerfEventId parentId = PerfEventId.of("Parent");
SimplePerfEventListener listener = new SimplePerfEventListener();
SettableFakeClock clock = new SettableFakeClock(0L, 0L);
BuckEventBus eventBus = BuckEventBusFactory.newInstance(clock);
eventBus.register(listener);
try (SimplePerfEvent.Scope parent = SimplePerfEvent.scope(eventBus, parentId)) {
clock.advanceTimeNanos(10L);
try (SimplePerfEvent.Scope scope =
SimplePerfEvent.scopeIgnoringShortEvents(
eventBus, ignoredEventId, parent, 1, TimeUnit.SECONDS)) {
clock.advanceTimeNanos(10L);
}
clock.advanceTimeNanos(10L);
try (SimplePerfEvent.Scope scope =
SimplePerfEvent.scopeIgnoringShortEvents(
eventBus, loggedEventId, parent, 1, TimeUnit.MILLISECONDS)) {
clock.advanceTimeNanos(TimeUnit.MILLISECONDS.toNanos(2));
}
}
ImmutableList<SimplePerfEvent> perfEvents = listener.getPerfEvents();
assertThat(perfEvents, Matchers.hasSize(4));
assertPerfEvent(perfEvents.get(0), parentId, SimplePerfEvent.Type.STARTED, ImmutableMap.of());
assertPerfEvent(
perfEvents.get(1), loggedEventId, SimplePerfEvent.Type.STARTED, ImmutableMap.of());
assertPerfEvent(
perfEvents.get(2), loggedEventId, SimplePerfEvent.Type.FINISHED, ImmutableMap.of());
assertPerfEvent(
perfEvents.get(3),
parentId,
SimplePerfEvent.Type.FINISHED,
ImmutableMap.of(
"IgnoreMe_accumulated_count", "1",
"IgnoreMe_accumulated_duration_ns", "10"));
}
}