/* * 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 com.facebook.buck.event.LeafEvent; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.rules.TestStatusMessageEvent; import com.facebook.buck.rules.TestSummaryEvent; import com.facebook.buck.test.TestRuleEvent; import com.facebook.buck.util.Ansi; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import java.util.Map; import java.util.Optional; import java.util.logging.Level; public class TestThreadStateRenderer implements MultiStateRenderer { private static final Level MIN_LOG_LEVEL = Level.INFO; private final CommonThreadStateRenderer commonThreadStateRenderer; private final ImmutableMap<Long, ThreadRenderingInformation> threadInformationMap; public TestThreadStateRenderer( Ansi ansi, Function<Long, String> formatTimeFunction, long currentTimeMs, Map<Long, Optional<? extends TestSummaryEvent>> testSummariesByThread, Map<Long, Optional<? extends TestStatusMessageEvent>> testStatusMessagesByThread, Map<Long, Optional<? extends LeafEvent>> runningStepsByThread, BuildRuleThreadTracker buildRuleThreadTracker) { this.threadInformationMap = getThreadInformationMap( currentTimeMs, testSummariesByThread, testStatusMessagesByThread, runningStepsByThread, buildRuleThreadTracker); this.commonThreadStateRenderer = new CommonThreadStateRenderer( ansi, formatTimeFunction, currentTimeMs, threadInformationMap); } private static ImmutableMap<Long, ThreadRenderingInformation> getThreadInformationMap( long currentTimeMs, Map<Long, Optional<? extends TestSummaryEvent>> testSummariesByThread, Map<Long, Optional<? extends TestStatusMessageEvent>> testStatusMessagesByThread, Map<Long, Optional<? extends LeafEvent>> runningStepsByThread, BuildRuleThreadTracker buildRuleThreadTracker) { ImmutableMap.Builder<Long, ThreadRenderingInformation> threadInformationMapBuilder = ImmutableMap.builder(); Map<Long, Optional<? extends TestRuleEvent>> testEventsByThread = buildRuleThreadTracker.getTestEventsByThread(); ImmutableList<Long> threadIds = ImmutableList.copyOf(testEventsByThread.keySet()); for (long threadId : threadIds) { Optional<? extends TestRuleEvent> testRuleEvent = testEventsByThread.get(threadId); if (testRuleEvent == null) { continue; } Optional<BuildTarget> buildTarget = Optional.empty(); long elapsedTimeMs = 0; if (testRuleEvent.isPresent()) { buildTarget = Optional.of(testRuleEvent.get().getBuildTarget()); elapsedTimeMs = currentTimeMs - testRuleEvent.get().getTimestamp(); } threadInformationMapBuilder.put( threadId, new ThreadRenderingInformation( buildTarget, testRuleEvent, testSummariesByThread.getOrDefault(threadId, Optional.empty()), testStatusMessagesByThread.getOrDefault(threadId, Optional.empty()), runningStepsByThread.getOrDefault(threadId, Optional.empty()), elapsedTimeMs)); } return threadInformationMapBuilder.build(); } @Override public String getExecutorCollectionLabel() { return "THREADS"; } @Override public int getExecutorCount() { return commonThreadStateRenderer.getThreadCount(); } @Override public ImmutableList<Long> getSortedExecutorIds(boolean sortByTime) { return commonThreadStateRenderer.getSortedThreadIds(sortByTime); } @Override public String renderStatusLine(long threadID, StringBuilder lineBuilder) { ThreadRenderingInformation threadInformation = Preconditions.checkNotNull(threadInformationMap.get(threadID)); Optional<String> stepCategory = Optional.empty(); Optional<? extends LeafEvent> runningStep = Optional.empty(); if (threadInformation.getTestStatusMessage().isPresent() && threadInformation .getTestStatusMessage() .get() .getTestStatusMessage() .getLevel() .intValue() >= MIN_LOG_LEVEL.intValue()) { stepCategory = Optional.of( threadInformation.getTestStatusMessage().get().getTestStatusMessage().getMessage()); runningStep = threadInformation.getTestStatusMessage(); } else if (threadInformation.getTestSummary().isPresent()) { stepCategory = Optional.of(threadInformation.getTestSummary().get().getTestName()); runningStep = threadInformation.getTestSummary(); } else if (threadInformation.getRunningStep().isPresent()) { stepCategory = Optional.of(threadInformation.getRunningStep().get().getCategory()); runningStep = threadInformation.getRunningStep(); } return commonThreadStateRenderer.renderLine( threadInformation.getBuildTarget(), threadInformation.getStartEvent(), runningStep, stepCategory, Optional.empty(), threadInformation.getElapsedTimeMs(), lineBuilder); } @Override public String renderShortStatus(long threadId) { ThreadRenderingInformation threadInformation = Preconditions.checkNotNull(threadInformationMap.get(threadId)); return commonThreadStateRenderer.renderShortStatus( threadInformation.getBuildTarget().isPresent(), /* renderSubtle = */ false, threadInformation.getElapsedTimeMs()); } }