github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/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 for _, tc := range testcases { 125 l := parseLogins(tc.text) 126 if len(l) != len(tc.logins) { 127 t.Errorf("For case %s, expected %s and got %s", tc.name, tc.logins, l) 128 } 129 for n, who := range l { 130 if tc.logins[n] != who { 131 t.Errorf("For case %s, expected %s and got %s", tc.name, tc.logins, l) 132 } 133 } 134 } 135 } 136 137 // TestAssignAndReview tests that the handle function uses the github client 138 // to correctly create and/or delete assignments and PR review requests. 139 func TestAssignAndReview(t *testing.T) { 140 var testcases = []struct { 141 name string 142 body string 143 commenter string 144 assigned []string 145 unassigned []string 146 requested []string 147 unrequested []string 148 commented bool 149 }{ 150 { 151 name: "unrelated comment", 152 body: "uh oh", 153 commenter: "o", 154 }, 155 { 156 name: "assign on open", 157 body: "/assign", 158 commenter: "rando", 159 assigned: []string{"rando"}, 160 }, 161 { 162 name: "assign me", 163 body: "/assign", 164 commenter: "rando", 165 assigned: []string{"rando"}, 166 }, 167 { 168 name: "unassign myself", 169 body: "/unassign", 170 commenter: "rando", 171 unassigned: []string{"rando"}, 172 }, 173 { 174 name: "tab completion", 175 body: "/assign @fejta ", 176 commenter: "rando", 177 assigned: []string{"fejta"}, 178 }, 179 { 180 name: "no @ works too", 181 body: "/assign fejta", 182 commenter: "rando", 183 assigned: []string{"fejta"}, 184 }, 185 { 186 name: "multi commands", 187 body: "/assign @fejta\n/unassign @spxtr", 188 commenter: "rando", 189 assigned: []string{"fejta"}, 190 unassigned: []string{"spxtr"}, 191 }, 192 { 193 name: "interesting names", 194 body: "/assign @hello-world @allow_underscore", 195 commenter: "rando", 196 assigned: []string{"hello-world", "allow_underscore"}, 197 }, 198 { 199 name: "bad login", 200 commenter: "rando", 201 body: "/assign @Invalid$User", 202 }, 203 { 204 name: "bad login, no @", 205 commenter: "rando", 206 body: "/assign Invalid$User", 207 }, 208 { 209 name: "assign friends", 210 body: "/assign @bert @ernie", 211 commenter: "rando", 212 assigned: []string{"bert", "ernie"}, 213 }, 214 { 215 name: "unassign buddies", 216 body: "/unassign @ashitaka @eboshi", 217 commenter: "san", 218 unassigned: []string{"ashitaka", "eboshi"}, 219 }, 220 { 221 name: "unassign buddies, trailing space.", 222 body: "/unassign @ashitaka @eboshi \r", 223 commenter: "san", 224 unassigned: []string{"ashitaka", "eboshi"}, 225 }, 226 { 227 name: "evil commenter", 228 body: "/assign @merlin", 229 commenter: "evil", 230 assigned: []string{"merlin"}, 231 }, 232 { 233 name: "evil commenter self assign", 234 body: "/assign", 235 commenter: "evil", 236 commented: true, 237 }, 238 { 239 name: "evil assignee", 240 body: "/assign @evil @merlin", 241 commenter: "innocent", 242 assigned: []string{"merlin"}, 243 commented: true, 244 }, 245 { 246 name: "evil unassignee", 247 body: "/unassign @evil @merlin", 248 commenter: "innocent", 249 unassigned: []string{"evil", "merlin"}, 250 }, 251 { 252 name: "review on open", 253 body: "/cc @merlin", 254 commenter: "rando", 255 requested: []string{"merlin"}, 256 }, 257 { 258 name: "tab completion", 259 body: "/cc @cjwagner ", 260 commenter: "rando", 261 requested: []string{"cjwagner"}, 262 }, 263 { 264 name: "no @ works too", 265 body: "/cc cjwagner ", 266 commenter: "rando", 267 requested: []string{"cjwagner"}, 268 }, 269 { 270 name: "multi commands", 271 body: "/cc @cjwagner\n/uncc @spxtr", 272 commenter: "rando", 273 requested: []string{"cjwagner"}, 274 unrequested: []string{"spxtr"}, 275 }, 276 { 277 name: "interesting names", 278 body: "/cc @hello-world @allow_underscore", 279 commenter: "rando", 280 requested: []string{"hello-world", "allow_underscore"}, 281 }, 282 { 283 name: "bad login", 284 commenter: "rando", 285 body: "/cc @Invalid$User", 286 }, 287 { 288 name: "bad login", 289 commenter: "rando", 290 body: "/cc Invalid$User", 291 }, 292 { 293 name: "request multiple", 294 body: "/cc @cjwagner @merlin", 295 commenter: "rando", 296 requested: []string{"cjwagner", "merlin"}, 297 }, 298 { 299 name: "unrequest buddies", 300 body: "/uncc @ashitaka @eboshi", 301 commenter: "san", 302 unrequested: []string{"ashitaka", "eboshi"}, 303 }, 304 { 305 name: "evil commenter", 306 body: "/cc @merlin", 307 commenter: "evil", 308 requested: []string{"merlin"}, 309 }, 310 { 311 name: "evil reviewer requested", 312 body: "/cc @evil @merlin", 313 commenter: "innocent", 314 requested: []string{"merlin"}, 315 commented: true, 316 }, 317 { 318 name: "evil reviewer unrequested", 319 body: "/uncc @evil @merlin", 320 commenter: "innocent", 321 unrequested: []string{"evil", "merlin"}, 322 }, 323 { 324 name: "multi command types", 325 body: "/assign @fejta\n/unassign @spxtr @cjwagner\n/uncc @merlin \n/cc @cjwagner", 326 commenter: "rando", 327 assigned: []string{"fejta"}, 328 unassigned: []string{"spxtr", "cjwagner"}, 329 requested: []string{"cjwagner"}, 330 unrequested: []string{"merlin"}, 331 }, 332 { 333 name: "request review self", 334 body: "/cc", 335 commenter: "cjwagner", 336 requested: []string{"cjwagner"}, 337 }, 338 { 339 name: "unrequest review self", 340 body: "/uncc", 341 commenter: "cjwagner", 342 unrequested: []string{"cjwagner"}, 343 }, 344 { 345 name: "request review self, with unrequest friend, with trailing space.", 346 body: "/cc \n/uncc @spxtr ", 347 commenter: "cjwagner", 348 requested: []string{"cjwagner"}, 349 unrequested: []string{"spxtr"}, 350 }, 351 } 352 for _, tc := range testcases { 353 fc := newFakeClient([]string{"hello-world", "allow_underscore", "cjwagner", "merlin"}) 354 e := github.GenericCommentEvent{ 355 Body: tc.body, 356 User: github.User{Login: tc.commenter}, 357 Repo: github.Repo{Name: "repo", Owner: github.User{Login: "org"}}, 358 Number: 5, 359 } 360 if err := handle(newAssignHandler(e, fc, logrus.WithField("plugin", pluginName))); err != nil { 361 t.Errorf("For case %s, didn't expect error from handle: %v", tc.name, err) 362 continue 363 } 364 if err := handle(newReviewHandler(e, fc, logrus.WithField("plugin", pluginName))); err != nil { 365 t.Errorf("For case %s, didn't expect error from handle: %v", tc.name, err) 366 continue 367 } 368 369 if tc.commented != fc.commented { 370 t.Errorf("For case %s, expect commented: %v, got commented %v", tc.name, tc.commented, fc.commented) 371 } 372 373 if len(fc.assigned) != len(tc.assigned) { 374 t.Errorf("For case %s, assigned actual %v != expected %s", tc.name, fc.assigned, tc.assigned) 375 } else { 376 for _, who := range tc.assigned { 377 if n, ok := fc.assigned[who]; !ok || n < 1 { 378 t.Errorf("For case %s, assigned actual %v != expected %s", tc.name, fc.assigned, tc.assigned) 379 break 380 } 381 } 382 } 383 if len(fc.unassigned) != len(tc.unassigned) { 384 t.Errorf("For case %s, unassigned %v != %s", tc.name, fc.unassigned, tc.unassigned) 385 } else { 386 for _, who := range tc.unassigned { 387 if n, ok := fc.unassigned[who]; !ok || n < 1 { 388 t.Errorf("For case %s, unassigned %v != %s", tc.name, fc.unassigned, tc.unassigned) 389 break 390 } 391 } 392 } 393 394 if len(fc.requested) != len(tc.requested) { 395 t.Errorf("For case %s, requested actual %v != expected %s", tc.name, fc.requested, tc.requested) 396 } else { 397 for _, who := range tc.requested { 398 if n, ok := fc.requested[who]; !ok || n < 1 { 399 t.Errorf("For case %s, requested actual %v != expected %s", tc.name, fc.requested, tc.requested) 400 break 401 } 402 } 403 } 404 if len(fc.unrequested) != len(tc.unrequested) { 405 t.Errorf("For case %s, unrequested %v != %s", tc.name, fc.unrequested, tc.unrequested) 406 } else { 407 for _, who := range tc.unrequested { 408 if n, ok := fc.unrequested[who]; !ok || n < 1 { 409 t.Errorf("For case %s, unrequested %v != %s", tc.name, fc.unrequested, tc.unrequested) 410 break 411 } 412 } 413 } 414 } 415 }