go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/luci_notify/notify/commits_test.go (about) 1 // Copyright 2017 The LUCI Authors. 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 15 package notify 16 17 import ( 18 "context" 19 "testing" 20 21 buildbucketpb "go.chromium.org/luci/buildbucket/proto" 22 "go.chromium.org/luci/buildbucket/protoutil" 23 "go.chromium.org/luci/common/data/stringset" 24 gitpb "go.chromium.org/luci/common/proto/git" 25 26 notifypb "go.chromium.org/luci/luci_notify/api/config" 27 28 . "github.com/smartystreets/goconvey/convey" 29 . "go.chromium.org/luci/common/testing/assertions" 30 ) 31 32 var ( 33 // These defaults match up with the "basic" project config. 34 defaultGitilesHost = "chromium.googlesource.com" 35 defaultGitilesProject = "chromium/src" 36 37 // Test revisions. 38 rev1 = "deadbeef" 39 rev2 = "badcoffe" 40 41 // Test email addresses for commits. 42 commitEmail1 = "example1@google.com" 43 commitEmail2 = "example2@google.com" 44 45 // Test commits, ordered from new to old. 46 testCommits = []*gitpb.Commit{ 47 { 48 Author: &gitpb.Commit_User{ 49 Email: commitEmail2, 50 }, 51 Id: rev2, 52 }, 53 { 54 Author: &gitpb.Commit_User{ 55 Email: commitEmail1, 56 }, 57 Id: rev1, 58 }, 59 } 60 revTestCommits = []*gitpb.Commit{ 61 { 62 Author: &gitpb.Commit_User{ 63 Email: commitEmail1, 64 }, 65 Id: rev2, 66 }, 67 { 68 Author: &gitpb.Commit_User{ 69 Email: commitEmail2, 70 }, 71 Id: rev1, 72 }, 73 } 74 ) 75 76 func TestCheckout(t *testing.T) { 77 gitilesCheckout := ¬ifypb.GitilesCommits{ 78 Commits: []*buildbucketpb.GitilesCommit{ 79 { 80 Host: defaultGitilesHost, 81 Project: defaultGitilesProject, 82 Id: rev1, 83 }, 84 { 85 Host: defaultGitilesHost, 86 Project: "third_party/hello", 87 Id: rev2, 88 }, 89 }, 90 } 91 Convey(`Conversion with GitilesCommits Empty`, t, func() { 92 checkout := NewCheckout(¬ifypb.GitilesCommits{}) 93 So(checkout, ShouldHaveLength, 0) 94 result := checkout.ToGitilesCommits() 95 So(result, ShouldBeNil) 96 }) 97 98 Convey(`Conversion with GitilesCommits Non-Empty`, t, func() { 99 checkout := NewCheckout(gitilesCheckout) 100 So(checkout, ShouldResemble, Checkout{ 101 protoutil.GitilesRepoURL(gitilesCheckout.Commits[0]): rev1, 102 protoutil.GitilesRepoURL(gitilesCheckout.Commits[1]): rev2, 103 }) 104 result := checkout.ToGitilesCommits() 105 So(result, ShouldResembleProto, gitilesCheckout) 106 }) 107 108 Convey(`Filter repositories from allowlist`, t, func() { 109 checkout := NewCheckout(gitilesCheckout) 110 repoURL := protoutil.GitilesRepoURL(gitilesCheckout.Commits[0]) 111 filteredCheckout := checkout.Filter(stringset.NewFromSlice([]string{repoURL}...)) 112 So(filteredCheckout, ShouldResemble, Checkout{repoURL: rev1}) 113 }) 114 } 115 116 func TestLogs(t *testing.T) { 117 Convey(`ComputeLogs`, t, func() { 118 ctx := context.Background() 119 history := mockHistoryFunc(map[string][]*gitpb.Commit{ 120 "chromium/src": testCommits, 121 "third_party/hello": testCommits, 122 "third_party/what": testCommits, 123 }) 124 checkout1Old := Checkout{ 125 "https://chromium.googlesource.com/chromium/src": rev1, 126 "https://chromium.googlesource.com/third_party/hello": rev1, 127 } 128 checkout1New := Checkout{ 129 "https://chromium.googlesource.com/chromium/src": rev2, 130 "https://chromium.googlesource.com/third_party/hello": rev2, 131 } 132 checkout2 := Checkout{ 133 "https://chromium.googlesource.com/chromium/src": rev2, 134 "https://chromium.googlesource.com/third_party/what": rev2, 135 } 136 checkout3 := Checkout{ 137 "https://chromium.googlesource.com/third_party/what": rev2, 138 } 139 Convey(`Both empty`, func() { 140 logs, err := ComputeLogs(ctx, "luci-proj", nil, nil, history) 141 So(err, ShouldBeNil) 142 So(logs, ShouldHaveLength, 0) 143 }) 144 Convey(`One empty`, func() { 145 logs1, err := ComputeLogs(ctx, "luci-proj", checkout1Old, nil, history) 146 So(err, ShouldBeNil) 147 So(logs1, ShouldHaveLength, 0) 148 149 logs2, err := ComputeLogs(ctx, "luci-proj", nil, checkout1Old, history) 150 So(err, ShouldBeNil) 151 So(logs2, ShouldHaveLength, 0) 152 }) 153 Convey(`Both valid, full overlap`, func() { 154 logs, err := ComputeLogs(ctx, "luci-proj", checkout1Old, checkout1New, history) 155 So(err, ShouldBeNil) 156 So(logs["https://chromium.googlesource.com/chromium/src"], ShouldResembleProto, testCommits[:1]) 157 So(logs["https://chromium.googlesource.com/third_party/hello"], ShouldResembleProto, testCommits[:1]) 158 }) 159 Convey(`Both valid, partial overlap`, func() { 160 logs, err := ComputeLogs(ctx, "luci-proj", checkout1Old, checkout2, history) 161 So(err, ShouldBeNil) 162 So(logs["https://chromium.googlesource.com/chromium/src"], ShouldResembleProto, testCommits[:1]) 163 }) 164 Convey(`Both valid, no overlap`, func() { 165 logs, err := ComputeLogs(ctx, "luci-proj", checkout1Old, checkout3, history) 166 So(err, ShouldBeNil) 167 So(logs, ShouldHaveLength, 0) 168 }) 169 }) 170 171 testLogs := Logs{ 172 "https://chromium.googlesource.com/chromium/src": testCommits, 173 "https://chromium.googlesource.com/third_party/hello": testCommits, 174 } 175 176 Convey(`Filter repositories from allowlist`, t, func() { 177 filteredLogs := testLogs.Filter(stringset.NewFromSlice([]string{ 178 "https://chromium.googlesource.com/chromium/src", 179 }...)) 180 So(filteredLogs["https://chromium.googlesource.com/chromium/src"], ShouldResembleProto, testCommits) 181 }) 182 183 Convey(`Blamelist`, t, func() { 184 blamelist := testLogs.Blamelist("default") 185 So(blamelist, ShouldResemble, []EmailNotify{ 186 { 187 Email: "example1@google.com", 188 Template: "default", 189 }, 190 { 191 Email: "example2@google.com", 192 Template: "default", 193 }, 194 }) 195 }) 196 } 197 198 // mockHistoryFunc returns a mock HistoryFunc that gets its history from 199 // a given list of gitpb.Commit. 200 // 201 // mockCommits should be ordered from newest to oldest, to mimic the ordering 202 // returned by Gitiles. 203 func mockHistoryFunc(projectCommits map[string][]*gitpb.Commit) HistoryFunc { 204 return func(_ context.Context, _, _, project, oldRevision, newRevision string) ([]*gitpb.Commit, error) { 205 mockCommits := projectCommits[project] 206 oldCommit := -1 207 newCommit := -1 208 for i, c := range mockCommits { 209 if c.Id == oldRevision { 210 oldCommit = i 211 } 212 if c.Id == newRevision { 213 newCommit = i 214 } 215 } 216 if oldCommit == -1 || newCommit == -1 || newCommit > oldCommit { 217 return nil, nil 218 } 219 commits := make([]*gitpb.Commit, oldCommit-newCommit+1) 220 copy(commits, mockCommits[newCommit:oldCommit+1]) 221 return commits, nil 222 } 223 }