Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 1 | // Copyright 2015 The Bazel Authors. All rights reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | package com.google.devtools.build.lib.skyframe; |
| 15 | |
| 16 | import static com.google.common.truth.Truth.assertThat; |
| 17 | import static com.google.devtools.build.lib.actions.FilesetTraversalParams.PackageBoundaryMode.CROSS; |
| 18 | import static com.google.devtools.build.lib.actions.FilesetTraversalParams.PackageBoundaryMode.DONT_CROSS; |
| 19 | import static com.google.devtools.build.lib.actions.FilesetTraversalParams.PackageBoundaryMode.REPORT_ERROR; |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 20 | import static com.google.devtools.build.lib.skyframe.RecursiveFilesystemTraversalValue.ResolvedFileFactoryForTesting.danglingSymlinkForTesting; |
| 21 | import static com.google.devtools.build.lib.skyframe.RecursiveFilesystemTraversalValue.ResolvedFileFactoryForTesting.regularFileForTesting; |
| 22 | import static com.google.devtools.build.lib.skyframe.RecursiveFilesystemTraversalValue.ResolvedFileFactoryForTesting.symlinkToDirectoryForTesting; |
| 23 | import static com.google.devtools.build.lib.skyframe.RecursiveFilesystemTraversalValue.ResolvedFileFactoryForTesting.symlinkToFileForTesting; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 24 | |
tomlu | a155b53 | 2017-11-08 20:12:47 +0100 | [diff] [blame] | 25 | import com.google.common.base.Preconditions; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 26 | import com.google.common.collect.ImmutableList; |
| 27 | import com.google.common.collect.ImmutableSet; |
| 28 | import com.google.common.collect.Sets; |
| 29 | import com.google.devtools.build.lib.actions.Artifact; |
tomlu | 1cdcdf9 | 2018-01-16 11:07:51 -0800 | [diff] [blame] | 30 | import com.google.devtools.build.lib.actions.ArtifactRoot; |
felly | 5be4dd6 | 2018-02-05 11:11:53 -0800 | [diff] [blame] | 31 | import com.google.devtools.build.lib.actions.FilesetTraversalParams.DirectTraversalRoot; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 32 | import com.google.devtools.build.lib.actions.FilesetTraversalParams.PackageBoundaryMode; |
Kristina Chodorow | f9fdc8d | 2015-12-08 12:49:31 +0000 | [diff] [blame] | 33 | import com.google.devtools.build.lib.analysis.BlazeDirectories; |
Ulf Adams | 015aad9 | 2016-07-13 16:49:40 +0000 | [diff] [blame] | 34 | import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; |
janakr | 3b63a4e | 2017-09-14 09:55:40 +0200 | [diff] [blame] | 35 | import com.google.devtools.build.lib.analysis.ServerDirectories; |
Ulf Adams | 015aad9 | 2016-07-13 16:49:40 +0000 | [diff] [blame] | 36 | import com.google.devtools.build.lib.analysis.util.AnalysisMock; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 37 | import com.google.devtools.build.lib.cmdline.PackageIdentifier; |
| 38 | import com.google.devtools.build.lib.events.NullEventHandler; |
| 39 | import com.google.devtools.build.lib.pkgcache.PathPackageLocator; |
Nathan Harmata | d4f7594 | 2016-10-18 08:55:17 +0000 | [diff] [blame] | 40 | import com.google.devtools.build.lib.skyframe.ExternalFilesHelper.ExternalFileAction; |
John Cater | 5e9ce94 | 2016-10-12 17:23:30 +0000 | [diff] [blame] | 41 | import com.google.devtools.build.lib.skyframe.PackageLookupFunction.CrossRepositoryLabelViolationStrategy; |
kush | 95bf7c8 | 2017-08-30 00:27:35 +0200 | [diff] [blame] | 42 | import com.google.devtools.build.lib.skyframe.RecursiveFilesystemTraversalFunction.FileOperationException; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 43 | import com.google.devtools.build.lib.skyframe.RecursiveFilesystemTraversalValue.ResolvedFile; |
| 44 | import com.google.devtools.build.lib.skyframe.RecursiveFilesystemTraversalValue.TraversalRequest; |
Florian Weikert | cca703a | 2015-12-07 09:56:38 +0000 | [diff] [blame] | 45 | import com.google.devtools.build.lib.testutil.FoundationTestCase; |
laszlocsomor | 29bdf63 | 2018-03-13 02:50:46 -0700 | [diff] [blame] | 46 | import com.google.devtools.build.lib.testutil.TimestampGranularityUtils; |
Laszlo Csomor | a31e035 | 2018-03-09 04:51:38 -0800 | [diff] [blame] | 47 | import com.google.devtools.build.lib.util.io.OutErr; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 48 | import com.google.devtools.build.lib.vfs.Path; |
| 49 | import com.google.devtools.build.lib.vfs.PathFragment; |
tomlu | ee6a686 | 2018-01-17 14:36:26 -0800 | [diff] [blame] | 50 | import com.google.devtools.build.lib.vfs.Root; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 51 | import com.google.devtools.build.lib.vfs.RootedPath; |
| 52 | import com.google.devtools.build.skyframe.ErrorInfo; |
| 53 | import com.google.devtools.build.skyframe.EvaluationProgressReceiver; |
| 54 | import com.google.devtools.build.skyframe.EvaluationResult; |
| 55 | import com.google.devtools.build.skyframe.InMemoryMemoizingEvaluator; |
| 56 | import com.google.devtools.build.skyframe.MemoizingEvaluator; |
| 57 | import com.google.devtools.build.skyframe.RecordingDifferencer; |
janakr | 1cde872 | 2017-10-10 03:22:21 +0200 | [diff] [blame] | 58 | import com.google.devtools.build.skyframe.SequencedRecordingDifferencer; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 59 | import com.google.devtools.build.skyframe.SequentialBuildDriver; |
| 60 | import com.google.devtools.build.skyframe.SkyFunction; |
felly | 5be4dd6 | 2018-02-05 11:11:53 -0800 | [diff] [blame] | 61 | import com.google.devtools.build.skyframe.SkyFunctionException; |
| 62 | import com.google.devtools.build.skyframe.SkyFunctionException.Transience; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 63 | import com.google.devtools.build.skyframe.SkyFunctionName; |
| 64 | import com.google.devtools.build.skyframe.SkyKey; |
| 65 | import com.google.devtools.build.skyframe.SkyValue; |
felly | 5be4dd6 | 2018-02-05 11:11:53 -0800 | [diff] [blame] | 66 | import java.io.IOException; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 67 | import java.io.OutputStream; |
| 68 | import java.nio.charset.StandardCharsets; |
| 69 | import java.util.HashMap; |
| 70 | import java.util.HashSet; |
| 71 | import java.util.Map; |
| 72 | import java.util.Set; |
| 73 | import java.util.UUID; |
| 74 | import java.util.concurrent.atomic.AtomicReference; |
janakr | 61377f7 | 2018-06-04 12:50:13 -0700 | [diff] [blame] | 75 | import java.util.function.Supplier; |
felly | 5be4dd6 | 2018-02-05 11:11:53 -0800 | [diff] [blame] | 76 | import javax.annotation.Nullable; |
John Cater | 5e9ce94 | 2016-10-12 17:23:30 +0000 | [diff] [blame] | 77 | import org.junit.Before; |
| 78 | import org.junit.Test; |
| 79 | import org.junit.runner.RunWith; |
| 80 | import org.junit.runners.JUnit4; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 81 | |
| 82 | /** Tests for {@link RecursiveFilesystemTraversalFunction}. */ |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 83 | @RunWith(JUnit4.class) |
Florian Weikert | cca703a | 2015-12-07 09:56:38 +0000 | [diff] [blame] | 84 | public final class RecursiveFilesystemTraversalFunctionTest extends FoundationTestCase { |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 85 | private RecordingEvaluationProgressReceiver progressReceiver; |
| 86 | private MemoizingEvaluator evaluator; |
| 87 | private SequentialBuildDriver driver; |
| 88 | private RecordingDifferencer differencer; |
| 89 | private AtomicReference<PathPackageLocator> pkgLocator; |
felly | 5be4dd6 | 2018-02-05 11:11:53 -0800 | [diff] [blame] | 90 | private ArtifactFakeFunction artifactFakeFunction; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 91 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 92 | @Before |
| 93 | public final void setUp() throws Exception { |
Ulf Adams | 015aad9 | 2016-07-13 16:49:40 +0000 | [diff] [blame] | 94 | AnalysisMock analysisMock = AnalysisMock.get(); |
felly | 5be4dd6 | 2018-02-05 11:11:53 -0800 | [diff] [blame] | 95 | artifactFakeFunction = new ArtifactFakeFunction(); |
John Cater | e0d1d0e | 2017-11-28 20:47:41 -0800 | [diff] [blame] | 96 | pkgLocator = |
| 97 | new AtomicReference<>( |
| 98 | new PathPackageLocator( |
| 99 | outputBase, |
tomlu | ee6a686 | 2018-01-17 14:36:26 -0800 | [diff] [blame] | 100 | ImmutableList.of(Root.fromPath(rootDirectory)), |
John Cater | e0d1d0e | 2017-11-28 20:47:41 -0800 | [diff] [blame] | 101 | BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY)); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 102 | AtomicReference<ImmutableSet<PackageIdentifier>> deletedPackages = |
| 103 | new AtomicReference<>(ImmutableSet.<PackageIdentifier>of()); |
Ulf Adams | 015aad9 | 2016-07-13 16:49:40 +0000 | [diff] [blame] | 104 | BlazeDirectories directories = |
| 105 | new BlazeDirectories( |
Klaus Aehlig | c2499c4 | 2018-02-27 05:47:21 -0800 | [diff] [blame] | 106 | new ServerDirectories(rootDirectory, outputBase, rootDirectory), |
janakr | 3b63a4e | 2017-09-14 09:55:40 +0200 | [diff] [blame] | 107 | rootDirectory, |
cushon | 849df36 | 2018-05-14 01:51:45 -0700 | [diff] [blame] | 108 | null, |
janakr | 3b63a4e | 2017-09-14 09:55:40 +0200 | [diff] [blame] | 109 | analysisMock.getProductName()); |
nharmata | 3fb7d34 | 2018-02-23 11:37:51 -0800 | [diff] [blame] | 110 | ExternalFilesHelper externalFilesHelper = ExternalFilesHelper.createForTesting( |
Nathan Harmata | d4f7594 | 2016-10-18 08:55:17 +0000 | [diff] [blame] | 111 | pkgLocator, ExternalFileAction.DEPEND_ON_EXTERNAL_PKG_FOR_EXTERNAL_REPO_PATHS, directories); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 112 | |
Ulf Adams | 015aad9 | 2016-07-13 16:49:40 +0000 | [diff] [blame] | 113 | ConfiguredRuleClassProvider ruleClassProvider = analysisMock.createRuleClassProvider(); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 114 | Map<SkyFunctionName, SkyFunction> skyFunctions = new HashMap<>(); |
Ulf Adams | c73051c6 | 2016-03-23 09:18:13 +0000 | [diff] [blame] | 115 | skyFunctions.put(SkyFunctions.FILE_STATE, new FileStateFunction( |
felly | 5be4dd6 | 2018-02-05 11:11:53 -0800 | [diff] [blame] | 116 | new AtomicReference<>(), externalFilesHelper)); |
Kristina Chodorow | f9fdc8d | 2015-12-08 12:49:31 +0000 | [diff] [blame] | 117 | skyFunctions.put(SkyFunctions.FILE, new FileFunction(pkgLocator)); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 118 | skyFunctions.put(SkyFunctions.DIRECTORY_LISTING, new DirectoryListingFunction()); |
| 119 | skyFunctions.put( |
| 120 | SkyFunctions.DIRECTORY_LISTING_STATE, |
| 121 | new DirectoryListingStateFunction(externalFilesHelper)); |
| 122 | skyFunctions.put( |
| 123 | SkyFunctions.RECURSIVE_FILESYSTEM_TRAVERSAL, new RecursiveFilesystemTraversalFunction()); |
John Cater | 5e9ce94 | 2016-10-12 17:23:30 +0000 | [diff] [blame] | 124 | skyFunctions.put( |
| 125 | SkyFunctions.PACKAGE_LOOKUP, |
John Cater | 0c0735a | 2016-11-11 01:52:02 +0000 | [diff] [blame] | 126 | new PackageLookupFunction( |
| 127 | deletedPackages, |
| 128 | CrossRepositoryLabelViolationStrategy.ERROR, |
John Cater | e0d1d0e | 2017-11-28 20:47:41 -0800 | [diff] [blame] | 129 | BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY)); |
Eric Fellheimer | 7ef96d7 | 2015-11-12 02:28:44 +0000 | [diff] [blame] | 130 | skyFunctions.put(SkyFunctions.BLACKLISTED_PACKAGE_PREFIXES, |
nharmata | e4eb23f | 2017-12-05 09:27:45 -0800 | [diff] [blame] | 131 | new BlacklistedPackagePrefixesFunction( |
| 132 | /*hardcodedBlacklistedPackagePrefixes=*/ ImmutableSet.of(), |
| 133 | /*additionalBlacklistedPackagePrefixesFile=*/ PathFragment.EMPTY_FRAGMENT)); |
Kristina Chodorow | f9fdc8d | 2015-12-08 12:49:31 +0000 | [diff] [blame] | 134 | skyFunctions.put(SkyFunctions.PACKAGE, |
| 135 | new PackageFunction(null, null, null, null, null, null, null)); |
Ulf Adams | 015aad9 | 2016-07-13 16:49:40 +0000 | [diff] [blame] | 136 | skyFunctions.put(SkyFunctions.WORKSPACE_AST, new WorkspaceASTFunction(ruleClassProvider)); |
| 137 | skyFunctions.put( |
| 138 | SkyFunctions.WORKSPACE_FILE, |
| 139 | new WorkspaceFileFunction( |
| 140 | ruleClassProvider, |
| 141 | analysisMock |
janakr | 52d05e8 | 2017-09-22 13:27:14 -0400 | [diff] [blame] | 142 | .getPackageFactoryBuilderForTesting(directories) |
nharmata | e57e9a3 | 2018-04-02 15:10:24 -0700 | [diff] [blame] | 143 | .build(ruleClassProvider), |
Kristina Chodorow | 5a2936f | 2016-04-22 17:02:19 +0000 | [diff] [blame] | 144 | directories)); |
Damien Martin-Guillerez | bc8b5e0 | 2016-02-05 22:09:09 +0000 | [diff] [blame] | 145 | skyFunctions.put(SkyFunctions.EXTERNAL_PACKAGE, new ExternalPackageFunction()); |
John Cater | b4f461e | 2016-10-25 16:16:35 +0000 | [diff] [blame] | 146 | skyFunctions.put(SkyFunctions.LOCAL_REPOSITORY_LOOKUP, new LocalRepositoryLookupFunction()); |
kush | 95bf7c8 | 2017-08-30 00:27:35 +0200 | [diff] [blame] | 147 | skyFunctions.put( |
| 148 | SkyFunctions.FILE_SYMLINK_INFINITE_EXPANSION_UNIQUENESS, |
| 149 | new FileSymlinkInfiniteExpansionUniquenessFunction()); |
| 150 | skyFunctions.put( |
| 151 | SkyFunctions.FILE_SYMLINK_CYCLE_UNIQUENESS, new FileSymlinkCycleUniquenessFunction()); |
felly | 5be4dd6 | 2018-02-05 11:11:53 -0800 | [diff] [blame] | 152 | skyFunctions.put( |
| 153 | SkyFunctions.ARTIFACT, |
| 154 | artifactFakeFunction); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 155 | |
| 156 | progressReceiver = new RecordingEvaluationProgressReceiver(); |
janakr | 1cde872 | 2017-10-10 03:22:21 +0200 | [diff] [blame] | 157 | differencer = new SequencedRecordingDifferencer(); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 158 | evaluator = new InMemoryMemoizingEvaluator(skyFunctions, differencer, progressReceiver); |
| 159 | driver = new SequentialBuildDriver(evaluator); |
| 160 | PrecomputedValue.BUILD_ID.set(differencer, UUID.randomUUID()); |
| 161 | PrecomputedValue.PATH_PACKAGE_LOCATOR.set(differencer, pkgLocator.get()); |
| 162 | } |
| 163 | |
| 164 | private Artifact sourceArtifact(String path) { |
tomlu | ee6a686 | 2018-01-17 14:36:26 -0800 | [diff] [blame] | 165 | return new Artifact( |
| 166 | PathFragment.create(path), ArtifactRoot.asSourceRoot(Root.fromPath(rootDirectory))); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 167 | } |
| 168 | |
| 169 | private Artifact sourceArtifactUnderPackagePath(String path, String packagePath) { |
| 170 | return new Artifact( |
tomlu | 1cdcdf9 | 2018-01-16 11:07:51 -0800 | [diff] [blame] | 171 | PathFragment.create(path), |
tomlu | ee6a686 | 2018-01-17 14:36:26 -0800 | [diff] [blame] | 172 | ArtifactRoot.asSourceRoot(Root.fromPath(rootDirectory.getRelative(packagePath)))); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 173 | } |
| 174 | |
| 175 | private Artifact derivedArtifact(String path) { |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 176 | PathFragment execPath = PathFragment.create("out").getRelative(path); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 177 | Artifact output = |
| 178 | new Artifact( |
tomlu | 1cdcdf9 | 2018-01-16 11:07:51 -0800 | [diff] [blame] | 179 | ArtifactRoot.asDerivedRoot(rootDirectory, rootDirectory.getRelative("out")), |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 180 | execPath); |
| 181 | return output; |
| 182 | } |
| 183 | |
| 184 | private static RootedPath rootedPath(Artifact artifact) { |
tomlu | ee6a686 | 2018-01-17 14:36:26 -0800 | [diff] [blame] | 185 | return RootedPath.toRootedPath(artifact.getRoot().getRoot(), artifact.getRootRelativePath()); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 186 | } |
| 187 | |
| 188 | private RootedPath rootedPath(String path, String packagePath) { |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 189 | return RootedPath.toRootedPath( |
tomlu | ee6a686 | 2018-01-17 14:36:26 -0800 | [diff] [blame] | 190 | Root.fromPath(rootDirectory.getRelative(packagePath)), PathFragment.create(path)); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 191 | } |
| 192 | |
| 193 | private static RootedPath childOf(Artifact artifact, String relative) { |
| 194 | return RootedPath.toRootedPath( |
tomlu | ee6a686 | 2018-01-17 14:36:26 -0800 | [diff] [blame] | 195 | artifact.getRoot().getRoot(), artifact.getRootRelativePath().getRelative(relative)); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 196 | } |
| 197 | |
| 198 | private static RootedPath childOf(RootedPath path, String relative) { |
tomlu | 8cc5dcf | 2018-01-19 09:28:06 -0800 | [diff] [blame] | 199 | return RootedPath.toRootedPath( |
| 200 | path.getRoot(), path.getRootRelativePath().getRelative(relative)); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 201 | } |
| 202 | |
| 203 | private static RootedPath parentOf(RootedPath path) { |
tomlu | 8cc5dcf | 2018-01-19 09:28:06 -0800 | [diff] [blame] | 204 | PathFragment parent = |
| 205 | Preconditions.checkNotNull(path.getRootRelativePath().getParentDirectory()); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 206 | return RootedPath.toRootedPath(path.getRoot(), parent); |
| 207 | } |
| 208 | |
| 209 | private static RootedPath siblingOf(RootedPath path, String relative) { |
tomlu | 8cc5dcf | 2018-01-19 09:28:06 -0800 | [diff] [blame] | 210 | PathFragment parent = |
| 211 | Preconditions.checkNotNull(path.getRootRelativePath().getParentDirectory()); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 212 | return RootedPath.toRootedPath(path.getRoot(), parent.getRelative(relative)); |
| 213 | } |
| 214 | |
| 215 | private static RootedPath siblingOf(Artifact artifact, String relative) { |
| 216 | PathFragment parent = |
| 217 | Preconditions.checkNotNull(artifact.getRootRelativePath().getParentDirectory()); |
tomlu | ee6a686 | 2018-01-17 14:36:26 -0800 | [diff] [blame] | 218 | return RootedPath.toRootedPath(artifact.getRoot().getRoot(), parent.getRelative(relative)); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 219 | } |
| 220 | |
| 221 | private void createFile(Path path, String... contents) throws Exception { |
| 222 | if (!path.getParentDirectory().exists()) { |
| 223 | scratch.dir(path.getParentDirectory().getPathString()); |
| 224 | } |
| 225 | scratch.file(path.getPathString(), contents); |
| 226 | } |
| 227 | |
| 228 | private void createFile(Artifact artifact, String... contents) throws Exception { |
| 229 | createFile(artifact.getPath(), contents); |
| 230 | } |
| 231 | |
| 232 | private RootedPath createFile(RootedPath path, String... contents) throws Exception { |
| 233 | scratch.dir(parentOf(path).asPath().getPathString()); |
| 234 | createFile(path.asPath(), contents); |
| 235 | return path; |
| 236 | } |
| 237 | |
| 238 | private static TraversalRequest fileLikeRoot(Artifact file, PackageBoundaryMode pkgBoundaryMode) { |
janakr | 5fb2a48 | 2018-03-02 17:48:57 -0800 | [diff] [blame] | 239 | return TraversalRequest.create( |
| 240 | DirectTraversalRoot.forFileOrDirectory(file), |
| 241 | !file.isSourceArtifact(), |
| 242 | pkgBoundaryMode, |
| 243 | false, |
| 244 | null); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 245 | } |
| 246 | |
| 247 | private static TraversalRequest pkgRoot( |
| 248 | RootedPath pkgDirectory, PackageBoundaryMode pkgBoundaryMode) { |
janakr | 5fb2a48 | 2018-03-02 17:48:57 -0800 | [diff] [blame] | 249 | return TraversalRequest.create( |
| 250 | DirectTraversalRoot.forRootedPath(pkgDirectory), false, pkgBoundaryMode, true, null); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 251 | } |
| 252 | |
| 253 | private <T extends SkyValue> EvaluationResult<T> eval(SkyKey key) throws Exception { |
| 254 | return driver.evaluate( |
| 255 | ImmutableList.of(key), |
| 256 | false, |
| 257 | SkyframeExecutor.DEFAULT_THREAD_COUNT, |
| 258 | NullEventHandler.INSTANCE); |
| 259 | } |
| 260 | |
| 261 | private RecursiveFilesystemTraversalValue evalTraversalRequest(TraversalRequest params) |
| 262 | throws Exception { |
janakr | 5fb2a48 | 2018-03-02 17:48:57 -0800 | [diff] [blame] | 263 | EvaluationResult<RecursiveFilesystemTraversalValue> result = eval(params); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 264 | assertThat(result.hasError()).isFalse(); |
janakr | 5fb2a48 | 2018-03-02 17:48:57 -0800 | [diff] [blame] | 265 | return result.get(params); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 266 | } |
| 267 | |
| 268 | /** |
| 269 | * Asserts that the requested SkyValue can be built and results in the expected set of files. |
| 270 | * |
| 271 | * <p>The metadata of files is ignored in comparing the actual results with the expected ones. |
| 272 | * The returned object however contains the actual metadata. |
| 273 | */ |
| 274 | @SafeVarargs |
| 275 | private final RecursiveFilesystemTraversalValue traverseAndAssertFiles( |
| 276 | TraversalRequest params, ResolvedFile... expectedFilesIgnoringMetadata) throws Exception { |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 277 | RecursiveFilesystemTraversalValue result = evalTraversalRequest(params); |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 278 | Set<ResolvedFile> actual = new HashSet<>(); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 279 | for (ResolvedFile act : result.getTransitiveFiles()) { |
| 280 | // Strip metadata so only the type and path of the objects are compared. |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 281 | actual.add(act.stripMetadataForTesting()); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 282 | } |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 283 | assertThat(actual).containsExactly((Object[]) expectedFilesIgnoringMetadata); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 284 | |
| 285 | // The returned object still has the unstripped metadata. |
| 286 | return result; |
| 287 | } |
| 288 | |
felly | 5be4dd6 | 2018-02-05 11:11:53 -0800 | [diff] [blame] | 289 | private void appendToFile(RootedPath rootedPath, SkyKey toInvalidate, String content) |
| 290 | throws Exception { |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 291 | Path path = rootedPath.asPath(); |
| 292 | if (path.exists()) { |
| 293 | try (OutputStream os = path.getOutputStream(/*append=*/ true)) { |
| 294 | os.write(content.getBytes(StandardCharsets.UTF_8)); |
| 295 | } |
felly | 5be4dd6 | 2018-02-05 11:11:53 -0800 | [diff] [blame] | 296 | differencer.invalidate(ImmutableList.of(toInvalidate)); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 297 | } else { |
| 298 | createFile(path, content); |
| 299 | } |
| 300 | } |
| 301 | |
felly | 5be4dd6 | 2018-02-05 11:11:53 -0800 | [diff] [blame] | 302 | private void appendToFile(RootedPath rootedPath, String content) throws Exception { |
| 303 | appendToFile(rootedPath, FileStateValue.key(rootedPath), content); |
| 304 | } |
| 305 | |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 306 | private void appendToFile(Artifact file, String content) throws Exception { |
felly | 5be4dd6 | 2018-02-05 11:11:53 -0800 | [diff] [blame] | 307 | SkyKey key = file.isSourceArtifact() |
| 308 | ? FileStateValue.key(rootedPath(file)) |
| 309 | : ArtifactSkyKey.key(file, true); |
| 310 | appendToFile(rootedPath(file), key, content); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 311 | } |
| 312 | |
| 313 | private void invalidateDirectory(RootedPath path) { |
| 314 | differencer.invalidate(ImmutableList.of(DirectoryListingStateValue.key(path))); |
| 315 | } |
| 316 | |
felly | 5be4dd6 | 2018-02-05 11:11:53 -0800 | [diff] [blame] | 317 | private void invalidateOutputArtifact(Artifact output) { |
| 318 | assertThat(output.isSourceArtifact()).isFalse(); |
| 319 | differencer.invalidate(ImmutableList.of(ArtifactSkyKey.key(output, true))); |
| 320 | } |
| 321 | |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 322 | private void invalidateDirectory(Artifact directoryArtifact) { |
| 323 | invalidateDirectory(rootedPath(directoryArtifact)); |
| 324 | } |
| 325 | |
| 326 | private static final class RecordingEvaluationProgressReceiver |
nharmata | 8040b0b | 2017-05-09 13:53:19 -0400 | [diff] [blame] | 327 | extends EvaluationProgressReceiver.NullEvaluationProgressReceiver { |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 328 | Set<SkyKey> invalidations; |
janakr | 61377f7 | 2018-06-04 12:50:13 -0700 | [diff] [blame] | 329 | Set<SkyKey> evaluations; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 330 | |
| 331 | RecordingEvaluationProgressReceiver() { |
| 332 | clear(); |
| 333 | } |
| 334 | |
| 335 | void clear() { |
| 336 | invalidations = Sets.newConcurrentHashSet(); |
| 337 | evaluations = Sets.newConcurrentHashSet(); |
| 338 | } |
| 339 | |
| 340 | @Override |
| 341 | public void invalidated(SkyKey skyKey, InvalidationState state) { |
| 342 | invalidations.add(skyKey); |
| 343 | } |
| 344 | |
| 345 | @Override |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 346 | public void evaluated( |
janakr | 61377f7 | 2018-06-04 12:50:13 -0700 | [diff] [blame] | 347 | SkyKey skyKey, |
| 348 | Supplier<EvaluationSuccessState> evaluationSuccessState, |
| 349 | EvaluationState state) { |
| 350 | if (evaluationSuccessState.get().succeeded()) { |
| 351 | evaluations.add(skyKey); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 352 | } |
| 353 | } |
| 354 | } |
| 355 | |
Laszlo Csomor | 207140f | 2015-12-07 15:07:33 +0000 | [diff] [blame] | 356 | private void assertTraversalRootHashesAre( |
| 357 | boolean equal, RecursiveFilesystemTraversalValue a, RecursiveFilesystemTraversalValue b) |
| 358 | throws Exception { |
| 359 | if (equal) { |
| 360 | assertThat(a.getResolvedRoot().get().hashCode()) |
| 361 | .isEqualTo(b.getResolvedRoot().get().hashCode()); |
| 362 | } else { |
| 363 | assertThat(a.getResolvedRoot().get().hashCode()) |
| 364 | .isNotEqualTo(b.getResolvedRoot().get().hashCode()); |
| 365 | } |
| 366 | } |
| 367 | |
| 368 | private void assertTraversalRootHashesAreEqual( |
| 369 | RecursiveFilesystemTraversalValue a, RecursiveFilesystemTraversalValue b) throws Exception { |
| 370 | assertTraversalRootHashesAre(true, a, b); |
| 371 | } |
| 372 | |
| 373 | private void assertTraversalRootHashesAreNotEqual( |
| 374 | RecursiveFilesystemTraversalValue a, RecursiveFilesystemTraversalValue b) throws Exception { |
| 375 | assertTraversalRootHashesAre(false, a, b); |
| 376 | } |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 377 | |
| 378 | private void assertTraversalOfFile(Artifact rootArtifact) throws Exception { |
| 379 | TraversalRequest traversalRoot = fileLikeRoot(rootArtifact, DONT_CROSS); |
| 380 | RootedPath rootedPath = createFile(rootedPath(rootArtifact), "foo"); |
| 381 | |
| 382 | // Assert that the SkyValue is built and looks right. |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 383 | ResolvedFile expected = regularFileForTesting(rootedPath); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 384 | RecursiveFilesystemTraversalValue v1 = traverseAndAssertFiles(traversalRoot, expected); |
| 385 | assertThat(progressReceiver.invalidations).isEmpty(); |
janakr | 61377f7 | 2018-06-04 12:50:13 -0700 | [diff] [blame] | 386 | assertThat(progressReceiver.evaluations).contains(traversalRoot); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 387 | progressReceiver.clear(); |
| 388 | |
| 389 | // Edit the file and verify that the value is rebuilt. |
| 390 | appendToFile(rootArtifact, "bar"); |
| 391 | RecursiveFilesystemTraversalValue v2 = traverseAndAssertFiles(traversalRoot, expected); |
janakr | 5fb2a48 | 2018-03-02 17:48:57 -0800 | [diff] [blame] | 392 | assertThat(progressReceiver.invalidations).contains(traversalRoot); |
janakr | 61377f7 | 2018-06-04 12:50:13 -0700 | [diff] [blame] | 393 | assertThat(progressReceiver.evaluations).contains(traversalRoot); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 394 | assertThat(v2).isNotEqualTo(v1); |
Laszlo Csomor | 207140f | 2015-12-07 15:07:33 +0000 | [diff] [blame] | 395 | assertTraversalRootHashesAreNotEqual(v1, v2); |
| 396 | |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 397 | progressReceiver.clear(); |
| 398 | } |
| 399 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 400 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 401 | public void testTraversalOfSourceFile() throws Exception { |
| 402 | assertTraversalOfFile(sourceArtifact("foo/bar.txt")); |
| 403 | } |
| 404 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 405 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 406 | public void testTraversalOfGeneratedFile() throws Exception { |
| 407 | assertTraversalOfFile(derivedArtifact("foo/bar.txt")); |
| 408 | } |
| 409 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 410 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 411 | public void testTraversalOfSymlinkToFile() throws Exception { |
| 412 | Artifact linkNameArtifact = sourceArtifact("foo/baz/qux.sym"); |
| 413 | Artifact linkTargetArtifact = sourceArtifact("foo/bar/baz.txt"); |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 414 | PathFragment linkValue = PathFragment.create("../bar/baz.txt"); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 415 | TraversalRequest traversalRoot = fileLikeRoot(linkNameArtifact, DONT_CROSS); |
| 416 | createFile(linkTargetArtifact); |
| 417 | scratch.dir(linkNameArtifact.getExecPath().getParentDirectory().getPathString()); |
| 418 | rootDirectory.getRelative(linkNameArtifact.getExecPath()).createSymbolicLink(linkValue); |
| 419 | |
| 420 | // Assert that the SkyValue is built and looks right. |
| 421 | RootedPath symlinkNamePath = rootedPath(linkNameArtifact); |
| 422 | RootedPath symlinkTargetPath = rootedPath(linkTargetArtifact); |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 423 | ResolvedFile expected = symlinkToFileForTesting(symlinkTargetPath, symlinkNamePath, linkValue); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 424 | RecursiveFilesystemTraversalValue v1 = traverseAndAssertFiles(traversalRoot, expected); |
| 425 | assertThat(progressReceiver.invalidations).isEmpty(); |
janakr | 61377f7 | 2018-06-04 12:50:13 -0700 | [diff] [blame] | 426 | assertThat(progressReceiver.evaluations).contains(traversalRoot); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 427 | progressReceiver.clear(); |
| 428 | |
| 429 | // Edit the target of the symlink and verify that the value is rebuilt. |
| 430 | appendToFile(linkTargetArtifact, "bar"); |
| 431 | RecursiveFilesystemTraversalValue v2 = traverseAndAssertFiles(traversalRoot, expected); |
janakr | 5fb2a48 | 2018-03-02 17:48:57 -0800 | [diff] [blame] | 432 | assertThat(progressReceiver.invalidations).contains(traversalRoot); |
janakr | 61377f7 | 2018-06-04 12:50:13 -0700 | [diff] [blame] | 433 | assertThat(progressReceiver.evaluations).contains(traversalRoot); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 434 | assertThat(v2).isNotEqualTo(v1); |
Laszlo Csomor | 207140f | 2015-12-07 15:07:33 +0000 | [diff] [blame] | 435 | assertTraversalRootHashesAreNotEqual(v1, v2); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 436 | } |
| 437 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 438 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 439 | public void testTraversalOfTransitiveSymlinkToFile() throws Exception { |
| 440 | Artifact directLinkArtifact = sourceArtifact("direct/file.sym"); |
| 441 | Artifact transitiveLinkArtifact = sourceArtifact("transitive/sym.sym"); |
| 442 | RootedPath fileA = createFile(rootedPath(sourceArtifact("a/file.a"))); |
| 443 | RootedPath directLink = rootedPath(directLinkArtifact); |
| 444 | RootedPath transitiveLink = rootedPath(transitiveLinkArtifact); |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 445 | PathFragment directLinkPath = PathFragment.create("../a/file.a"); |
| 446 | PathFragment transitiveLinkPath = PathFragment.create("../direct/file.sym"); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 447 | |
| 448 | parentOf(directLink).asPath().createDirectory(); |
| 449 | parentOf(transitiveLink).asPath().createDirectory(); |
| 450 | directLink.asPath().createSymbolicLink(directLinkPath); |
| 451 | transitiveLink.asPath().createSymbolicLink(transitiveLinkPath); |
| 452 | |
| 453 | traverseAndAssertFiles( |
| 454 | fileLikeRoot(directLinkArtifact, DONT_CROSS), |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 455 | symlinkToFileForTesting(fileA, directLink, directLinkPath)); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 456 | |
| 457 | traverseAndAssertFiles( |
| 458 | fileLikeRoot(transitiveLinkArtifact, DONT_CROSS), |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 459 | symlinkToFileForTesting(fileA, transitiveLink, transitiveLinkPath)); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 460 | } |
| 461 | |
| 462 | private void assertTraversalOfDirectory(Artifact directoryArtifact) throws Exception { |
| 463 | // Create files under the directory. |
| 464 | // Use the root + root-relative path of the rootArtifact to create these files, rather than |
| 465 | // using the rootDirectory + execpath of the rootArtifact. The resulting paths are the same |
| 466 | // but the RootedPaths are different: |
| 467 | // in the 1st case, it is: RootedPath(/root/execroot, relative), in the second it is |
| 468 | // in the 2nd case, it is: RootedPath(/root, execroot/relative). |
| 469 | // Creating the files will also create the parent directories. |
| 470 | RootedPath file1 = createFile(childOf(directoryArtifact, "bar.txt")); |
| 471 | RootedPath file2 = createFile(childOf(directoryArtifact, "baz/qux.txt")); |
| 472 | |
| 473 | TraversalRequest traversalRoot = fileLikeRoot(directoryArtifact, DONT_CROSS); |
| 474 | |
| 475 | // Assert that the SkyValue is built and looks right. |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 476 | ResolvedFile expected1 = regularFileForTesting(file1); |
| 477 | ResolvedFile expected2 = regularFileForTesting(file2); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 478 | RecursiveFilesystemTraversalValue v1 = |
| 479 | traverseAndAssertFiles(traversalRoot, expected1, expected2); |
| 480 | assertThat(progressReceiver.invalidations).isEmpty(); |
janakr | 61377f7 | 2018-06-04 12:50:13 -0700 | [diff] [blame] | 481 | assertThat(progressReceiver.evaluations).contains(traversalRoot); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 482 | progressReceiver.clear(); |
| 483 | |
| 484 | // Add a new file to the directory and see that the value is rebuilt. |
laszlocsomor | 29bdf63 | 2018-03-13 02:50:46 -0700 | [diff] [blame] | 485 | TimestampGranularityUtils.waitForTimestampGranularity( |
| 486 | directoryArtifact.getPath().stat().getLastChangeTime(), OutErr.SYSTEM_OUT_ERR); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 487 | RootedPath file3 = createFile(childOf(directoryArtifact, "foo.txt")); |
felly | 5be4dd6 | 2018-02-05 11:11:53 -0800 | [diff] [blame] | 488 | if (directoryArtifact.isSourceArtifact()) { |
| 489 | invalidateDirectory(directoryArtifact); |
| 490 | } else { |
| 491 | invalidateOutputArtifact(directoryArtifact); |
| 492 | } |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 493 | ResolvedFile expected3 = regularFileForTesting(file3); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 494 | RecursiveFilesystemTraversalValue v2 = |
| 495 | traverseAndAssertFiles(traversalRoot, expected1, expected2, expected3); |
janakr | 5fb2a48 | 2018-03-02 17:48:57 -0800 | [diff] [blame] | 496 | assertThat(progressReceiver.invalidations).contains(traversalRoot); |
janakr | 61377f7 | 2018-06-04 12:50:13 -0700 | [diff] [blame] | 497 | assertThat(progressReceiver.evaluations).contains(traversalRoot); |
Laszlo Csomor | 207140f | 2015-12-07 15:07:33 +0000 | [diff] [blame] | 498 | // Directories always have the same hash code, but that is fine because their contents are also |
| 499 | // part of the RecursiveFilesystemTraversalValue, so v1 and v2 are unequal. |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 500 | assertThat(v2).isNotEqualTo(v1); |
Laszlo Csomor | 207140f | 2015-12-07 15:07:33 +0000 | [diff] [blame] | 501 | assertTraversalRootHashesAreEqual(v1, v2); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 502 | progressReceiver.clear(); |
| 503 | |
| 504 | // Edit a file in the directory and see that the value is rebuilt. |
felly | 5be4dd6 | 2018-02-05 11:11:53 -0800 | [diff] [blame] | 505 | RecursiveFilesystemTraversalValue v3; |
| 506 | if (directoryArtifact.isSourceArtifact()) { |
| 507 | SkyKey toInvalidate = FileStateValue.key(file1); |
| 508 | appendToFile(file1, toInvalidate, "bar"); |
| 509 | v3 = traverseAndAssertFiles(traversalRoot, expected1, expected2, expected3); |
janakr | 5fb2a48 | 2018-03-02 17:48:57 -0800 | [diff] [blame] | 510 | assertThat(progressReceiver.invalidations).contains(traversalRoot); |
janakr | 61377f7 | 2018-06-04 12:50:13 -0700 | [diff] [blame] | 511 | assertThat(progressReceiver.evaluations).contains(traversalRoot); |
felly | 5be4dd6 | 2018-02-05 11:11:53 -0800 | [diff] [blame] | 512 | assertThat(v3).isNotEqualTo(v2); |
| 513 | // Directories always have the same hash code, but that is fine because their contents are |
| 514 | // also part of the RecursiveFilesystemTraversalValue, so v2 and v3 are unequal. |
| 515 | assertTraversalRootHashesAreEqual(v2, v3); |
| 516 | progressReceiver.clear(); |
| 517 | } else { |
| 518 | // Dependency checking of output directories is unsound. Specifically, the directory mtime |
| 519 | // is not changed when a contained file is modified. |
| 520 | v3 = v2; |
| 521 | } |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 522 | |
| 523 | // Add a new file *outside* of the directory and see that the value is *not* rebuilt. |
| 524 | Artifact someFile = sourceArtifact("somewhere/else/a.file"); |
| 525 | createFile(someFile, "new file"); |
| 526 | appendToFile(someFile, "not all changes are treated equal"); |
| 527 | RecursiveFilesystemTraversalValue v4 = |
| 528 | traverseAndAssertFiles(traversalRoot, expected1, expected2, expected3); |
| 529 | assertThat(v4).isEqualTo(v3); |
Laszlo Csomor | 207140f | 2015-12-07 15:07:33 +0000 | [diff] [blame] | 530 | assertTraversalRootHashesAreEqual(v3, v4); |
janakr | 5fb2a48 | 2018-03-02 17:48:57 -0800 | [diff] [blame] | 531 | assertThat(progressReceiver.invalidations).doesNotContain(traversalRoot); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 532 | } |
| 533 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 534 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 535 | public void testTraversalOfSourceDirectory() throws Exception { |
| 536 | assertTraversalOfDirectory(sourceArtifact("dir")); |
| 537 | } |
| 538 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 539 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 540 | public void testTraversalOfGeneratedDirectory() throws Exception { |
| 541 | assertTraversalOfDirectory(derivedArtifact("dir")); |
| 542 | } |
| 543 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 544 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 545 | public void testTraversalOfTransitiveSymlinkToDirectory() throws Exception { |
| 546 | Artifact directLinkArtifact = sourceArtifact("direct/dir.sym"); |
| 547 | Artifact transitiveLinkArtifact = sourceArtifact("transitive/sym.sym"); |
| 548 | RootedPath fileA = createFile(rootedPath(sourceArtifact("a/file.a"))); |
| 549 | RootedPath directLink = rootedPath(directLinkArtifact); |
| 550 | RootedPath transitiveLink = rootedPath(transitiveLinkArtifact); |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 551 | PathFragment directLinkPath = PathFragment.create("../a"); |
| 552 | PathFragment transitiveLinkPath = PathFragment.create("../direct/dir.sym"); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 553 | |
| 554 | parentOf(directLink).asPath().createDirectory(); |
| 555 | parentOf(transitiveLink).asPath().createDirectory(); |
| 556 | directLink.asPath().createSymbolicLink(directLinkPath); |
| 557 | transitiveLink.asPath().createSymbolicLink(transitiveLinkPath); |
| 558 | |
| 559 | // Expect the file as if was a child of the direct symlink, not of the actual directory. |
| 560 | traverseAndAssertFiles( |
| 561 | fileLikeRoot(directLinkArtifact, DONT_CROSS), |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 562 | symlinkToDirectoryForTesting(parentOf(fileA), directLink, directLinkPath), |
| 563 | regularFileForTesting(childOf(directLinkArtifact, "file.a"))); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 564 | |
| 565 | // Expect the file as if was a child of the transitive symlink, not of the actual directory. |
| 566 | traverseAndAssertFiles( |
| 567 | fileLikeRoot(transitiveLinkArtifact, DONT_CROSS), |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 568 | symlinkToDirectoryForTesting(parentOf(fileA), transitiveLink, transitiveLinkPath), |
| 569 | regularFileForTesting(childOf(transitiveLinkArtifact, "file.a"))); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 570 | } |
| 571 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 572 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 573 | public void testTraversePackage() throws Exception { |
| 574 | Artifact buildFile = sourceArtifact("pkg/BUILD"); |
| 575 | RootedPath buildFilePath = createFile(rootedPath(buildFile)); |
| 576 | RootedPath file1 = createFile(siblingOf(buildFile, "subdir/file.a")); |
| 577 | |
| 578 | traverseAndAssertFiles( |
| 579 | pkgRoot(parentOf(buildFilePath), DONT_CROSS), |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 580 | regularFileForTesting(buildFilePath), |
| 581 | regularFileForTesting(file1)); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 582 | } |
| 583 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 584 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 585 | public void testTraversalOfSymlinkToDirectory() throws Exception { |
| 586 | Artifact linkNameArtifact = sourceArtifact("link/foo.sym"); |
| 587 | Artifact linkTargetArtifact = sourceArtifact("dir"); |
| 588 | RootedPath linkName = rootedPath(linkNameArtifact); |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 589 | PathFragment linkValue = PathFragment.create("../dir"); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 590 | RootedPath file1 = createFile(childOf(linkTargetArtifact, "file.1")); |
| 591 | createFile(childOf(linkTargetArtifact, "sub/file.2")); |
| 592 | scratch.dir(parentOf(linkName).asPath().getPathString()); |
| 593 | linkName.asPath().createSymbolicLink(linkValue); |
| 594 | |
| 595 | // Assert that the SkyValue is built and looks right. |
| 596 | TraversalRequest traversalRoot = fileLikeRoot(linkNameArtifact, DONT_CROSS); |
| 597 | ResolvedFile expected1 = |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 598 | symlinkToDirectoryForTesting(rootedPath(linkTargetArtifact), linkName, linkValue); |
| 599 | ResolvedFile expected2 = regularFileForTesting(childOf(linkNameArtifact, "file.1")); |
| 600 | ResolvedFile expected3 = regularFileForTesting(childOf(linkNameArtifact, "sub/file.2")); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 601 | // We expect to see all the files from the symlink'd directory, under the symlink's path, not |
| 602 | // under the symlink target's path. |
| 603 | RecursiveFilesystemTraversalValue v1 = |
| 604 | traverseAndAssertFiles(traversalRoot, expected1, expected2, expected3); |
| 605 | assertThat(progressReceiver.invalidations).isEmpty(); |
janakr | 61377f7 | 2018-06-04 12:50:13 -0700 | [diff] [blame] | 606 | assertThat(progressReceiver.evaluations).contains(traversalRoot); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 607 | progressReceiver.clear(); |
| 608 | |
| 609 | // Add a new file to the directory and see that the value is rebuilt. |
| 610 | createFile(childOf(linkTargetArtifact, "file.3")); |
| 611 | invalidateDirectory(linkTargetArtifact); |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 612 | ResolvedFile expected4 = regularFileForTesting(childOf(linkNameArtifact, "file.3")); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 613 | RecursiveFilesystemTraversalValue v2 = |
| 614 | traverseAndAssertFiles(traversalRoot, expected1, expected2, expected3, expected4); |
janakr | 5fb2a48 | 2018-03-02 17:48:57 -0800 | [diff] [blame] | 615 | assertThat(progressReceiver.invalidations).contains(traversalRoot); |
janakr | 61377f7 | 2018-06-04 12:50:13 -0700 | [diff] [blame] | 616 | assertThat(progressReceiver.evaluations).contains(traversalRoot); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 617 | assertThat(v2).isNotEqualTo(v1); |
Laszlo Csomor | 207140f | 2015-12-07 15:07:33 +0000 | [diff] [blame] | 618 | assertTraversalRootHashesAreNotEqual(v1, v2); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 619 | progressReceiver.clear(); |
| 620 | |
| 621 | // Edit a file in the directory and see that the value is rebuilt. |
| 622 | appendToFile(file1, "bar"); |
| 623 | RecursiveFilesystemTraversalValue v3 = |
| 624 | traverseAndAssertFiles(traversalRoot, expected1, expected2, expected3, expected4); |
janakr | 5fb2a48 | 2018-03-02 17:48:57 -0800 | [diff] [blame] | 625 | assertThat(progressReceiver.invalidations).contains(traversalRoot); |
janakr | 61377f7 | 2018-06-04 12:50:13 -0700 | [diff] [blame] | 626 | assertThat(progressReceiver.evaluations).contains(traversalRoot); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 627 | assertThat(v3).isNotEqualTo(v2); |
Laszlo Csomor | 207140f | 2015-12-07 15:07:33 +0000 | [diff] [blame] | 628 | assertTraversalRootHashesAreNotEqual(v2, v3); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 629 | progressReceiver.clear(); |
| 630 | |
| 631 | // Add a new file *outside* of the directory and see that the value is *not* rebuilt. |
| 632 | Artifact someFile = sourceArtifact("somewhere/else/a.file"); |
| 633 | createFile(someFile, "new file"); |
| 634 | appendToFile(someFile, "not all changes are treated equal"); |
| 635 | RecursiveFilesystemTraversalValue v4 = |
| 636 | traverseAndAssertFiles(traversalRoot, expected1, expected2, expected3, expected4); |
| 637 | assertThat(v4).isEqualTo(v3); |
Laszlo Csomor | 207140f | 2015-12-07 15:07:33 +0000 | [diff] [blame] | 638 | assertTraversalRootHashesAreEqual(v3, v4); |
janakr | 5fb2a48 | 2018-03-02 17:48:57 -0800 | [diff] [blame] | 639 | assertThat(progressReceiver.invalidations).doesNotContain(traversalRoot); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 640 | } |
| 641 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 642 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 643 | public void testTraversalOfDanglingSymlink() throws Exception { |
| 644 | Artifact linkArtifact = sourceArtifact("a/dangling.sym"); |
| 645 | RootedPath link = rootedPath(linkArtifact); |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 646 | PathFragment linkTarget = PathFragment.create("non_existent"); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 647 | parentOf(link).asPath().createDirectory(); |
| 648 | link.asPath().createSymbolicLink(linkTarget); |
| 649 | traverseAndAssertFiles( |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 650 | fileLikeRoot(linkArtifact, DONT_CROSS), danglingSymlinkForTesting(link, linkTarget)); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 651 | } |
| 652 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 653 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 654 | public void testTraversalOfDanglingSymlinkInADirectory() throws Exception { |
| 655 | Artifact dirArtifact = sourceArtifact("a"); |
| 656 | RootedPath file = createFile(childOf(dirArtifact, "file.txt")); |
| 657 | RootedPath link = rootedPath(sourceArtifact("a/dangling.sym")); |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 658 | PathFragment linkTarget = PathFragment.create("non_existent"); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 659 | parentOf(link).asPath().createDirectory(); |
| 660 | link.asPath().createSymbolicLink(linkTarget); |
| 661 | traverseAndAssertFiles( |
| 662 | fileLikeRoot(dirArtifact, DONT_CROSS), |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 663 | regularFileForTesting(file), |
| 664 | danglingSymlinkForTesting(link, linkTarget)); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 665 | } |
| 666 | |
| 667 | private void assertTraverseSubpackages(PackageBoundaryMode traverseSubpackages) throws Exception { |
| 668 | Artifact pkgDirArtifact = sourceArtifact("pkg1/foo"); |
| 669 | Artifact subpkgDirArtifact = sourceArtifact("pkg1/foo/subdir/subpkg"); |
| 670 | RootedPath pkgBuildFile = childOf(pkgDirArtifact, "BUILD"); |
| 671 | RootedPath subpkgBuildFile = childOf(subpkgDirArtifact, "BUILD"); |
| 672 | scratch.dir(rootedPath(pkgDirArtifact).asPath().getPathString()); |
| 673 | scratch.dir(rootedPath(subpkgDirArtifact).asPath().getPathString()); |
| 674 | createFile(pkgBuildFile); |
| 675 | createFile(subpkgBuildFile); |
| 676 | |
| 677 | TraversalRequest traversalRoot = pkgRoot(parentOf(pkgBuildFile), traverseSubpackages); |
| 678 | |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 679 | ResolvedFile expected1 = regularFileForTesting(pkgBuildFile); |
| 680 | ResolvedFile expected2 = regularFileForTesting(subpkgBuildFile); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 681 | switch (traverseSubpackages) { |
| 682 | case CROSS: |
| 683 | traverseAndAssertFiles(traversalRoot, expected1, expected2); |
| 684 | break; |
| 685 | case DONT_CROSS: |
| 686 | traverseAndAssertFiles(traversalRoot, expected1); |
| 687 | break; |
| 688 | case REPORT_ERROR: |
janakr | 5fb2a48 | 2018-03-02 17:48:57 -0800 | [diff] [blame] | 689 | SkyKey key = traversalRoot; |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 690 | EvaluationResult<SkyValue> result = eval(key); |
| 691 | assertThat(result.hasError()).isTrue(); |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 692 | assertThat(result.getError().getException()) |
| 693 | .hasMessageThat() |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 694 | .contains("crosses package boundary into package rooted at"); |
| 695 | break; |
| 696 | default: |
| 697 | throw new IllegalStateException(traverseSubpackages.toString()); |
| 698 | } |
| 699 | } |
| 700 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 701 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 702 | public void testTraverseSubpackages() throws Exception { |
| 703 | assertTraverseSubpackages(CROSS); |
| 704 | } |
| 705 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 706 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 707 | public void testDoNotTraverseSubpackages() throws Exception { |
| 708 | assertTraverseSubpackages(DONT_CROSS); |
| 709 | } |
| 710 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 711 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 712 | public void testReportErrorWhenTraversingSubpackages() throws Exception { |
| 713 | assertTraverseSubpackages(REPORT_ERROR); |
| 714 | } |
| 715 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 716 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 717 | public void testSwitchPackageRootsWhenUsingMultiplePackagePaths() throws Exception { |
| 718 | // Layout: |
| 719 | // pp1://a/BUILD |
| 720 | // pp1://a/file.a |
| 721 | // pp1://a/b.sym -> b/ (only created later) |
| 722 | // pp1://a/b/ |
| 723 | // pp1://a/b/file.fake |
| 724 | // pp1://a/subdir/file.b |
| 725 | // |
| 726 | // pp2://a/BUILD |
| 727 | // pp2://a/b/ |
| 728 | // pp2://a/b/BUILD |
| 729 | // pp2://a/b/file.a |
| 730 | // pp2://a/subdir.fake/ |
| 731 | // pp2://a/subdir.fake/file.fake |
| 732 | // |
| 733 | // Notice that pp1://a/b will be overlaid by pp2://a/b as the latter has a BUILD file and that |
| 734 | // takes precedence. On the other hand the package definition pp2://a/BUILD will be ignored |
| 735 | // since package //a is already defined under pp1. |
| 736 | // |
| 737 | // Notice also that pp1://a/b.sym is a relative symlink pointing to b/. This should be resolved |
| 738 | // to the definition of //a/b/ under pp1, not under pp2. |
| 739 | |
| 740 | // Set the package paths. |
John Cater | e0d1d0e | 2017-11-28 20:47:41 -0800 | [diff] [blame] | 741 | pkgLocator.set( |
| 742 | new PathPackageLocator( |
| 743 | outputBase, |
tomlu | ee6a686 | 2018-01-17 14:36:26 -0800 | [diff] [blame] | 744 | ImmutableList.of( |
| 745 | Root.fromPath(rootDirectory.getRelative("pp1")), |
| 746 | Root.fromPath(rootDirectory.getRelative("pp2"))), |
John Cater | e0d1d0e | 2017-11-28 20:47:41 -0800 | [diff] [blame] | 747 | BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY)); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 748 | PrecomputedValue.PATH_PACKAGE_LOCATOR.set(differencer, pkgLocator.get()); |
| 749 | |
| 750 | Artifact aBuildArtifact = sourceArtifactUnderPackagePath("a/BUILD", "pp1"); |
| 751 | Artifact bBuildArtifact = sourceArtifactUnderPackagePath("a/b/BUILD", "pp2"); |
| 752 | |
| 753 | RootedPath pp1aBuild = createFile(rootedPath(aBuildArtifact)); |
| 754 | RootedPath pp1aFileA = createFile(siblingOf(pp1aBuild, "file.a")); |
| 755 | RootedPath pp1bFileFake = createFile(siblingOf(pp1aBuild, "b/file.fake")); |
| 756 | RootedPath pp1aSubdirFileB = createFile(siblingOf(pp1aBuild, "subdir/file.b")); |
| 757 | |
| 758 | RootedPath pp2aBuild = createFile(rootedPath("a/BUILD", "pp2")); |
| 759 | RootedPath pp2bBuild = createFile(rootedPath(bBuildArtifact)); |
| 760 | RootedPath pp2bFileA = createFile(siblingOf(pp2bBuild, "file.a")); |
| 761 | createFile(siblingOf(pp2aBuild, "subdir.fake/file.fake")); |
| 762 | |
| 763 | // Traverse //a including subpackages. The result should contain the pp1-definition of //a and |
| 764 | // the pp2-definition of //a/b. |
| 765 | traverseAndAssertFiles( |
| 766 | pkgRoot(parentOf(rootedPath(aBuildArtifact)), CROSS), |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 767 | regularFileForTesting(pp1aBuild), |
| 768 | regularFileForTesting(pp1aFileA), |
| 769 | regularFileForTesting(pp1aSubdirFileB), |
| 770 | regularFileForTesting(pp2bBuild), |
| 771 | regularFileForTesting(pp2bFileA)); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 772 | |
| 773 | // Traverse //a excluding subpackages. The result should only contain files from //a and not |
| 774 | // from //a/b. |
| 775 | traverseAndAssertFiles( |
| 776 | pkgRoot(parentOf(rootedPath(aBuildArtifact)), DONT_CROSS), |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 777 | regularFileForTesting(pp1aBuild), |
| 778 | regularFileForTesting(pp1aFileA), |
| 779 | regularFileForTesting(pp1aSubdirFileB)); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 780 | |
| 781 | // Create a relative symlink pp1://a/b.sym -> b/. It will be resolved to the subdirectory |
| 782 | // pp1://a/b, even though a package definition pp2://a/b exists. |
| 783 | RootedPath pp1aBsym = siblingOf(pp1aFileA, "b.sym"); |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 784 | pp1aBsym.asPath().createSymbolicLink(PathFragment.create("b")); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 785 | invalidateDirectory(parentOf(pp1aBsym)); |
| 786 | |
| 787 | // Traverse //a excluding subpackages. The relative symlink //a/b.sym points to the subdirectory |
| 788 | // a/b, i.e. the pp1-definition, even though there is a pp2-defined package //a/b and we expect |
| 789 | // to see b.sym/b.fake (not b/b.fake). |
| 790 | traverseAndAssertFiles( |
| 791 | pkgRoot(parentOf(rootedPath(aBuildArtifact)), DONT_CROSS), |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 792 | regularFileForTesting(pp1aBuild), |
| 793 | regularFileForTesting(pp1aFileA), |
| 794 | regularFileForTesting(childOf(pp1aBsym, "file.fake")), |
nharmata | b4060b6 | 2017-04-04 17:11:39 +0000 | [diff] [blame] | 795 | symlinkToDirectoryForTesting(parentOf(pp1bFileFake), pp1aBsym, PathFragment.create("b")), |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 796 | regularFileForTesting(pp1aSubdirFileB)); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 797 | } |
| 798 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 799 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 800 | public void testFileDigestChangeCausesRebuild() throws Exception { |
| 801 | Artifact artifact = sourceArtifact("foo/bar.txt"); |
| 802 | RootedPath path = rootedPath(artifact); |
| 803 | createFile(path, "hello"); |
| 804 | |
| 805 | // Assert that the SkyValue is built and looks right. |
| 806 | TraversalRequest params = fileLikeRoot(artifact, DONT_CROSS); |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 807 | ResolvedFile expected = regularFileForTesting(path); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 808 | RecursiveFilesystemTraversalValue v1 = traverseAndAssertFiles(params, expected); |
janakr | 61377f7 | 2018-06-04 12:50:13 -0700 | [diff] [blame] | 809 | assertThat(progressReceiver.evaluations).contains(params); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 810 | progressReceiver.clear(); |
| 811 | |
| 812 | // Change the digest of the file. See that the value is rebuilt. |
| 813 | appendToFile(path, "world"); |
| 814 | RecursiveFilesystemTraversalValue v2 = traverseAndAssertFiles(params, expected); |
janakr | 5fb2a48 | 2018-03-02 17:48:57 -0800 | [diff] [blame] | 815 | assertThat(progressReceiver.invalidations).contains(params); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 816 | assertThat(v2).isNotEqualTo(v1); |
Laszlo Csomor | 207140f | 2015-12-07 15:07:33 +0000 | [diff] [blame] | 817 | assertTraversalRootHashesAreNotEqual(v1, v2); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 818 | } |
| 819 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 820 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 821 | public void testFileMtimeChangeDoesNotCauseRebuildIfDigestIsUnchanged() throws Exception { |
| 822 | Artifact artifact = sourceArtifact("foo/bar.txt"); |
| 823 | RootedPath path = rootedPath(artifact); |
| 824 | createFile(path, "hello"); |
| 825 | |
| 826 | // Assert that the SkyValue is built and looks right. |
| 827 | TraversalRequest params = fileLikeRoot(artifact, DONT_CROSS); |
Laszlo Csomor | e9c41c5 | 2015-12-07 10:32:26 +0000 | [diff] [blame] | 828 | ResolvedFile expected = regularFileForTesting(path); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 829 | RecursiveFilesystemTraversalValue v1 = traverseAndAssertFiles(params, expected); |
janakr | 61377f7 | 2018-06-04 12:50:13 -0700 | [diff] [blame] | 830 | assertThat(progressReceiver.evaluations).contains(params); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 831 | progressReceiver.clear(); |
| 832 | |
| 833 | // Change the mtime of the file but not the digest. See that the value is *not* rebuilt. |
laszlocsomor | 29bdf63 | 2018-03-13 02:50:46 -0700 | [diff] [blame] | 834 | TimestampGranularityUtils.waitForTimestampGranularity( |
| 835 | path.asPath().stat().getLastChangeTime(), OutErr.SYSTEM_OUT_ERR); |
Laszlo Csomor | a31e035 | 2018-03-09 04:51:38 -0800 | [diff] [blame] | 836 | path.asPath().setLastModifiedTime(System.currentTimeMillis()); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 837 | RecursiveFilesystemTraversalValue v2 = traverseAndAssertFiles(params, expected); |
| 838 | assertThat(v2).isEqualTo(v1); |
Laszlo Csomor | 207140f | 2015-12-07 15:07:33 +0000 | [diff] [blame] | 839 | assertTraversalRootHashesAreEqual(v1, v2); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 840 | } |
| 841 | |
Florian Weikert | 92b2236 | 2015-12-03 10:17:18 +0000 | [diff] [blame] | 842 | @Test |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 843 | public void testGeneratedDirectoryConflictsWithPackage() throws Exception { |
| 844 | Artifact genDir = derivedArtifact("a/b"); |
| 845 | createFile(rootedPath(sourceArtifact("a/b/c/file.real"))); |
| 846 | createFile(rootedPath(derivedArtifact("a/b/c/file.fake"))); |
| 847 | createFile(sourceArtifact("a/b/c/BUILD")); |
| 848 | |
janakr | 5fb2a48 | 2018-03-02 17:48:57 -0800 | [diff] [blame] | 849 | SkyKey key = fileLikeRoot(genDir, CROSS); |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 850 | EvaluationResult<SkyValue> result = eval(key); |
| 851 | assertThat(result.hasError()).isTrue(); |
| 852 | ErrorInfo error = result.getError(key); |
nharmata | bea67e9 | 2017-06-16 00:26:27 +0200 | [diff] [blame] | 853 | assertThat(error.isTransitivelyTransient()).isFalse(); |
lberki | aea56b3 | 2017-05-30 12:35:33 +0200 | [diff] [blame] | 854 | assertThat(error.getException()) |
| 855 | .hasMessageThat() |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 856 | .contains("Generated directory a/b/c conflicts with package under the same path."); |
| 857 | } |
kush | 95bf7c8 | 2017-08-30 00:27:35 +0200 | [diff] [blame] | 858 | |
| 859 | @Test |
| 860 | public void unboundedSymlinkExpansionError() throws Exception { |
| 861 | Artifact bazLink = sourceArtifact("foo/baz.sym"); |
| 862 | Path parentDir = scratch.dir("foo"); |
| 863 | bazLink.getPath().createSymbolicLink(parentDir); |
janakr | 5fb2a48 | 2018-03-02 17:48:57 -0800 | [diff] [blame] | 864 | SkyKey key = pkgRoot(parentOf(rootedPath(bazLink)), DONT_CROSS); |
kush | 95bf7c8 | 2017-08-30 00:27:35 +0200 | [diff] [blame] | 865 | EvaluationResult<SkyValue> result = eval(key); |
| 866 | assertThat(result.hasError()).isTrue(); |
| 867 | ErrorInfo error = result.getError(key); |
| 868 | assertThat(error.getException()).isInstanceOf(FileOperationException.class); |
| 869 | assertThat(error.getException()).hasMessageThat().contains("Infinite symlink expansion"); |
| 870 | } |
| 871 | |
| 872 | @Test |
| 873 | public void symlinkChainError() throws Exception { |
| 874 | scratch.dir("a"); |
| 875 | Artifact fooLink = sourceArtifact("a/foo.sym"); |
| 876 | Artifact barLink = sourceArtifact("a/bar.sym"); |
| 877 | Artifact bazLink = sourceArtifact("a/baz.sym"); |
| 878 | fooLink.getPath().createSymbolicLink(barLink.getPath()); |
| 879 | barLink.getPath().createSymbolicLink(bazLink.getPath()); |
| 880 | bazLink.getPath().createSymbolicLink(fooLink.getPath()); |
| 881 | |
janakr | 5fb2a48 | 2018-03-02 17:48:57 -0800 | [diff] [blame] | 882 | SkyKey key = pkgRoot(parentOf(rootedPath(bazLink)), DONT_CROSS); |
kush | 95bf7c8 | 2017-08-30 00:27:35 +0200 | [diff] [blame] | 883 | EvaluationResult<SkyValue> result = eval(key); |
| 884 | assertThat(result.hasError()).isTrue(); |
| 885 | ErrorInfo error = result.getError(key); |
| 886 | assertThat(error.getException()).isInstanceOf(FileOperationException.class); |
| 887 | assertThat(error.getException()).hasMessageThat().contains("Symlink cycle"); |
| 888 | } |
felly | 5be4dd6 | 2018-02-05 11:11:53 -0800 | [diff] [blame] | 889 | |
| 890 | private static class ArtifactFakeFunction implements SkyFunction { |
| 891 | @Nullable |
| 892 | @Override |
| 893 | public SkyValue compute(SkyKey skyKey, Environment env) |
| 894 | throws SkyFunctionException, InterruptedException { |
felly | 1eeba9c | 2018-02-05 14:32:51 -0800 | [diff] [blame] | 895 | ArtifactSkyKey artifactKey = (ArtifactSkyKey) skyKey.argument(); |
| 896 | Artifact artifact = artifactKey.getArtifact(); |
felly | 5be4dd6 | 2018-02-05 11:11:53 -0800 | [diff] [blame] | 897 | try { |
| 898 | return FileArtifactValue.create(artifact.getPath()); |
| 899 | } catch (IOException e) { |
| 900 | throw new SkyFunctionException(e, Transience.PERSISTENT){}; |
| 901 | } |
| 902 | } |
| 903 | |
| 904 | @Nullable |
| 905 | @Override |
| 906 | public String extractTag(SkyKey skyKey) { |
| 907 | return null; |
| 908 | } |
| 909 | } |
Han-Wen Nienhuys | 81b9083 | 2015-10-26 16:57:27 +0000 | [diff] [blame] | 910 | } |