blob: aaf0c5f9b34014ad9cd4762b643fda7b334cd500 [file] [log] [blame]
ulfjack4f647e82017-05-09 07:45:40 -04001// Copyright 2017 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.
14package com.google.devtools.build.lib.pkgcache;
15
lberkibf6ef0f2017-05-29 11:00:40 +020016import static com.google.common.truth.Truth.assertThat;
ulfjack4f647e82017-05-09 07:45:40 -040017
ulfjack4f647e82017-05-09 07:45:40 -040018import com.google.common.collect.ImmutableList;
19import com.google.common.collect.ImmutableMap;
20import com.google.common.collect.ImmutableSet;
tomlu3d1a1942017-11-29 14:01:21 -080021import com.google.devtools.build.lib.actions.ActionKeyContext;
ulfjack4f647e82017-05-09 07:45:40 -040022import com.google.devtools.build.lib.analysis.BlazeDirectories;
23import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
janakr3b63a4e2017-09-14 09:55:40 +020024import com.google.devtools.build.lib.analysis.ServerDirectories;
ulfjack4f647e82017-05-09 07:45:40 -040025import com.google.devtools.build.lib.analysis.util.AnalysisMock;
26import com.google.devtools.build.lib.cmdline.PackageIdentifier;
27import com.google.devtools.build.lib.packages.NoSuchPackageException;
28import com.google.devtools.build.lib.packages.Package;
brandjon674ab862017-10-06 23:17:33 +020029import com.google.devtools.build.lib.packages.SkylarkSemanticsOptions;
janakr5e606e62017-07-19 22:40:20 +020030import com.google.devtools.build.lib.skyframe.BazelSkyframeExecutorConstants;
ulfjack4f647e82017-05-09 07:45:40 -040031import com.google.devtools.build.lib.skyframe.DiffAwareness;
ulfjack4f647e82017-05-09 07:45:40 -040032import com.google.devtools.build.lib.skyframe.SequencedSkyframeExecutor;
33import com.google.devtools.build.lib.skyframe.SkyValueDirtinessChecker;
34import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
ulfjack4f647e82017-05-09 07:45:40 -040035import com.google.devtools.build.lib.testutil.FoundationTestCase;
36import com.google.devtools.build.lib.testutil.ManualClock;
janakr150858b2017-07-25 00:04:53 +020037import com.google.devtools.build.lib.testutil.TestConstants;
ulfjack4f647e82017-05-09 07:45:40 -040038import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
39import com.google.devtools.build.lib.vfs.FileSystem;
40import com.google.devtools.build.lib.vfs.FileSystemUtils;
41import com.google.devtools.build.lib.vfs.ModifiedFileSet;
42import com.google.devtools.build.lib.vfs.Path;
tomluee6a6862018-01-17 14:36:26 -080043import com.google.devtools.build.lib.vfs.Root;
ulfjack4f647e82017-05-09 07:45:40 -040044import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem;
45import com.google.devtools.common.options.OptionsParser;
46import java.nio.charset.StandardCharsets;
47import java.util.UUID;
48import java.util.logging.Level;
49import java.util.logging.Logger;
50import org.junit.Before;
51import org.junit.Test;
52import org.junit.runner.RunWith;
53import org.junit.runners.JUnit4;
54
55/**
56 * Tests for package loading.
57 */
58@RunWith(JUnit4.class)
59public class BuildFileModificationTest extends FoundationTestCase {
60
61 private ManualClock clock = new ManualClock();
62 private AnalysisMock analysisMock;
63 private ConfiguredRuleClassProvider ruleClassProvider;
64 private SkyframeExecutor skyframeExecutor;
tomlu3d1a1942017-11-29 14:01:21 -080065 private final ActionKeyContext actionKeyContext = new ActionKeyContext();
ulfjack4f647e82017-05-09 07:45:40 -040066
67 @Before
68 public final void disableLogging() throws Exception {
69 Logger.getLogger("com.google.devtools").setLevel(Level.SEVERE);
70 }
71
72 @Before
73 public final void initializeSkyframeExecutor() throws Exception {
74 analysisMock = AnalysisMock.get();
75 ruleClassProvider = analysisMock.createRuleClassProvider();
76 BlazeDirectories directories =
janakr3b63a4e2017-09-14 09:55:40 +020077 new BlazeDirectories(
78 new ServerDirectories(outputBase, outputBase),
79 rootDirectory,
80 analysisMock.getProductName());
ulfjack4f647e82017-05-09 07:45:40 -040081 skyframeExecutor =
janakr5e606e62017-07-19 22:40:20 +020082 SequencedSkyframeExecutor.create(
ulfjack4f647e82017-05-09 07:45:40 -040083 analysisMock
janakr52d05e82017-09-22 13:27:14 -040084 .getPackageFactoryBuilderForTesting(directories)
nharmatad922e652017-05-17 20:29:19 +020085 .build(ruleClassProvider, scratch.getFileSystem()),
tomluf903eb52017-10-27 12:12:11 -040086 fileSystem,
ulfjack4f647e82017-05-09 07:45:40 -040087 directories,
tomlu3d1a1942017-11-29 14:01:21 -080088 actionKeyContext,
ulfjack4f647e82017-05-09 07:45:40 -040089 null, /* workspaceStatusActionFactory */
90 ruleClassProvider.getBuildInfoFactories(),
91 ImmutableList.<DiffAwareness.Factory>of(),
janakr52d05e82017-09-22 13:27:14 -040092 analysisMock.getSkyFunctions(directories),
ulfjack4f647e82017-05-09 07:45:40 -040093 ImmutableList.<SkyValueDirtinessChecker>of(),
nharmatae4eb23f2017-12-05 09:27:45 -080094 BazelSkyframeExecutorConstants.HARDCODED_BLACKLISTED_PACKAGE_PREFIXES,
95 BazelSkyframeExecutorConstants.ADDITIONAL_BLACKLISTED_PACKAGE_PREFIXES_FILE,
janakr5e606e62017-07-19 22:40:20 +020096 BazelSkyframeExecutorConstants.CROSS_REPOSITORY_LABEL_VIOLATION_STRATEGY,
97 BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY,
98 BazelSkyframeExecutorConstants.ACTION_ON_IO_EXCEPTION_READING_BUILD_FILE);
janakr150858b2017-07-25 00:04:53 +020099 TestConstants.processSkyframeExecutorForTesting(skyframeExecutor);
ulfjack4f647e82017-05-09 07:45:40 -0400100 OptionsParser parser = OptionsParser.newOptionsParser(
101 PackageCacheOptions.class, SkylarkSemanticsOptions.class);
102 analysisMock.getInvocationPolicyEnforcer().enforce(parser);
103 setUpSkyframe(
104 parser.getOptions(PackageCacheOptions.class),
105 parser.getOptions(SkylarkSemanticsOptions.class));
106 }
107
108 private void setUpSkyframe(
109 PackageCacheOptions packageCacheOptions,
110 SkylarkSemanticsOptions skylarkSemanticsOptions) {
John Catere0d1d0e2017-11-28 20:47:41 -0800111 PathPackageLocator pkgLocator =
112 PathPackageLocator.create(
113 null,
114 packageCacheOptions.packagePath,
115 reporter,
116 rootDirectory,
117 rootDirectory,
118 BazelSkyframeExecutorConstants.BUILD_FILES_BY_PRIORITY);
ulfjack4f647e82017-05-09 07:45:40 -0400119 packageCacheOptions.showLoadingProgress = true;
120 packageCacheOptions.globbingThreads = 7;
121 skyframeExecutor.preparePackageLoading(
122 pkgLocator,
123 packageCacheOptions,
124 skylarkSemanticsOptions,
125 analysisMock.getDefaultsPackageContent(),
126 UUID.randomUUID(),
127 ImmutableMap.<String, String>of(),
128 ImmutableMap.<String, String>of(),
129 new TimestampGranularityMonitor(clock));
130 skyframeExecutor.setDeletedPackages(
131 ImmutableSet.copyOf(packageCacheOptions.getDeletedPackages()));
132 }
133
134 @Override
135 protected FileSystem createFileSystem() {
136 return new InMemoryFileSystem(clock);
137 }
138
139 private void invalidatePackages() throws InterruptedException {
140 skyframeExecutor.invalidateFilesUnderPathForTesting(
tomluee6a6862018-01-17 14:36:26 -0800141 reporter, ModifiedFileSet.EVERYTHING_MODIFIED, Root.fromPath(rootDirectory));
ulfjack4f647e82017-05-09 07:45:40 -0400142 }
143
144 private Package getPackage(String packageName)
145 throws NoSuchPackageException, InterruptedException {
146 return skyframeExecutor.getPackageManager().getPackage(reporter,
147 PackageIdentifier.createInMainRepo(packageName));
148 }
149
150 @Test
151 public void testCTimeChangeDetectedWithError() throws Exception {
152 reporter.removeHandler(failFastHandler);
153 Path build = scratch.file(
154 "a/BUILD", "cc_library(name='a', feet='stinky')".getBytes(StandardCharsets.ISO_8859_1));
155 Package a1 = getPackage("a");
lberkibf6ef0f2017-05-29 11:00:40 +0200156 assertThat(a1.containsErrors()).isTrue();
ulfjack4f647e82017-05-09 07:45:40 -0400157 assertContainsEvent("//a:a: no such attribute 'feet'");
158 eventCollector.clear();
159 // writeContent updates mtime and ctime. Note that we keep the content length exactly the same.
160 clock.advanceMillis(1);
161 FileSystemUtils.writeContent(
162 build, "cc_library(name='a', srcs=['a.cc'])".getBytes(StandardCharsets.ISO_8859_1));
163
164 invalidatePackages();
165 Package a2 = getPackage("a");
lberkibf6ef0f2017-05-29 11:00:40 +0200166 assertThat(a2).isNotSameAs(a1);
167 assertThat(a2.containsErrors()).isFalse();
ulfjack4f647e82017-05-09 07:45:40 -0400168 assertNoEvents();
169 }
170
171 @Test
172 public void testCTimeChangeDetected() throws Exception {
173 Path path = scratch.file(
174 "pkg/BUILD", "cc_library(name = 'foo')\n".getBytes(StandardCharsets.ISO_8859_1));
175 Package oldPkg = getPackage("pkg");
176
177 // Note that the content has exactly the same length as before.
178 clock.advanceMillis(1);
179 FileSystemUtils.writeContent(
180 path, "cc_library(name = 'bar')\n".getBytes(StandardCharsets.ISO_8859_1));
lberkibf6ef0f2017-05-29 11:00:40 +0200181 assertThat(getPackage("pkg"))
182 .isSameAs(oldPkg); // Change only becomes visible after invalidatePackages.
ulfjack4f647e82017-05-09 07:45:40 -0400183
184 invalidatePackages();
185
186 Package newPkg = getPackage("pkg");
lberkibf6ef0f2017-05-29 11:00:40 +0200187 assertThat(newPkg).isNotSameAs(oldPkg);
188 assertThat(newPkg.getTarget("bar")).isNotNull();
ulfjack4f647e82017-05-09 07:45:40 -0400189 }
190
191 @Test
192 public void testLengthChangeDetected() throws Exception {
193 reporter.removeHandler(failFastHandler);
194 Path build = scratch.file(
195 "a/BUILD", "cc_library(name='a', srcs=['a.cc'])".getBytes(StandardCharsets.ISO_8859_1));
196 Package a1 = getPackage("a");
197 eventCollector.clear();
198 // Note that we didn't advance the clock, so ctime/mtime is the same as before.
199 // However, the file contents are one byte longer.
200 FileSystemUtils.writeContent(
201 build, "cc_library(name='ab', srcs=['a.cc'])".getBytes(StandardCharsets.ISO_8859_1));
202
203 invalidatePackages();
204 Package a2 = getPackage("a");
lberkibf6ef0f2017-05-29 11:00:40 +0200205 assertThat(a2).isNotSameAs(a1);
ulfjack4f647e82017-05-09 07:45:40 -0400206 assertNoEvents();
207 }
208
209 @Test
210 public void testTouchedBuildFileCausesReloadAfterSync() throws Exception {
211 Path path = scratch.file("pkg/BUILD",
212 "cc_library(name = 'foo')");
213
214 Package oldPkg = getPackage("pkg");
215 // Change ctime to 1.
216 clock.advanceMillis(1);
217 path.setLastModifiedTime(1001);
lberkibf6ef0f2017-05-29 11:00:40 +0200218 assertThat(getPackage("pkg")).isSameAs(oldPkg); // change not yet visible
ulfjack4f647e82017-05-09 07:45:40 -0400219
220 invalidatePackages();
221
222 Package newPkg = getPackage("pkg");
lberkibf6ef0f2017-05-29 11:00:40 +0200223 assertThat(newPkg).isNotSameAs(oldPkg);
ulfjack4f647e82017-05-09 07:45:40 -0400224 }
225}