github.com/abayer/test-infra@v0.0.5/prow/plugins/assign/assign_test.go (about) 1 /* 2 Copyright 2017 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 assign 18 19 import ( 20 "testing" 21 22 "github.com/sirupsen/logrus" 23 24 "k8s.io/test-infra/prow/github" 25 ) 26 27 type fakeClient struct { 28 assigned map[string]int 29 unassigned map[string]int 30 31 requested map[string]int 32 unrequested map[string]int 33 contributors map[string]bool 34 35 commented bool 36 } 37 38 func (c *fakeClient) UnassignIssue(owner, repo string, number int, assignees []string) error { 39 for _, who := range assignees { 40 c.unassigned[who]++ 41 } 42 43 return nil 44 } 45 46 func (c *fakeClient) AssignIssue(owner, repo string, number int, assignees []string) error { 47 var missing github.MissingUsers 48 for _, who := range assignees { 49 if who != "evil" { 50 c.assigned[who]++ 51 } else { 52 missing.Users = append(missing.Users, who) 53 } 54 } 55 56 if len(missing.Users) == 0 { 57 return nil 58 } 59 return missing 60 } 61 62 func (c *fakeClient) RequestReview(org, repo string, number int, logins []string) error { 63 var missing github.MissingUsers 64 for _, user := range logins { 65 if c.contributors[user] { 66 c.requested[user]++ 67 } else { 68 missing.Users = append(missing.Users, user) 69 } 70 } 71 if len(missing.Users) > 0 { 72 return missing 73 } 74 return nil 75 } 76 77 func (c *fakeClient) UnrequestReview(org, repo string, number int, logins []string) error { 78 for _, user := range logins { 79 c.unrequested[user]++ 80 } 81 return nil 82 } 83 84 func (c *fakeClient) CreateComment(owner, repo string, number int, comment string) error { 85 c.commented = comment != "" 86 return nil 87 } 88 89 func newFakeClient(contribs []string) *fakeClient { 90 c := &fakeClient{ 91 contributors: make(map[string]bool), 92 requested: make(map[string]int), 93 unrequested: make(map[string]int), 94 assigned: make(map[string]int), 95 unassigned: make(map[string]int), 96 } 97 for _, user := range contribs { 98 c.contributors[user] = true 99 } 100 return c 101 } 102 103 func TestParseLogins(t *testing.T) { 104 var testcases = []struct { 105 name string 106 text string 107 logins []string 108 }{ 109 { 110 name: "empty", 111 text: "", 112 }, 113 { 114 name: "one", 115 text: " @jungle", 116 logins: []string{"jungle"}, 117 }, 118 { 119 name: "two", 120 text: " @erick @fejta", 121 logins: []string{"erick", "fejta"}, 122 }, 123 { 124 name: "one team", 125 text: " @kubernetes/sig-testing-misc", 126 logins: []string{"kubernetes/sig-testing-misc"}, 127 }, 128 { 129 name: "two teams", 130 text: " @kubernetes/sig-testing-misc @kubernetes/sig-testing-bugs", 131 logins: []string{"kubernetes/sig-testing-misc", "kubernetes/sig-testing-bugs"}, 132 }, 133 } 134 for _, tc := range testcases { 135 l := parseLogins(tc.text) 136 if len(l) != len(tc.logins) { 137 t.Errorf("For case %s, expected %s and got %s", tc.name, tc.logins, l) 138 } 139 for n, who := range l { 140 if tc.logins[n] != who { 141 t.Errorf("For case %s, expected %s and got %s", tc.name, tc.logins, l) 142 } 143 } 144 } 145 } 146 147 // TestAssignAndReview tests that the handle function uses the github client 148 // to correctly create and/or delete assignments and PR review requests. 149 func TestAssignAndReview(t *testing.T) { 150 var testcases = []struct { 151 name string 152 body string 153 commenter string 154 assigned []string 155 unassigned []string 156 requested []string 157 unrequested []string 158 commented bool 159 }{ 160 { 161 name: "unrelated comment", 162 body: "uh oh", 163 commenter: "o", 164 }, 165 { 166 name: "assign on open", 167 body: "/assign", 168 commenter: "rando", 169 assigned: []string{"rando"}, 170 }, 171 { 172 name: "assign me", 173 body: "/assign", 174 commenter: "rando", 175 assigned: []string{"rando"}, 176 }, 177 { 178 name: "unassign myself", 179 body: "/unassign", 180 commenter: "rando", 181 unassigned: []string{"rando"}, 182 }, 183 { 184 name: "tab completion", 185 body: "/assign @fejta ", 186 commenter: "rando", 187 assigned: []string{"fejta"}, 188 }, 189 { 190 name: "no @ works too", 191 body: "/assign fejta", 192 commenter: "rando", 193 assigned: []string{"fejta"}, 194 }, 195 { 196 name: "multi commands", 197 body: "/assign @fejta\n/unassign @spxtr", 198 commenter: "rando", 199 assigned: []string{"fejta"}, 200 unassigned: []string{"spxtr"}, 201 }, 202 { 203 name: "interesting names", 204 body: "/assign @hello-world @allow_underscore", 205 commenter: "rando", 206 assigned: []string{"hello-world", "allow_underscore"}, 207 }, 208 { 209 name: "bad login", 210 commenter: "rando", 211 body: "/assign @Invalid$User", 212 }, 213 { 214 name: "bad login, no @", 215 commenter: "rando", 216 body: "/assign Invalid$User", 217 }, 218 { 219 name: "assign friends", 220 body: "/assign @bert @ernie", 221 commenter: "rando", 222 assigned: []string{"bert", "ernie"}, 223 }, 224 { 225 name: "unassign buddies", 226 body: "/unassign @ashitaka @eboshi", 227 commenter: "san", 228 unassigned: []string{"ashitaka", "eboshi"}, 229 }, 230 { 231 name: "unassign buddies, trailing space.", 232 body: "/unassign @ashitaka @eboshi \r", 233 commenter: "san", 234 unassigned: []string{"ashitaka", "eboshi"}, 235 }, 236 { 237 name: "evil commenter", 238 body: "/assign @merlin", 239 commenter: "evil", 240 assigned: []string{"merlin"}, 241 }, 242 { 243 name: "evil commenter self assign", 244 body: "/assign", 245 commenter: "evil", 246 commented: true, 247 }, 248 { 249 name: "evil assignee", 250 body: "/assign @evil @merlin", 251 commenter: "innocent", 252 assigned: []string{"merlin"}, 253 commented: true, 254 }, 255 { 256 name: "evil unassignee", 257 body: "/unassign @evil @merlin", 258 commenter: "innocent", 259 unassigned: []string{"evil", "merlin"}, 260 }, 261 { 262 name: "review on open", 263 body: "/cc @merlin", 264 commenter: "rando", 265 requested: []string{"merlin"}, 266 }, 267 { 268 name: "tab completion", 269 body: "/cc @cjwagner ", 270 commenter: "rando", 271 requested: []string{"cjwagner"}, 272 }, 273 { 274 name: "no @ works too", 275 body: "/cc cjwagner ", 276 commenter: "rando", 277 requested: []string{"cjwagner"}, 278 }, 279 { 280 name: "multi commands", 281 body: "/cc @cjwagner\n/uncc @spxtr", 282 commenter: "rando", 283 requested: []string{"cjwagner"}, 284 unrequested: []string{"spxtr"}, 285 }, 286 { 287 name: "interesting names", 288 body: "/cc @hello-world @allow_underscore", 289 commenter: "rando", 290 requested: []string{"hello-world", "allow_underscore"}, 291 }, 292 { 293 name: "bad login", 294 commenter: "rando", 295 body: "/cc @Invalid$User", 296 }, 297 { 298 name: "bad login", 299 commenter: "rando", 300 body: "/cc Invalid$User", 301 }, 302 { 303 name: "request multiple", 304 body: "/cc @cjwagner @merlin", 305 commenter: "rando", 306 requested: []string{"cjwagner", "merlin"}, 307 }, 308 { 309 name: "unrequest buddies", 310 body: "/uncc @ashitaka @eboshi", 311 commenter: "san", 312 unrequested: []string{"ashitaka", "eboshi"}, 313 }, 314 { 315 name: "evil commenter", 316 body: "/cc @merlin", 317 commenter: "evil", 318 requested: []string{"merlin"}, 319 }, 320 { 321 name: "evil reviewer requested", 322 body: "/cc @evil @merlin", 323 commenter: "innocent", 324 requested: []string{"merlin"}, 325 commented: true, 326 }, 327 { 328 name: "evil reviewer unrequested", 329 body: "/uncc @evil @merlin", 330 commenter: "innocent", 331 unrequested: []string{"evil", "merlin"}, 332 }, 333 { 334 name: "multi command types", 335 body: "/assign @fejta\n/unassign @spxtr @cjwagner\n/uncc @merlin \n/cc @cjwagner", 336 commenter: "rando", 337 assigned: []string{"fejta"}, 338 unassigned: []string{"spxtr", "cjwagner"}, 339 requested: []string{"cjwagner"}, 340 unrequested: []string{"merlin"}, 341 }, 342 { 343 name: "request review self", 344 body: "/cc", 345 commenter: "cjwagner", 346 requested: []string{"cjwagner"}, 347 }, 348 { 349 name: "unrequest review self", 350 body: "/uncc", 351 commenter: "cjwagner", 352 unrequested: []string{"cjwagner"}, 353 }, 354 { 355 name: "request review self, with unrequest friend, with trailing space.", 356 body: "/cc \n/uncc @spxtr ", 357 commenter: "cjwagner", 358 requested: []string{"cjwagner"}, 359 unrequested: []string{"spxtr"}, 360 }, 361 { 362 name: "request team review", 363 body: "/cc @kubernetes/sig-testing-misc", 364 commenter: "rando", 365 requested: []string{"kubernetes/sig-testing-misc"}, 366 }, 367 { 368 name: "unrequest team review", 369 body: "/uncc @kubernetes/sig-testing-misc", 370 commenter: "rando", 371 unrequested: []string{"kubernetes/sig-testing-misc"}, 372 }, 373 } 374 for _, tc := range testcases { 375 fc := newFakeClient([]string{"hello-world", "allow_underscore", "cjwagner", "merlin", "kubernetes/sig-testing-misc"}) 376 e := github.GenericCommentEvent{ 377 Body: tc.body, 378 User: github.User{Login: tc.commenter}, 379 Repo: github.Repo{Name: "repo", Owner: github.User{Login: "org"}}, 380 Number: 5, 381 } 382 if err := handle(newAssignHandler(e, fc, logrus.WithField("plugin", pluginName))); err != nil { 383 t.Errorf("For case %s, didn't expect error from handle: %v", tc.name, err) 384 continue 385 } 386 if err := handle(newReviewHandler(e, fc, logrus.WithField("plugin", pluginName))); err != nil { 387 t.Errorf("For case %s, didn't expect error from handle: %v", tc.name, err) 388 continue 389 } 390 391 if tc.commented != fc.commented { 392 t.Errorf("For case %s, expect commented: %v, got commented %v", tc.name, tc.commented, fc.commented) 393 } 394 395 if len(fc.assigned) != len(tc.assigned) { 396 t.Errorf("For case %s, assigned actual %v != expected %s", tc.name, fc.assigned, tc.assigned) 397 } else { 398 for _, who := range tc.assigned { 399 if n, ok := fc.assigned[who]; !ok || n < 1 { 400 t.Errorf("For case %s, assigned actual %v != expected %s", tc.name, fc.assigned, tc.assigned) 401 break 402 } 403 } 404 } 405 if len(fc.unassigned) != len(tc.unassigned) { 406 t.Errorf("For case %s, unassigned %v != %s", tc.name, fc.unassigned, tc.unassigned) 407 } else { 408 for _, who := range tc.unassigned { 409 if n, ok := fc.unassigned[who]; !ok || n < 1 { 410 t.Errorf("For case %s, unassigned %v != %s", tc.name, fc.unassigned, tc.unassigned) 411 break 412 } 413 } 414 } 415 416 if len(fc.requested) != len(tc.requested) { 417 t.Errorf("For case %s, requested actual %v != expected %s", tc.name, fc.requested, tc.requested) 418 } else { 419 for _, who := range tc.requested { 420 if n, ok := fc.requested[who]; !ok || n < 1 { 421 t.Errorf("For case %s, requested actual %v != expected %s", tc.name, fc.requested, tc.requested) 422 break 423 } 424 } 425 } 426 if len(fc.unrequested) != len(tc.unrequested) { 427 t.Errorf("For case %s, unrequested %v != %s", tc.name, fc.unrequested, tc.unrequested) 428 } else { 429 for _, who := range tc.unrequested { 430 if n, ok := fc.unrequested[who]; !ok || n < 1 { 431 t.Errorf("For case %s, unrequested %v != %s", tc.name, fc.unrequested, tc.unrequested) 432 break 433 } 434 } 435 } 436 } 437 }