github.com/zppinho/prow@v0.0.0-20240510014325-1738badeb017/pkg/gerrit/adapter/trigger_test.go (about) 1 /* 2 Copyright 2020 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package adapter 18 19 import ( 20 "reflect" 21 "testing" 22 "time" 23 24 "github.com/andygrunwald/go-gerrit" 25 "github.com/sirupsen/logrus" 26 "k8s.io/apimachinery/pkg/api/equality" 27 "k8s.io/apimachinery/pkg/util/diff" 28 "k8s.io/apimachinery/pkg/util/sets" 29 30 "sigs.k8s.io/prow/pkg/config" 31 "sigs.k8s.io/prow/pkg/gerrit/client" 32 ) 33 34 func TestPresubmitContexts(t *testing.T) { 35 jobs := func(names ...string) []config.Presubmit { 36 var presubmits []config.Presubmit 37 for _, n := range names { 38 var p config.Presubmit 39 p.Name = n 40 presubmits = append(presubmits, p) 41 } 42 return presubmits 43 } 44 cases := []struct { 45 name string 46 presubmits []config.Presubmit 47 failing sets.Set[string] 48 failed sets.Set[string] 49 all sets.Set[string] 50 }{ 51 { 52 name: "basically works", 53 }, 54 { 55 name: "simple case works", 56 presubmits: jobs("hello-fail", "world"), 57 failing: sets.New[string]("world"), 58 failed: sets.New[string]("world"), 59 all: sets.New[string]("hello-fail", "world"), 60 }, 61 { 62 name: "ignore failures from deleted jobs", 63 presubmits: jobs("failing", "passing"), 64 failing: sets.New[string]("failing", "deleted"), 65 failed: sets.New[string]("failing"), 66 all: sets.New[string]("failing", "passing"), 67 }, 68 } 69 70 for _, tc := range cases { 71 t.Run(tc.name, func(t *testing.T) { 72 gotFailed, gotAll := presubmitContexts(tc.failing, tc.presubmits, logrus.WithField("case", tc.name)) 73 if !equality.Semantic.DeepEqual(tc.failed, gotFailed) { 74 t.Errorf("wrong failures:%s", diff.ObjectReflectDiff(tc.failed, gotFailed)) 75 } 76 if !equality.Semantic.DeepEqual(tc.all, gotAll) { 77 t.Errorf("wrong all contexts:%s", diff.ObjectReflectDiff(tc.all, gotAll)) 78 } 79 }) 80 } 81 } 82 83 func stamp(t time.Time) gerrit.Timestamp { 84 return gerrit.Timestamp{Time: t} 85 } 86 87 func TestCurrentMessages(t *testing.T) { 88 now := time.Now() 89 before := now.Add(-time.Minute) 90 after := now.Add(time.Hour) 91 later := after.Add(time.Hour) 92 93 now3 := gerrit.ChangeMessageInfo{ 94 RevisionNumber: 3, 95 Date: stamp(now), 96 Message: "now", 97 } 98 after3 := gerrit.ChangeMessageInfo{ 99 RevisionNumber: 3, 100 Date: stamp(after), 101 Message: "after", 102 } 103 later3 := gerrit.ChangeMessageInfo{ 104 RevisionNumber: 3, 105 Date: stamp(later), 106 Message: "later", 107 } 108 after4 := gerrit.ChangeMessageInfo{ 109 RevisionNumber: 4, 110 Date: stamp(after), 111 Message: "4-after", 112 } 113 114 cases := []struct { 115 name string 116 change gerrit.ChangeInfo 117 since time.Time 118 want []gerrit.ChangeMessageInfo 119 }{ 120 { 121 name: "basically works", 122 }, 123 { 124 name: "simple case", 125 since: before, 126 change: gerrit.ChangeInfo{ 127 Revisions: map[string]gerrit.RevisionInfo{ 128 "3": { 129 Number: 3, 130 }, 131 }, 132 CurrentRevision: "3", 133 Messages: []gerrit.ChangeMessageInfo{now3, after3, later3}, 134 }, 135 want: []gerrit.ChangeMessageInfo{now3, after3, later3}, 136 }, 137 { 138 name: "reject old messages", 139 since: now, 140 change: gerrit.ChangeInfo{ 141 Revisions: map[string]gerrit.RevisionInfo{ 142 "3": { 143 Number: 3, 144 }, 145 }, 146 CurrentRevision: "3", 147 Messages: []gerrit.ChangeMessageInfo{now3, after3, later3}, 148 }, 149 want: []gerrit.ChangeMessageInfo{after3, later3}, 150 }, 151 { 152 name: "reject message from other revisions", 153 since: before, 154 change: gerrit.ChangeInfo{ 155 Revisions: map[string]gerrit.RevisionInfo{ 156 "3": { 157 Number: 3, 158 }, 159 }, 160 CurrentRevision: "3", 161 Messages: []gerrit.ChangeMessageInfo{now3, after4, later3}, 162 }, 163 want: []gerrit.ChangeMessageInfo{now3, later3}, 164 }, 165 } 166 167 for _, tc := range cases { 168 t.Run(tc.name, func(t *testing.T) { 169 got := currentMessages(tc.change, tc.since) 170 if !reflect.DeepEqual(got, tc.want) { 171 t.Errorf("wrong messages:%s", diff.ObjectReflectDiff(got, tc.want)) 172 } 173 }) 174 } 175 } 176 177 func TestMessageFilter(t *testing.T) { 178 old := time.Now().Add(-1 * time.Hour) 179 older := old.Add(-1 * time.Hour) 180 job := func(name string, patch func(j *config.Presubmit)) config.Presubmit { 181 var presubmit config.Presubmit 182 presubmit.Name = name 183 presubmit.Context = name 184 presubmit.Trigger = config.DefaultTriggerFor(name) 185 presubmit.RerunCommand = config.DefaultRerunCommandFor(name) 186 presubmit.AlwaysRun = true 187 if patch != nil { 188 patch(&presubmit) 189 } 190 return presubmit 191 } 192 msg := func(content string, t time.Time) gerrit.ChangeMessageInfo { 193 return gerrit.ChangeMessageInfo{Message: content, Date: gerrit.Timestamp{Time: t}} 194 } 195 type check struct { 196 job config.Presubmit 197 shouldRun bool 198 forcedToRun bool 199 defaultBehavior bool 200 triggered time.Time 201 } 202 cases := []struct { 203 name string 204 messages []gerrit.ChangeMessageInfo 205 failed sets.Set[string] 206 all sets.Set[string] 207 checks []check 208 }{ 209 { 210 name: "basically works", 211 }, 212 { 213 name: "/test foo works", 214 messages: []gerrit.ChangeMessageInfo{msg("/test foo", older), msg("/test bar", old)}, 215 all: sets.New[string]("foo", "bar", "ignored"), 216 checks: []check{ 217 { 218 job: job("foo", nil), 219 shouldRun: true, 220 forcedToRun: true, 221 defaultBehavior: true, 222 triggered: older, 223 }, 224 { 225 job: job("bar", nil), 226 shouldRun: true, 227 forcedToRun: true, 228 defaultBehavior: true, 229 triggered: old, 230 }, 231 { 232 job: job("ignored", nil), 233 shouldRun: false, 234 forcedToRun: false, 235 defaultBehavior: false, 236 }, 237 }, 238 }, 239 { 240 name: "/test all triggers multiple", 241 messages: []gerrit.ChangeMessageInfo{msg("/test all", old)}, 242 all: sets.New[string]("foo", "bar"), 243 checks: []check{ 244 { 245 job: job("foo", nil), 246 shouldRun: true, 247 forcedToRun: false, 248 defaultBehavior: false, 249 triggered: old, 250 }, 251 { 252 job: job("bar", nil), 253 shouldRun: true, 254 forcedToRun: false, 255 defaultBehavior: false, 256 triggered: old, 257 }, 258 }, 259 }, 260 { 261 name: "/retest triggers failures", 262 messages: []gerrit.ChangeMessageInfo{msg("/retest", old)}, 263 failed: sets.New[string]("failed"), 264 all: sets.New[string]("foo", "bar", "failed"), 265 checks: []check{ 266 { 267 job: job("foo", nil), 268 shouldRun: false, 269 forcedToRun: false, 270 defaultBehavior: false, 271 }, 272 { 273 job: job("failed", nil), 274 shouldRun: true, 275 forcedToRun: false, 276 defaultBehavior: true, 277 triggered: old, 278 }, 279 { 280 job: job("bar", nil), 281 shouldRun: false, 282 forcedToRun: false, 283 defaultBehavior: false, 284 }, 285 }, 286 }, 287 { 288 name: "draft->active by clicking `MARK AS ACTIVE` triggers multiple", 289 messages: []gerrit.ChangeMessageInfo{msg(client.ReadyForReviewMessageFixed, old)}, 290 all: sets.New[string]("foo", "bar"), 291 checks: []check{ 292 { 293 job: job("foo", nil), 294 shouldRun: true, 295 forcedToRun: false, 296 defaultBehavior: false, 297 triggered: old, 298 }, 299 { 300 job: job("bar", nil), 301 shouldRun: true, 302 forcedToRun: false, 303 defaultBehavior: false, 304 triggered: old, 305 }, 306 }, 307 }, 308 { 309 name: "draft->active by clicking `SEND AND START REVIEW` triggers multiple", 310 messages: []gerrit.ChangeMessageInfo{msg(`Patch Set 1: 311 312 (1 comment) 313 314 `+client.ReadyForReviewMessageCustomizable, old)}, 315 all: sets.New[string]("foo", "bar"), 316 checks: []check{ 317 { 318 job: job("foo", nil), 319 shouldRun: true, 320 forcedToRun: false, 321 defaultBehavior: false, 322 triggered: old, 323 }, 324 { 325 job: job("bar", nil), 326 shouldRun: true, 327 forcedToRun: false, 328 defaultBehavior: false, 329 triggered: old, 330 }, 331 }, 332 }, 333 } 334 335 for _, tc := range cases { 336 t.Run(tc.name, func(t *testing.T) { 337 logger := logrus.WithField("case", tc.name) 338 triggerTimes := map[string]time.Time{} 339 filt := messageFilter(tc.messages, tc.failed, tc.all, triggerTimes, logger) 340 for _, check := range tc.checks { 341 t.Run(check.job.Name, func(t *testing.T) { 342 fixed := []config.Presubmit{check.job} 343 config.SetPresubmitRegexes(fixed) 344 check.job = fixed[0] 345 shouldRun, forcedToRun, defaultBehavior := filt.ShouldRun(check.job) 346 if got, want := shouldRun, check.shouldRun; got != want { 347 t.Errorf("shouldRun: got %t, want %t", got, want) 348 } 349 if got, want := forcedToRun, check.forcedToRun; got != want { 350 t.Errorf("forcedToRun: got %t, want %t", got, want) 351 } 352 if got, want := defaultBehavior, check.defaultBehavior; got != want { 353 t.Errorf("defaultBehavior: got %t, want %t", got, want) 354 } 355 }) 356 } 357 // Validate that triggerTimes was populated correctly after ShouldRun is called on every job. 358 for _, check := range tc.checks { 359 if !triggerTimes[check.job.Name].Equal(check.triggered) { 360 t.Errorf("expected job %q to have trigger time %v, but got %v", check.job.Name, check.triggered, triggerTimes[check.job.Name]) 361 } 362 } 363 }) 364 } 365 }