github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/prow/external-plugins/cherrypicker/server_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 main 18 19 import ( 20 "fmt" 21 "sync" 22 "testing" 23 24 "github.com/sirupsen/logrus" 25 26 "k8s.io/test-infra/prow/git/localgit" 27 "k8s.io/test-infra/prow/github" 28 ) 29 30 type fghc struct { 31 sync.Mutex 32 pr *github.PullRequest 33 isMember bool 34 35 patch []byte 36 comments []string 37 prs []string 38 prComments []github.IssueComment 39 createdNum int 40 orgMembers []github.TeamMember 41 } 42 43 func (f *fghc) AssignIssue(org, repo string, number int, logins []string) error { 44 f.Lock() 45 defer f.Unlock() 46 return nil 47 } 48 49 func (f *fghc) GetPullRequest(org, repo string, number int) (*github.PullRequest, error) { 50 f.Lock() 51 defer f.Unlock() 52 return f.pr, nil 53 } 54 55 func (f *fghc) GetPullRequestPatch(org, repo string, number int) ([]byte, error) { 56 f.Lock() 57 defer f.Unlock() 58 return f.patch, nil 59 } 60 61 func (f *fghc) CreateComment(org, repo string, number int, comment string) error { 62 f.Lock() 63 defer f.Unlock() 64 f.comments = append(f.comments, fmt.Sprintf("%s/%s#%d %s", org, repo, number, comment)) 65 return nil 66 } 67 68 func (f *fghc) IsMember(org, user string) (bool, error) { 69 f.Lock() 70 defer f.Unlock() 71 return f.isMember, nil 72 } 73 74 func (f *fghc) GetRepo(owner, name string) (github.Repo, error) { 75 f.Lock() 76 defer f.Unlock() 77 return github.Repo{}, nil 78 } 79 80 var expectedFmt = `repo=%s title=%q body=%q head=%s base=%s maintainer_can_modify=%t` 81 82 func (f *fghc) CreatePullRequest(org, repo, title, body, head, base string, canModify bool) (int, error) { 83 f.Lock() 84 defer f.Unlock() 85 f.prs = append(f.prs, fmt.Sprintf(expectedFmt, org+"/"+repo, title, body, head, base, canModify)) 86 return f.createdNum, nil 87 } 88 89 func (f *fghc) ListIssueComments(org, repo string, number int) ([]github.IssueComment, error) { 90 f.Lock() 91 defer f.Unlock() 92 return f.prComments, nil 93 } 94 95 func (f *fghc) ListOrgMembers(org, role string) ([]github.TeamMember, error) { 96 f.Lock() 97 defer f.Unlock() 98 if role != "all" { 99 return nil, fmt.Errorf("all is only supported role, not: %s", role) 100 } 101 return f.orgMembers, nil 102 } 103 104 func (f *fghc) CreateFork(org, repo string) error { 105 return nil 106 } 107 108 var initialFiles = map[string][]byte{ 109 "bar.go": []byte(`// Package bar does an interesting thing. 110 package bar 111 112 // Foo does a thing. 113 func Foo(wow int) int { 114 return 42 + wow 115 } 116 `), 117 } 118 119 var patch = []byte(`From af468c9e69dfdf39db591f1e3e8de5b64b0e62a2 Mon Sep 17 00:00:00 2001 120 From: Wise Guy <wise@guy.com> 121 Date: Thu, 19 Oct 2017 15:14:36 +0200 122 Subject: [PATCH] Update magic number 123 124 --- 125 bar.go | 3 ++- 126 1 file changed, 2 insertions(+), 1 deletion(-) 127 128 diff --git a/bar.go b/bar.go 129 index 1ea52dc..5bd70a9 100644 130 --- a/bar.go 131 +++ b/bar.go 132 @@ -3,5 +3,6 @@ package bar 133 134 // Foo does a thing. 135 func Foo(wow int) int { 136 - return 42 + wow 137 + // Needs to be 49 because of a reason. 138 + return 49 + wow 139 } 140 `) 141 142 var body = "This PR updates the magic number.\n\n```release-note\nUpdate the magic number from 42 to 49\n```" 143 144 func TestCherryPickIC(t *testing.T) { 145 lg, c, err := localgit.New() 146 if err != nil { 147 t.Fatalf("Making localgit: %v", err) 148 } 149 defer func() { 150 if err := lg.Clean(); err != nil { 151 t.Errorf("Cleaning up localgit: %v", err) 152 } 153 if err := c.Clean(); err != nil { 154 t.Errorf("Cleaning up client: %v", err) 155 } 156 }() 157 if err := lg.MakeFakeRepo("foo", "bar"); err != nil { 158 t.Fatalf("Making fake repo: %v", err) 159 } 160 if err := lg.AddCommit("foo", "bar", initialFiles); err != nil { 161 t.Fatalf("Adding initial commit: %v", err) 162 } 163 if err := lg.CheckoutNewBranch("foo", "bar", "stage"); err != nil { 164 t.Fatalf("Checking out pull branch: %v", err) 165 } 166 167 ghc := &fghc{ 168 pr: &github.PullRequest{ 169 Base: github.PullRequestBranch{ 170 Ref: "master", 171 }, 172 Merged: true, 173 Title: "This is a fix for X", 174 Body: body, 175 }, 176 isMember: true, 177 createdNum: 3, 178 patch: patch, 179 } 180 ic := github.IssueCommentEvent{ 181 Action: github.IssueCommentActionCreated, 182 Repo: github.Repo{ 183 Owner: github.User{ 184 Login: "foo", 185 }, 186 Name: "bar", 187 FullName: "foo/bar", 188 }, 189 Issue: github.Issue{ 190 Number: 2, 191 State: "closed", 192 PullRequest: &struct{}{}, 193 }, 194 Comment: github.IssueComment{ 195 User: github.User{ 196 Login: "wiseguy", 197 }, 198 Body: "/cherrypick stage", 199 }, 200 } 201 202 botName := "ci-robot" 203 expectedRepo := "foo/bar" 204 expectedTitle := "[stage] This is a fix for X" 205 expectedBody := "This is an automated cherry-pick of #2\n\n/assign wiseguy\n\n```release-note\nUpdate the magic number from 42 to 49\n```" 206 expectedBase := "stage" 207 expectedHead := fmt.Sprintf(botName+":"+cherryPickBranchFmt, 2, expectedBase) 208 expected := fmt.Sprintf(expectedFmt, expectedRepo, expectedTitle, expectedBody, expectedHead, expectedBase, true) 209 210 getSecret := func() []byte { 211 return []byte("sha=abcdefg") 212 } 213 214 s := &Server{ 215 botName: botName, 216 gc: c, 217 push: func(repo, newBranch string) error { return nil }, 218 ghc: ghc, 219 tokenGenerator: getSecret, 220 log: logrus.StandardLogger().WithField("client", "cherrypicker"), 221 repos: []github.Repo{{Fork: true, FullName: "ci-robot/bar"}}, 222 223 prowAssignments: true, 224 } 225 226 if err := s.handleIssueComment(logrus.NewEntry(logrus.StandardLogger()), ic); err != nil { 227 t.Errorf("unexpected error: %v", err) 228 } 229 if ghc.prs[0] != expected { 230 t.Errorf("Expected (%d):\n%s\nGot (%d):\n%+v\n", len(expected), expected, len(ghc.prs[0]), ghc.prs[0]) 231 } 232 } 233 234 func TestCherryPickPR(t *testing.T) { 235 lg, c, err := localgit.New() 236 if err != nil { 237 t.Fatalf("Making localgit: %v", err) 238 } 239 defer func() { 240 if err := lg.Clean(); err != nil { 241 t.Errorf("Cleaning up localgit: %v", err) 242 } 243 if err := c.Clean(); err != nil { 244 t.Errorf("Cleaning up client: %v", err) 245 } 246 }() 247 if err := lg.MakeFakeRepo("foo", "bar"); err != nil { 248 t.Fatalf("Making fake repo: %v", err) 249 } 250 if err := lg.AddCommit("foo", "bar", initialFiles); err != nil { 251 t.Fatalf("Adding initial commit: %v", err) 252 } 253 if err := lg.CheckoutNewBranch("foo", "bar", "release-1.5"); err != nil { 254 t.Fatalf("Checking out pull branch: %v", err) 255 } 256 if err := lg.CheckoutNewBranch("foo", "bar", "release-1.6"); err != nil { 257 t.Fatalf("Checking out pull branch: %v", err) 258 } 259 260 ghc := &fghc{ 261 orgMembers: []github.TeamMember{ 262 { 263 Login: "approver", 264 }, 265 { 266 Login: "merge-bot", 267 }, 268 }, 269 prComments: []github.IssueComment{ 270 { 271 User: github.User{ 272 Login: "developer", 273 }, 274 Body: "a review comment", 275 }, 276 { 277 User: github.User{ 278 Login: "approver", 279 }, 280 Body: "/cherrypick release-1.5\r", 281 }, 282 { 283 User: github.User{ 284 Login: "approver", 285 }, 286 Body: "/cherrypick release-1.6", 287 }, 288 { 289 User: github.User{ 290 Login: "fan", 291 }, 292 Body: "/cherrypick release-1.7", 293 }, 294 { 295 User: github.User{ 296 Login: "approver", 297 }, 298 Body: "/approve", 299 }, 300 { 301 User: github.User{ 302 Login: "merge-bot", 303 }, 304 Body: "Automatic merge from submit-queue.", 305 }, 306 }, 307 isMember: true, 308 createdNum: 3, 309 patch: patch, 310 } 311 pr := github.PullRequestEvent{ 312 Action: github.PullRequestActionClosed, 313 PullRequest: github.PullRequest{ 314 Base: github.PullRequestBranch{ 315 Ref: "master", 316 Repo: github.Repo{ 317 Owner: github.User{ 318 Login: "foo", 319 }, 320 Name: "bar", 321 }, 322 }, 323 Number: 2, 324 Merged: true, 325 MergeSHA: new(string), 326 Title: "This is a fix for Y", 327 }, 328 } 329 330 botName := "ci-robot" 331 332 getSecret := func() []byte { 333 return []byte("sha=abcdefg") 334 } 335 336 s := &Server{ 337 botName: botName, 338 gc: c, 339 push: func(repo, newBranch string) error { return nil }, 340 ghc: ghc, 341 tokenGenerator: getSecret, 342 log: logrus.StandardLogger().WithField("client", "cherrypicker"), 343 repos: []github.Repo{{Fork: true, FullName: "ci-robot/bar"}}, 344 345 prowAssignments: false, 346 } 347 348 if err := s.handlePullRequest(logrus.NewEntry(logrus.StandardLogger()), pr); err != nil { 349 t.Errorf("unexpected error: %v", err) 350 } 351 352 var expectedFn = func(branch string) string { 353 expectedRepo := "foo/bar" 354 expectedTitle := fmt.Sprintf("[%s] This is a fix for Y", branch) 355 expectedBody := "This is an automated cherry-pick of #2" 356 expectedHead := fmt.Sprintf(botName+":"+cherryPickBranchFmt, 2, branch) 357 return fmt.Sprintf(expectedFmt, expectedRepo, expectedTitle, expectedBody, expectedHead, branch, true) 358 } 359 360 if len(ghc.prs) != 2 { 361 t.Fatalf("Expected %d PRs, got %d", 2, len(ghc.prs)) 362 } 363 364 expectedBranches := []string{"release-1.5", "release-1.6"} 365 seenBranches := make(map[string]struct{}) 366 for _, pr := range ghc.prs { 367 if pr != expectedFn("release-1.5") && pr != expectedFn("release-1.6") { 368 t.Errorf("Unexpected PR:\n%s\nExpected to target one of the following branches: %v", pr, expectedBranches) 369 } 370 if pr == expectedFn("release-1.5") { 371 seenBranches["release-1.5"] = struct{}{} 372 } 373 if pr == expectedFn("release-1.6") { 374 seenBranches["release-1.6"] = struct{}{} 375 } 376 } 377 if len(seenBranches) != 2 { 378 t.Fatalf("Expected to see PRs for %d branches, got %d (%v)", 2, len(seenBranches), seenBranches) 379 } 380 }