Open source some skyframe/bazel tests.
--
MOS_MIGRATED_REVID=106308990
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java b/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
new file mode 100644
index 0000000..abd081c
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
@@ -0,0 +1,385 @@
+// Copyright 2015 The Bazel Authors. All rights reserved.
+//
+// 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.google.devtools.build.lib.skyframe;
+
+import static com.google.devtools.build.lib.actions.util.ActionCacheTestHelper.AMNESIAC_CACHE;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Range;
+import com.google.common.collect.Sets;
+import com.google.common.eventbus.EventBus;
+import com.google.devtools.build.lib.actions.Action;
+import com.google.devtools.build.lib.actions.ActionCacheChecker;
+import com.google.devtools.build.lib.actions.ActionExecutionStatusReporter;
+import com.google.devtools.build.lib.actions.ActionLogBufferPathGenerator;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.BuildFailedException;
+import com.google.devtools.build.lib.actions.Executor;
+import com.google.devtools.build.lib.actions.ResourceManager;
+import com.google.devtools.build.lib.actions.ResourceSet;
+import com.google.devtools.build.lib.actions.Root;
+import com.google.devtools.build.lib.actions.TestExecException;
+import com.google.devtools.build.lib.actions.cache.ActionCache;
+import com.google.devtools.build.lib.actions.util.DummyExecutor;
+import com.google.devtools.build.lib.actions.util.TestAction;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.buildtool.SkyframeBuilder;
+import com.google.devtools.build.lib.events.Reporter;
+import com.google.devtools.build.lib.events.StoredEventHandler;
+import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
+import com.google.devtools.build.lib.skyframe.ActionExecutionFunction;
+import com.google.devtools.build.lib.skyframe.ActionLookupValue;
+import com.google.devtools.build.lib.skyframe.ArtifactFunction;
+import com.google.devtools.build.lib.skyframe.ArtifactValue;
+import com.google.devtools.build.lib.skyframe.AspectValue;
+import com.google.devtools.build.lib.skyframe.Builder;
+import com.google.devtools.build.lib.skyframe.ExternalFilesHelper;
+import com.google.devtools.build.lib.skyframe.FileFunction;
+import com.google.devtools.build.lib.skyframe.FileStateFunction;
+import com.google.devtools.build.lib.skyframe.PrecomputedValue;
+import com.google.devtools.build.lib.skyframe.SkyFunctions;
+import com.google.devtools.build.lib.skyframe.SkyframeActionExecutor;
+import com.google.devtools.build.lib.testutil.FoundationTestCase;
+import com.google.devtools.build.lib.testutil.TestUtils;
+import com.google.devtools.build.lib.util.AbruptExitException;
+import com.google.devtools.build.lib.util.BlazeClock;
+import com.google.devtools.build.lib.util.Clock;
+import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
+import com.google.devtools.build.lib.vfs.FileSystem;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.skyframe.CycleInfo;
+import com.google.devtools.build.skyframe.ErrorInfo;
+import com.google.devtools.build.skyframe.EvaluationProgressReceiver;
+import com.google.devtools.build.skyframe.EvaluationResult;
+import com.google.devtools.build.skyframe.InMemoryMemoizingEvaluator;
+import com.google.devtools.build.skyframe.RecordingDifferencer;
+import com.google.devtools.build.skyframe.SequentialBuildDriver;
+import com.google.devtools.build.skyframe.SkyFunctionName;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.annotation.Nullable;
+
+/**
+ * The common code that's shared between various builder tests.
+ */
+public abstract class TimestampBuilderTestCase extends FoundationTestCase {
+
+ private static final SkyKey OWNER_KEY = new SkyKey(SkyFunctions.ACTION_LOOKUP, "OWNER");
+ protected static final ActionLookupValue.ActionLookupKey ALL_OWNER =
+ new SingletonActionLookupKey();
+ protected static final Predicate<Action> ALWAYS_EXECUTE_FILTER = Predicates.alwaysTrue();
+ protected static final String CYCLE_MSG = "Yarrrr, there be a cycle up in here";
+
+ protected Clock clock = BlazeClock.instance();
+ protected TimestampGranularityMonitor tsgm;
+ protected RecordingDifferencer differencer = new RecordingDifferencer();
+ private Set<Action> actions;
+
+ protected AtomicReference<EventBus> eventBusRef = new AtomicReference<>();
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ inMemoryCache = new InMemoryActionCache();
+ tsgm = new TimestampGranularityMonitor(clock);
+ ResourceManager.instance().setAvailableResources(ResourceSet.createWithRamCpuIo(100, 1, 1));
+ actions = new HashSet<>();
+ }
+
+ protected void clearActions() {
+ actions.clear();
+ }
+
+ protected <T extends Action> T registerAction(T action) {
+ actions.add(action);
+ return action;
+ }
+
+ protected Builder createBuilder(ActionCache actionCache) {
+ return createBuilder(actionCache, 1, /*keepGoing=*/ false);
+ }
+
+ /**
+ * Create a ParallelBuilder with a DatabaseDependencyChecker using the
+ * specified ActionCache.
+ */
+ protected Builder createBuilder(
+ final ActionCache actionCache, final int threadCount, final boolean keepGoing) {
+ return createBuilder(actionCache, threadCount, keepGoing, null);
+ }
+
+ protected Builder createBuilder(
+ final ActionCache actionCache,
+ final int threadCount,
+ final boolean keepGoing,
+ @Nullable EvaluationProgressReceiver evaluationProgressReceiver) {
+ AtomicReference<PathPackageLocator> pkgLocator =
+ new AtomicReference<>(new PathPackageLocator());
+ ExternalFilesHelper externalFilesHelper = new ExternalFilesHelper(pkgLocator);
+ differencer = new RecordingDifferencer();
+
+ ActionExecutionStatusReporter statusReporter =
+ ActionExecutionStatusReporter.create(new StoredEventHandler());
+ final SkyframeActionExecutor skyframeActionExecutor =
+ new SkyframeActionExecutor(
+ ResourceManager.instance(), eventBusRef, new AtomicReference<>(statusReporter));
+
+ skyframeActionExecutor.setActionLogBufferPathGenerator(
+ new ActionLogBufferPathGenerator(actionOutputBase));
+
+ final InMemoryMemoizingEvaluator evaluator =
+ new InMemoryMemoizingEvaluator(
+ ImmutableMap.of(
+ SkyFunctions.FILE_STATE,
+ new FileStateFunction(tsgm, externalFilesHelper),
+ SkyFunctions.FILE,
+ new FileFunction(pkgLocator, tsgm, externalFilesHelper),
+ SkyFunctions.ARTIFACT,
+ new ArtifactFunction(Predicates.<PathFragment>alwaysFalse()),
+ SkyFunctions.ACTION_EXECUTION,
+ new ActionExecutionFunction(skyframeActionExecutor, tsgm)),
+ differencer,
+ evaluationProgressReceiver);
+ final SequentialBuildDriver driver = new SequentialBuildDriver(evaluator);
+ PrecomputedValue.BUILD_ID.set(differencer, UUID.randomUUID());
+
+ return new Builder() {
+ private void setGeneratingActions() {
+ if (evaluator.getExistingValueForTesting(OWNER_KEY) == null) {
+ differencer.inject(ImmutableMap.of(OWNER_KEY, new ActionLookupValue(actions)));
+ }
+ }
+
+ @Override
+ public void buildArtifacts(
+ Reporter reporter,
+ Set<Artifact> artifacts,
+ Set<ConfiguredTarget> parallelTests,
+ Set<ConfiguredTarget> exclusiveTests,
+ Collection<ConfiguredTarget> targetsToBuild,
+ Collection<AspectValue> aspects,
+ Executor executor,
+ Set<ConfiguredTarget> builtTargets,
+ boolean explain,
+ Range<Long> lastExecutionTimeRange)
+ throws BuildFailedException, AbruptExitException, InterruptedException,
+ TestExecException {
+ skyframeActionExecutor.prepareForExecution(
+ reporter,
+ executor,
+ keepGoing, /*explain=*/
+ false,
+ new ActionCacheChecker(actionCache, null, ALWAYS_EXECUTE_FILTER, false));
+
+ List<SkyKey> keys = new ArrayList<>();
+ for (Artifact artifact : artifacts) {
+ keys.add(ArtifactValue.key(artifact, true));
+ }
+
+ setGeneratingActions();
+ EvaluationResult<SkyValue> result = driver.evaluate(keys, keepGoing, threadCount, reporter);
+
+ if (result.hasError()) {
+ boolean hasCycles = false;
+ for (Map.Entry<SkyKey, ErrorInfo> entry : result.errorMap().entrySet()) {
+ Iterable<CycleInfo> cycles = entry.getValue().getCycleInfo();
+ hasCycles |= !Iterables.isEmpty(cycles);
+ }
+ if (hasCycles) {
+ throw new BuildFailedException(CYCLE_MSG);
+ } else if (result.errorMap().isEmpty() || keepGoing) {
+ throw new BuildFailedException();
+ } else {
+ SkyframeBuilder.rethrow(Preconditions.checkNotNull(result.getError().getException()));
+ }
+ }
+ }
+ };
+ }
+
+ /** A non-persistent cache. */
+ protected InMemoryActionCache inMemoryCache;
+
+ /** A class that records an event. */
+ protected static class Button implements Runnable {
+ protected boolean pressed = false;
+
+ @Override
+ public void run() {
+ pressed = true;
+ }
+ }
+
+ /** A class that counts occurrences of an event. */
+ static class Counter implements Runnable {
+ int count = 0;
+
+ @Override
+ public void run() {
+ count++;
+ }
+ }
+
+ Artifact createSourceArtifact(String name) {
+ return createSourceArtifact(scratch.getFileSystem(), name);
+ }
+
+ Artifact createSourceArtifact(FileSystem fs, String name) {
+ Path root = fs.getPath(TestUtils.tmpDir());
+ return new Artifact(new PathFragment(name), Root.asSourceRoot(root));
+ }
+
+ protected Artifact createDerivedArtifact(String name) {
+ return createDerivedArtifact(scratch.getFileSystem(), name);
+ }
+
+ Artifact createDerivedArtifact(FileSystem fs, String name) {
+ Path execRoot = fs.getPath(TestUtils.tmpDir());
+ PathFragment execPath = new PathFragment("out").getRelative(name);
+ Path path = execRoot.getRelative(execPath);
+ return new Artifact(
+ path, Root.asDerivedRoot(execRoot, execRoot.getRelative("out")), execPath, ALL_OWNER);
+ }
+
+ /**
+ * Creates and returns a new "amnesiac" builder based on the amnesiac cache.
+ */
+ protected Builder amnesiacBuilder() {
+ return createBuilder(AMNESIAC_CACHE);
+ }
+
+ /**
+ * Creates and returns a new caching builder based on the inMemoryCache.
+ */
+ protected Builder cachingBuilder() {
+ return createBuilder(inMemoryCache);
+ }
+
+ /**
+ * Creates a TestAction from 'inputs' to 'outputs', and a new button, such
+ * that executing the action causes the button to be pressed. The button is
+ * returned.
+ */
+ protected Button createActionButton(Collection<Artifact> inputs, Collection<Artifact> outputs) {
+ Button button = new Button();
+ registerAction(new TestAction(button, inputs, outputs));
+ return button;
+ }
+
+ /**
+ * Creates a TestAction from 'inputs' to 'outputs', and a new counter, such
+ * that executing the action causes the counter to be incremented. The
+ * counter is returned.
+ */
+ protected Counter createActionCounter(Collection<Artifact> inputs, Collection<Artifact> outputs) {
+ Counter counter = new Counter();
+ registerAction(new TestAction(counter, inputs, outputs));
+ return counter;
+ }
+
+ protected static Set<Artifact> emptySet = Collections.emptySet();
+
+ protected void buildArtifacts(Builder builder, Artifact... artifacts)
+ throws BuildFailedException, AbruptExitException, InterruptedException, TestExecException {
+
+ tsgm.setCommandStartTime();
+ Set<Artifact> artifactsToBuild = Sets.newHashSet(artifacts);
+ Set<ConfiguredTarget> builtArtifacts = new HashSet<>();
+ try {
+ builder.buildArtifacts(
+ reporter,
+ artifactsToBuild,
+ null,
+ null,
+ null,
+ null,
+ new DummyExecutor(rootDirectory),
+ builtArtifacts, /*explain=*/
+ false,
+ null);
+ } finally {
+ tsgm.waitForTimestampGranularity(reporter.getOutErr());
+ }
+ }
+
+ protected static class InMemoryActionCache implements ActionCache {
+
+ private final Map<String, Entry> actionCache = new HashMap<>();
+
+ @Override
+ public synchronized void put(String key, ActionCache.Entry entry) {
+ actionCache.put(key, entry);
+ }
+
+ @Override
+ public synchronized Entry get(String key) {
+ return actionCache.get(key);
+ }
+
+ @Override
+ public synchronized void remove(String key) {
+ actionCache.remove(key);
+ }
+
+ @Override
+ public Entry createEntry(String key) {
+ return new ActionCache.Entry(key);
+ }
+
+ public synchronized void reset() {
+ actionCache.clear();
+ }
+
+ @Override
+ public long save() {
+ // safe to ignore
+ return 0;
+ }
+
+ @Override
+ public void dump(PrintStream out) {
+ out.println("In-memory action cache has " + actionCache.size() + " records");
+ }
+ }
+
+ private static class SingletonActionLookupKey extends ActionLookupValue.ActionLookupKey {
+ @Override
+ SkyKey getSkyKey() {
+ return OWNER_KEY;
+ }
+
+ @Override
+ SkyFunctionName getType() {
+ throw new UnsupportedOperationException();
+ }
+ }
+}