Skip to content

Commit 8640bcd

Browse files
committed
fix: targets spuriously returned in cache case
Remove the "NewTarget" case, which can never be reached because: 1. beforeMetadata.TransitiveConfiguredTargets is a superset of beforeMetadata.MatchingTargets, and 2. at this point in the function, beforeMetadata.MatchingTargets is known to contain that same label and configuration. Doing this also addresses an issue where spurious targets were returned on a result cache hit: the codepath was looking for configured target structs, but when retrieving hashes from the cache, these are not populated in the first place, only the resulting hashes are.
1 parent 542c6d1 commit 8640bcd

3 files changed

Lines changed: 77 additions & 25 deletions

File tree

pkg/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ go_test(
3838
"hash_cache_test.go",
3939
"normalizer_test.go",
4040
"target_determinator_test.go",
41+
"walker_test.go",
4142
],
4243
data = ["//testdata/HelloWorld:all_srcs"],
4344
embed = [":pkg"],

pkg/walker.go

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -88,35 +88,29 @@ func DiffSingleLabel(beforeMetadata, afterMetadata *QueryResults, includeDiffere
8888
callback(label, differences, configuredTarget)
8989
return nil
9090
}
91-
_, ok := beforeMetadata.TransitiveConfiguredTargets[label][configuration]
92-
if !ok {
93-
collectDifference(Difference{Category: "NewTarget"})
94-
callback(label, differences, configuredTarget)
95-
return nil
96-
} else {
97-
labelAndConfiguration := LabelAndConfiguration{
98-
Label: label,
99-
Configuration: configuration,
100-
}
101-
hashBefore, err := beforeMetadata.TargetHashCache.Hash(labelAndConfiguration)
102-
if err != nil {
103-
return err
104-
}
105-
hashAfter, err := afterMetadata.TargetHashCache.Hash(labelAndConfiguration)
91+
labelAndConfiguration := LabelAndConfiguration{
92+
Label: label,
93+
Configuration: configuration,
94+
}
95+
96+
hashBefore, err := beforeMetadata.TargetHashCache.Hash(labelAndConfiguration)
97+
if err != nil {
98+
return err
99+
}
100+
hashAfter, err := afterMetadata.TargetHashCache.Hash(labelAndConfiguration)
101+
if err != nil {
102+
return err
103+
}
104+
if bytes.Equal(hashBefore, hashAfter) {
105+
continue
106+
}
107+
if includeDifferences {
108+
differences, err = WalkDiffs(beforeMetadata.TargetHashCache, afterMetadata.TargetHashCache, labelAndConfiguration)
106109
if err != nil {
107110
return err
108111
}
109-
if bytes.Equal(hashBefore, hashAfter) {
110-
continue
111-
}
112-
if includeDifferences {
113-
differences, err = WalkDiffs(beforeMetadata.TargetHashCache, afterMetadata.TargetHashCache, labelAndConfiguration)
114-
if err != nil {
115-
return err
116-
}
117-
}
118-
callback(label, differences, configuredTarget)
119112
}
113+
callback(label, differences, configuredTarget)
120114
}
121115
return nil
122116
}

pkg/walker_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package pkg
2+
3+
import (
4+
"testing"
5+
6+
ss "github.com/bazel-contrib/target-determinator/common/sorted_set"
7+
"github.com/bazel-contrib/target-determinator/third_party/protobuf/bazel/analysis"
8+
gazelle_label "github.com/bazelbuild/bazel-gazelle/label"
9+
)
10+
11+
func makeMatchingTargets(lbl gazelle_label.Label, config Configuration) *MatchingTargets {
12+
return &MatchingTargets{
13+
labels: ss.NewSortedSetFn([]gazelle_label.Label{lbl}, CompareLabels),
14+
labelsToConfigurations: map[gazelle_label.Label]*ss.SortedSet[Configuration]{
15+
lbl: ss.NewSortedSetFn([]Configuration{config}, ConfigurationLess),
16+
},
17+
}
18+
}
19+
20+
// TestDiffSingleLabel_NoDifferenceWhenBothFromCache verifies that when both before and after
21+
// metadata are loaded from cache (TransitiveConfiguredTargets == nil, pre-computed hashes
22+
// present), DiffSingleLabel does not report any differences for an unchanged target.
23+
func TestDiffSingleLabel_NoDifferenceWhenBothFromCache(t *testing.T) {
24+
const bazelRelease = "release 7.0.0"
25+
lbl := mustParseLabel("//foo:bar")
26+
config := NormalizeConfiguration("deadcafe")
27+
28+
mt := makeMatchingTargets(lbl, config)
29+
fakeHash := []byte{0xde, 0xad, 0xca, 0xfe}
30+
hashKey := lbl.String() + "\x00" + config.String()
31+
32+
makeFromCache := func() *QueryResults {
33+
thc := NewTargetHashCache(nil, &Normalizer{}, bazelRelease)
34+
if err := thc.RestoreHashes(map[string][]byte{hashKey: fakeHash}); err != nil {
35+
t.Fatalf("RestoreHashes: %v", err)
36+
}
37+
return &QueryResults{
38+
MatchingTargets: mt,
39+
TransitiveConfiguredTargets: nil, // as set by LoadFromCache
40+
TargetHashCache: thc,
41+
BazelRelease: bazelRelease,
42+
}
43+
}
44+
45+
beforeMetadata := makeFromCache()
46+
afterMetadata := makeFromCache()
47+
48+
err := DiffSingleLabel(
49+
beforeMetadata, afterMetadata, false, lbl,
50+
func(_ gazelle_label.Label, diffs []Difference, _ *analysis.ConfiguredTarget) {
51+
t.Errorf("callback called for unchanged target (diffs when includeDifferences=false are always nil: %v)", diffs)
52+
},
53+
)
54+
if err != nil {
55+
t.Fatalf("DiffSingleLabel returned unexpected error: %v", err)
56+
}
57+
}

0 commit comments

Comments
 (0)