aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com/google/devtools/build/lib/pkgcache/BuildFileModificationTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/java/com/google/devtools/build/lib/pkgcache/BuildFileModificationTest.java')
-rw-r--r--src/test/java/com/google/devtools/build/lib/pkgcache/BuildFileModificationTest.java216
1 files changed, 216 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/pkgcache/BuildFileModificationTest.java b/src/test/java/com/google/devtools/build/lib/pkgcache/BuildFileModificationTest.java
new file mode 100644
index 0000000000..91297b50b1
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/pkgcache/BuildFileModificationTest.java
@@ -0,0 +1,216 @@
+// Copyright 2017 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.pkgcache;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.analysis.BlazeDirectories;
+import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
+import com.google.devtools.build.lib.analysis.util.AnalysisMock;
+import com.google.devtools.build.lib.cmdline.PackageIdentifier;
+import com.google.devtools.build.lib.packages.NoSuchPackageException;
+import com.google.devtools.build.lib.packages.Package;
+import com.google.devtools.build.lib.skyframe.DiffAwareness;
+import com.google.devtools.build.lib.skyframe.PackageLookupFunction.CrossRepositoryLabelViolationStrategy;
+import com.google.devtools.build.lib.skyframe.PackageLookupValue.BuildFileName;
+import com.google.devtools.build.lib.skyframe.PrecomputedValue;
+import com.google.devtools.build.lib.skyframe.SequencedSkyframeExecutor;
+import com.google.devtools.build.lib.skyframe.SkyValueDirtinessChecker;
+import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
+import com.google.devtools.build.lib.syntax.SkylarkSemanticsOptions;
+import com.google.devtools.build.lib.testutil.FoundationTestCase;
+import com.google.devtools.build.lib.testutil.ManualClock;
+import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
+import com.google.devtools.build.lib.vfs.FileSystem;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
+import com.google.devtools.build.lib.vfs.ModifiedFileSet;
+import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem;
+import com.google.devtools.common.options.OptionsParser;
+import java.nio.charset.StandardCharsets;
+import java.util.UUID;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for package loading.
+ */
+@RunWith(JUnit4.class)
+public class BuildFileModificationTest extends FoundationTestCase {
+
+ private ManualClock clock = new ManualClock();
+ private AnalysisMock analysisMock;
+ private ConfiguredRuleClassProvider ruleClassProvider;
+ private SkyframeExecutor skyframeExecutor;
+
+ @Before
+ public final void disableLogging() throws Exception {
+ Logger.getLogger("com.google.devtools").setLevel(Level.SEVERE);
+ }
+
+ @Before
+ public final void initializeSkyframeExecutor() throws Exception {
+ analysisMock = AnalysisMock.get();
+ ruleClassProvider = analysisMock.createRuleClassProvider();
+ BlazeDirectories directories =
+ new BlazeDirectories(outputBase, outputBase, rootDirectory, analysisMock.getProductName());
+ skyframeExecutor =
+ SequencedSkyframeExecutor.create(
+ analysisMock
+ .getPackageFactoryForTesting()
+ .create(ruleClassProvider, scratch.getFileSystem()),
+ directories,
+ null, /* BinTools */
+ null, /* workspaceStatusActionFactory */
+ ruleClassProvider.getBuildInfoFactories(),
+ ImmutableList.<DiffAwareness.Factory>of(),
+ Predicates.<PathFragment>alwaysFalse(),
+ AnalysisMock.get().getSkyFunctions(),
+ ImmutableList.<PrecomputedValue.Injected>of(),
+ ImmutableList.<SkyValueDirtinessChecker>of(),
+ analysisMock.getProductName(),
+ CrossRepositoryLabelViolationStrategy.ERROR,
+ ImmutableList.of(BuildFileName.BUILD_DOT_BAZEL, BuildFileName.BUILD));
+ OptionsParser parser = OptionsParser.newOptionsParser(
+ PackageCacheOptions.class, SkylarkSemanticsOptions.class);
+ analysisMock.getInvocationPolicyEnforcer().enforce(parser);
+ setUpSkyframe(
+ parser.getOptions(PackageCacheOptions.class),
+ parser.getOptions(SkylarkSemanticsOptions.class));
+ }
+
+ private void setUpSkyframe(
+ PackageCacheOptions packageCacheOptions,
+ SkylarkSemanticsOptions skylarkSemanticsOptions) {
+ PathPackageLocator pkgLocator = PathPackageLocator.create(
+ null, packageCacheOptions.packagePath, reporter, rootDirectory, rootDirectory);
+ packageCacheOptions.showLoadingProgress = true;
+ packageCacheOptions.globbingThreads = 7;
+ skyframeExecutor.preparePackageLoading(
+ pkgLocator,
+ packageCacheOptions,
+ skylarkSemanticsOptions,
+ analysisMock.getDefaultsPackageContent(),
+ UUID.randomUUID(),
+ ImmutableMap.<String, String>of(),
+ ImmutableMap.<String, String>of(),
+ new TimestampGranularityMonitor(clock));
+ skyframeExecutor.setDeletedPackages(
+ ImmutableSet.copyOf(packageCacheOptions.getDeletedPackages()));
+ }
+
+ @Override
+ protected FileSystem createFileSystem() {
+ return new InMemoryFileSystem(clock);
+ }
+
+ private void invalidatePackages() throws InterruptedException {
+ skyframeExecutor.invalidateFilesUnderPathForTesting(
+ reporter, ModifiedFileSet.EVERYTHING_MODIFIED, rootDirectory);
+ }
+
+ private Package getPackage(String packageName)
+ throws NoSuchPackageException, InterruptedException {
+ return skyframeExecutor.getPackageManager().getPackage(reporter,
+ PackageIdentifier.createInMainRepo(packageName));
+ }
+
+ @Test
+ public void testCTimeChangeDetectedWithError() throws Exception {
+ reporter.removeHandler(failFastHandler);
+ Path build = scratch.file(
+ "a/BUILD", "cc_library(name='a', feet='stinky')".getBytes(StandardCharsets.ISO_8859_1));
+ Package a1 = getPackage("a");
+ assertTrue(a1.containsErrors());
+ assertContainsEvent("//a:a: no such attribute 'feet'");
+ eventCollector.clear();
+ // writeContent updates mtime and ctime. Note that we keep the content length exactly the same.
+ clock.advanceMillis(1);
+ FileSystemUtils.writeContent(
+ build, "cc_library(name='a', srcs=['a.cc'])".getBytes(StandardCharsets.ISO_8859_1));
+
+ invalidatePackages();
+ Package a2 = getPackage("a");
+ assertNotSame(a1, a2);
+ assertFalse(a2.containsErrors());
+ assertNoEvents();
+ }
+
+ @Test
+ public void testCTimeChangeDetected() throws Exception {
+ Path path = scratch.file(
+ "pkg/BUILD", "cc_library(name = 'foo')\n".getBytes(StandardCharsets.ISO_8859_1));
+ Package oldPkg = getPackage("pkg");
+
+ // Note that the content has exactly the same length as before.
+ clock.advanceMillis(1);
+ FileSystemUtils.writeContent(
+ path, "cc_library(name = 'bar')\n".getBytes(StandardCharsets.ISO_8859_1));
+ assertSame(oldPkg, getPackage("pkg")); // Change only becomes visible after invalidatePackages.
+
+ invalidatePackages();
+
+ Package newPkg = getPackage("pkg");
+ assertNotSame(oldPkg, newPkg);
+ assertNotNull(newPkg.getTarget("bar"));
+ }
+
+ @Test
+ public void testLengthChangeDetected() throws Exception {
+ reporter.removeHandler(failFastHandler);
+ Path build = scratch.file(
+ "a/BUILD", "cc_library(name='a', srcs=['a.cc'])".getBytes(StandardCharsets.ISO_8859_1));
+ Package a1 = getPackage("a");
+ eventCollector.clear();
+ // Note that we didn't advance the clock, so ctime/mtime is the same as before.
+ // However, the file contents are one byte longer.
+ FileSystemUtils.writeContent(
+ build, "cc_library(name='ab', srcs=['a.cc'])".getBytes(StandardCharsets.ISO_8859_1));
+
+ invalidatePackages();
+ Package a2 = getPackage("a");
+ assertNotSame(a1, a2);
+ assertNoEvents();
+ }
+
+ @Test
+ public void testTouchedBuildFileCausesReloadAfterSync() throws Exception {
+ Path path = scratch.file("pkg/BUILD",
+ "cc_library(name = 'foo')");
+
+ Package oldPkg = getPackage("pkg");
+ // Change ctime to 1.
+ clock.advanceMillis(1);
+ path.setLastModifiedTime(1001);
+ assertSame(oldPkg, getPackage("pkg")); // change not yet visible
+
+ invalidatePackages();
+
+ Package newPkg = getPackage("pkg");
+ assertNotSame(oldPkg, newPkg);
+ }
+}