| // Copyright 2020 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.query2.query.output; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import com.google.common.collect.ImmutableMap; |
| import com.google.devtools.build.lib.packages.Attribute; |
| import com.google.devtools.build.lib.packages.Rule; |
| import com.google.devtools.build.lib.packages.util.PackageLoadingTestCase; |
| import com.google.devtools.build.lib.query2.proto.proto2api.Build; |
| import com.google.devtools.build.lib.query2.proto.proto2api.Build.Attribute.Discriminator; |
| import com.google.devtools.build.lib.vfs.DigestHashFunction; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| |
| /** Tests for {@link SyntheticAttributeHashCalculator}. */ |
| @RunWith(JUnit4.class) |
| public class SyntheticAttributeHashCalculatorTest extends PackageLoadingTestCase { |
| |
| @Test |
| public void testComputeAttributeChangeChangesHash() throws Exception { |
| scratch.file("pkg/BUILD", "genrule(name='x', cmd='touch $@', outs=['y'])"); |
| Rule ruleBefore = (Rule) getTarget("//pkg:x"); |
| |
| scratch.overwriteFile("pkg/BUILD", "genrule(name='x', cmd='touch $@', outs=['z'])"); |
| invalidatePackages(); |
| Rule ruleAfter = (Rule) getTarget("//pkg:x"); |
| |
| String hashBefore = |
| SyntheticAttributeHashCalculator.compute( |
| ruleBefore, |
| /* serializedAttributes= */ ImmutableMap.of(), |
| /* extraDataForAttrHash= */ "", |
| DigestHashFunction.SHA256.getHashFunction(), |
| /* includeAttributeSourceAspects= */ false); |
| String hashAfter = |
| SyntheticAttributeHashCalculator.compute( |
| ruleAfter, |
| /* serializedAttributes= */ ImmutableMap.of(), |
| /* extraDataForAttrHash= */ "", |
| DigestHashFunction.SHA256.getHashFunction(), |
| /* includeAttributeSourceAspects= */ false); |
| |
| assertThat(hashBefore).isNotEqualTo(hashAfter); |
| } |
| |
| @Test |
| public void testComputeLocationDoesntChangeHash() throws Exception { |
| scratch.file("pkg/BUILD", "genrule(name='x', cmd='touch $@', outs=['y'])"); |
| Rule ruleBefore = (Rule) getTarget("//pkg:x"); |
| |
| scratch.overwriteFile( |
| "pkg/BUILD", |
| """ |
| genrule( |
| name = "rule_that_moves_x", |
| outs = ["whatever"], |
| cmd = "touch $@", |
| ) |
| |
| genrule( |
| name = "x", |
| outs = ["y"], |
| cmd = "touch $@", |
| ) |
| """); |
| invalidatePackages(); |
| Rule ruleAfter = (Rule) getTarget("//pkg:x"); |
| |
| String hashBefore = |
| SyntheticAttributeHashCalculator.compute( |
| ruleBefore, |
| /* serializedAttributes= */ ImmutableMap.of(), |
| /* extraDataForAttrHash= */ "", |
| DigestHashFunction.SHA256.getHashFunction(), |
| /* includeAttributeSourceAspects= */ false); |
| String hashAfter = |
| SyntheticAttributeHashCalculator.compute( |
| ruleAfter, |
| /* serializedAttributes= */ ImmutableMap.of(), |
| /* extraDataForAttrHash= */ "", |
| DigestHashFunction.SHA256.getHashFunction(), |
| /* includeAttributeSourceAspects= */ false); |
| |
| assertThat(hashBefore).isEqualTo(hashAfter); |
| } |
| |
| @Test |
| public void testComputeSerializedAttributesUsedOverAvailable() throws Exception { |
| scratch.file("pkg/BUILD", "genrule(name='x', cmd='touch $@', outs=['y'])"); |
| Rule rule = (Rule) getTarget("//pkg:x"); |
| |
| String hashBefore = |
| SyntheticAttributeHashCalculator.compute( |
| rule, |
| /* serializedAttributes= */ ImmutableMap.of(), |
| /* extraDataForAttrHash= */ "", |
| DigestHashFunction.SHA256.getHashFunction(), |
| /* includeAttributeSourceAspects= */ false); |
| |
| ImmutableMap<Attribute, Build.Attribute> serializedAttributes = |
| ImmutableMap.of( |
| rule.getRuleClassObject().getAttributeByName("cmd"), |
| Build.Attribute.newBuilder() |
| .setName("dummy") |
| .setType(Discriminator.STRING) |
| .setStringValue("hi") |
| .build()); |
| |
| String hashAfter = |
| SyntheticAttributeHashCalculator.compute( |
| rule, |
| serializedAttributes, /*extraDataForAttrHash*/ |
| "", |
| DigestHashFunction.SHA256.getHashFunction(), |
| /* includeAttributeSourceAspects= */ false); |
| |
| assertThat(hashBefore).isNotEqualTo(hashAfter); |
| } |
| |
| @Test |
| public void testComputeExtraDataChangesHash() throws Exception { |
| scratch.file("pkg/BUILD", "genrule(name='x', cmd='touch $@', outs=['y'])"); |
| Rule rule = (Rule) getTarget("//pkg:x"); |
| |
| String hashBefore = |
| SyntheticAttributeHashCalculator.compute( |
| rule, |
| /* serializedAttributes= */ ImmutableMap.of(), |
| /* extraDataForAttrHash= */ "", |
| DigestHashFunction.SHA256.getHashFunction(), |
| /* includeAttributeSourceAspects= */ false); |
| |
| String hashAfter = |
| SyntheticAttributeHashCalculator.compute( |
| rule, |
| /* serializedAttributes= */ ImmutableMap.of(), /*extraDataForAttrHash*/ |
| "blahblaah", |
| DigestHashFunction.SHA256.getHashFunction(), |
| /* includeAttributeSourceAspects= */ false); |
| |
| assertThat(hashBefore).isNotEqualTo(hashAfter); |
| } |
| |
| @Test |
| public void testComputePackageErrorStatusChangesHash() throws Exception { |
| scratch.file("pkg/BUILD", "genrule(name='x', cmd='touch $@', outs=['y'])"); |
| Rule ruleBefore = (Rule) getTarget("//pkg:x"); |
| |
| // Remove fail-fast handler, we're intentionally creating a package with errors. |
| reporter.removeHandler(failFastHandler); |
| scratch.overwriteFile( |
| "pkg/BUILD", |
| """ |
| genrule( |
| name = "x", |
| outs = ["z"], |
| cmd = "touch $@", |
| ) |
| |
| genrule(name = "missing_attributes") |
| """); |
| invalidatePackages(); |
| Rule ruleAfter = (Rule) getTarget("//pkg:x"); |
| assertThat(ruleAfter.containsErrors()).isTrue(); |
| |
| String hashBefore = |
| SyntheticAttributeHashCalculator.compute( |
| ruleBefore, |
| /* serializedAttributes= */ ImmutableMap.of(), |
| /* extraDataForAttrHash= */ "", |
| DigestHashFunction.SHA256.getHashFunction(), |
| /* includeAttributeSourceAspects= */ false); |
| String hashAfter = |
| SyntheticAttributeHashCalculator.compute( |
| ruleAfter, |
| /* serializedAttributes= */ ImmutableMap.of(), |
| /* extraDataForAttrHash= */ "", |
| DigestHashFunction.SHA256.getHashFunction(), |
| /* includeAttributeSourceAspects= */ false); |
| |
| assertThat(hashBefore).isNotEqualTo(hashAfter); |
| } |
| |
| @Test |
| public void testComputeIncludeAttributeSourceAspectsChangesHash() throws Exception { |
| scratch.file( |
| "a/defs.bzl", |
| """ |
| def _test_aspect_impl(target, ctx): |
| return [] |
| |
| test_aspect = aspect( |
| implementation = _test_aspect_impl, |
| attr_aspects = ["deps"], |
| attrs = { |
| "_aspect_attr_1": attr.label(default = "//a:c"), |
| "_aspect_attr_2": attr.label(default = "//a:d"), |
| }, |
| ) |
| |
| def _lib_impl(ctx): |
| return |
| |
| test_lib = rule( |
| implementation = _lib_impl, |
| attrs = { |
| "deps": attr.label_list(aspects = [test_aspect]), |
| }, |
| ) |
| """); |
| scratch.file( |
| "a/BUILD", |
| """ |
| load("defs.bzl", "test_lib") |
| |
| test_lib( |
| name = "a", |
| deps = [":b"], |
| ) |
| |
| test_lib(name = "b") |
| """); |
| Rule rule = (Rule) getTarget("//a:a"); |
| |
| String hashWithAttributeAspects = |
| SyntheticAttributeHashCalculator.compute( |
| rule, |
| /* serializedAttributes= */ ImmutableMap.of(), |
| /* extraDataForAttrHash= */ "", |
| DigestHashFunction.SHA256.getHashFunction(), |
| /* includeAttributeSourceAspects= */ true); |
| |
| String hashWithoutAttributeAspects = |
| SyntheticAttributeHashCalculator.compute( |
| rule, |
| /* serializedAttributes= */ ImmutableMap.of(), |
| /* extraDataForAttrHash= */ "", |
| DigestHashFunction.SHA256.getHashFunction(), |
| /* includeAttributeSourceAspects= */ false); |
| assertThat(hashWithAttributeAspects).isNotEqualTo(hashWithoutAttributeAspects); |
| } |
| } |