|  | // 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 com.google.common.collect.ImmutableList; | 
|  | import com.google.common.collect.ImmutableMap; | 
|  | import com.google.devtools.build.lib.actions.ActionAnalysisMetadata; | 
|  | import com.google.devtools.build.lib.actions.ActionKeyContext; | 
|  | import com.google.devtools.build.lib.actions.ActionLookupValue.ActionLookupKey; | 
|  | import com.google.devtools.build.lib.actions.Artifact; | 
|  | import com.google.devtools.build.lib.actions.FileStateValue; | 
|  | import com.google.devtools.build.lib.actions.FileValue; | 
|  | import com.google.devtools.build.lib.actions.util.InjectedActionLookupKey; | 
|  | import com.google.devtools.build.lib.analysis.BlazeDirectories; | 
|  | import com.google.devtools.build.lib.analysis.ServerDirectories; | 
|  | import com.google.devtools.build.lib.packages.WorkspaceFileValue; | 
|  | import com.google.devtools.build.lib.pkgcache.PathPackageLocator; | 
|  | import com.google.devtools.build.lib.skyframe.ExternalFilesHelper.ExternalFileAction; | 
|  | import com.google.devtools.build.lib.skyframe.PackageLookupFunction.CrossRepositoryLabelViolationStrategy; | 
|  | import com.google.devtools.build.lib.testutil.TestConstants; | 
|  | import com.google.devtools.build.lib.testutil.TestRuleClassProvider; | 
|  | import com.google.devtools.build.lib.testutil.TestUtils; | 
|  | import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor; | 
|  | import com.google.devtools.build.lib.vfs.FileSystemUtils; | 
|  | import com.google.devtools.build.lib.vfs.Path; | 
|  | import com.google.devtools.build.lib.vfs.Root; | 
|  | import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem; | 
|  | import com.google.devtools.build.skyframe.InMemoryMemoizingEvaluator; | 
|  | import com.google.devtools.build.skyframe.MemoizingEvaluator; | 
|  | import com.google.devtools.build.skyframe.RecordingDifferencer; | 
|  | import com.google.devtools.build.skyframe.SequencedRecordingDifferencer; | 
|  | import com.google.devtools.build.skyframe.SequentialBuildDriver; | 
|  | import com.google.devtools.build.skyframe.SkyFunction; | 
|  | import com.google.devtools.build.skyframe.SkyFunctionException; | 
|  | import com.google.devtools.build.skyframe.SkyFunctionName; | 
|  | import com.google.devtools.build.skyframe.SkyKey; | 
|  | import com.google.devtools.build.skyframe.SkyValue; | 
|  | import java.io.IOException; | 
|  | import java.util.LinkedHashSet; | 
|  | import java.util.UUID; | 
|  | import java.util.concurrent.atomic.AtomicReference; | 
|  | import org.junit.Before; | 
|  |  | 
|  | abstract class ArtifactFunctionTestCase { | 
|  | static final ActionLookupKey ALL_OWNER = new InjectedActionLookupKey("all_owner"); | 
|  |  | 
|  | protected LinkedHashSet<ActionAnalysisMetadata> actions; | 
|  | protected boolean fastDigest = false; | 
|  | protected RecordingDifferencer differencer = new SequencedRecordingDifferencer(); | 
|  | protected SequentialBuildDriver driver; | 
|  | protected MemoizingEvaluator evaluator; | 
|  | protected Path root; | 
|  | protected Path middlemanPath; | 
|  | protected final ActionKeyContext actionKeyContext = new ActionKeyContext(); | 
|  |  | 
|  | /** | 
|  | * The test action execution function. The Skyframe evaluator's action execution function | 
|  | * delegates to this one. | 
|  | */ | 
|  | protected SkyFunction delegateActionExecutionFunction; | 
|  |  | 
|  | @Before | 
|  | public void baseSetUp() throws Exception { | 
|  | CustomInMemoryFs fs = new CustomInMemoryFs(); | 
|  | setupRoot(fs); | 
|  | AtomicReference<PathPackageLocator> pkgLocator = | 
|  | new AtomicReference<>( | 
|  | new PathPackageLocator( | 
|  | root.getFileSystem().getPath("/outputbase"), | 
|  | ImmutableList.of(Root.fromPath(root)), | 
|  | BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY)); | 
|  | BlazeDirectories directories = | 
|  | new BlazeDirectories( | 
|  | new ServerDirectories(root, root, root), | 
|  | root, | 
|  | /* defaultSystemJavabase= */ null, | 
|  | TestConstants.PRODUCT_NAME); | 
|  | ExternalFilesHelper externalFilesHelper = ExternalFilesHelper.createForTesting( | 
|  | pkgLocator, | 
|  | ExternalFileAction.DEPEND_ON_EXTERNAL_PKG_FOR_EXTERNAL_REPO_PATHS, | 
|  | directories); | 
|  | differencer = new SequencedRecordingDifferencer(); | 
|  | evaluator = | 
|  | new InMemoryMemoizingEvaluator( | 
|  | ImmutableMap.<SkyFunctionName, SkyFunction>builder() | 
|  | .put( | 
|  | FileStateValue.FILE_STATE, | 
|  | new FileStateFunction( | 
|  | new AtomicReference<TimestampGranularityMonitor>(), externalFilesHelper)) | 
|  | .put(FileValue.FILE, new FileFunction(pkgLocator)) | 
|  | .put(Artifact.ARTIFACT, new ArtifactFunction(() -> true)) | 
|  | .put(SkyFunctions.ACTION_EXECUTION, new SimpleActionExecutionFunction()) | 
|  | .put( | 
|  | SkyFunctions.PACKAGE, | 
|  | new PackageFunction(null, null, null, null, null, null, null)) | 
|  | .put( | 
|  | SkyFunctions.PACKAGE_LOOKUP, | 
|  | new PackageLookupFunction( | 
|  | null, | 
|  | CrossRepositoryLabelViolationStrategy.ERROR, | 
|  | BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY)) | 
|  | .put( | 
|  | SkyFunctions.WORKSPACE_AST, | 
|  | new WorkspaceASTFunction(TestRuleClassProvider.getRuleClassProvider())) | 
|  | .put( | 
|  | WorkspaceFileValue.WORKSPACE_FILE, | 
|  | new WorkspaceFileFunction( | 
|  | TestRuleClassProvider.getRuleClassProvider(), | 
|  | TestConstants.PACKAGE_FACTORY_BUILDER_FACTORY_FOR_TESTING | 
|  | .builder(directories) | 
|  | .build(TestRuleClassProvider.getRuleClassProvider(), fs), | 
|  | directories, | 
|  | /*skylarkImportLookupFunctionForInlining=*/ null)) | 
|  | .put(SkyFunctions.EXTERNAL_PACKAGE, new ExternalPackageFunction()) | 
|  | .put( | 
|  | SkyFunctions.ACTION_TEMPLATE_EXPANSION, | 
|  | new ActionTemplateExpansionFunction(actionKeyContext)) | 
|  | .build(), | 
|  | differencer); | 
|  | driver = new SequentialBuildDriver(evaluator); | 
|  | PrecomputedValue.BUILD_ID.set(differencer, UUID.randomUUID()); | 
|  | PrecomputedValue.PATH_PACKAGE_LOCATOR.set(differencer, pkgLocator.get()); | 
|  | actions = new LinkedHashSet<>(); | 
|  | } | 
|  |  | 
|  | protected void setupRoot(CustomInMemoryFs fs) throws IOException { | 
|  | Path tmpDir = fs.getPath(TestUtils.tmpDir()); | 
|  | root = tmpDir.getChild("root"); | 
|  | FileSystemUtils.createDirectoryAndParents(root); | 
|  | FileSystemUtils.createEmptyFile(root.getRelative("WORKSPACE")); | 
|  | middlemanPath = tmpDir.getChild("middlemanRoot"); | 
|  | FileSystemUtils.createDirectoryAndParents(middlemanPath); | 
|  | } | 
|  |  | 
|  | protected static void writeFile(Path path, String contents) throws IOException { | 
|  | FileSystemUtils.createDirectoryAndParents(path.getParentDirectory()); | 
|  | FileSystemUtils.writeContentAsLatin1(path, contents); | 
|  | } | 
|  |  | 
|  | /** ActionExecutionFunction that delegates to our delegate. */ | 
|  | private class SimpleActionExecutionFunction implements SkyFunction { | 
|  | @Override | 
|  | public SkyValue compute(SkyKey skyKey, Environment env) | 
|  | throws SkyFunctionException, InterruptedException { | 
|  | return delegateActionExecutionFunction.compute(skyKey, env); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public String extractTag(SkyKey skyKey) { | 
|  | return delegateActionExecutionFunction.extractTag(skyKey); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** InMemoryFileSystem that can pretend to do a fast digest. */ | 
|  | protected class CustomInMemoryFs extends InMemoryFileSystem { | 
|  | @Override | 
|  | protected byte[] getFastDigest(Path path) throws IOException { | 
|  | return fastDigest ? getDigest(path) : null; | 
|  | } | 
|  | } | 
|  | } |