github.com/yrj2011/jx-test-infra@v0.0.0-20190529031832-7a2065ee98eb/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  func TestCherryPickIC(t *testing.T) {
   143  	lg, c, err := localgit.New()
   144  	if err != nil {
   145  		t.Fatalf("Making localgit: %v", err)
   146  	}
   147  	defer func() {
   148  		if err := lg.Clean(); err != nil {
   149  			t.Errorf("Cleaning up localgit: %v", err)
   150  		}
   151  		if err := c.Clean(); err != nil {
   152  			t.Errorf("Cleaning up client: %v", err)
   153  		}
   154  	}()
   155  	if err := lg.MakeFakeRepo("foo", "bar"); err != nil {
   156  		t.Fatalf("Making fake repo: %v", err)
   157  	}
   158  	if err := lg.AddCommit("foo", "bar", initialFiles); err != nil {
   159  		t.Fatalf("Adding initial commit: %v", err)
   160  	}
   161  	if err := lg.CheckoutNewBranch("foo", "bar", "stage"); err != nil {
   162  		t.Fatalf("Checking out pull branch: %v", err)
   163  	}
   164  
   165  	ghc := &fghc{
   166  		pr: &github.PullRequest{
   167  			Base: github.PullRequestBranch{
   168  				Ref: "master",
   169  			},
   170  			Merged: true,
   171  			Title:  "This is a fix for X",
   172  		},
   173  		isMember:   true,
   174  		createdNum: 3,
   175  		patch:      patch,
   176  	}
   177  	ic := github.IssueCommentEvent{
   178  		Action: github.IssueCommentActionCreated,
   179  		Repo: github.Repo{
   180  			Owner: github.User{
   181  				Login: "foo",
   182  			},
   183  			Name:     "bar",
   184  			FullName: "foo/bar",
   185  		},
   186  		Issue: github.Issue{
   187  			Number:      2,
   188  			State:       "closed",
   189  			PullRequest: &struct{}{},
   190  		},
   191  		Comment: github.IssueComment{
   192  			User: github.User{
   193  				Login: "wiseguy",
   194  			},
   195  			Body: "/cherrypick stage",
   196  		},
   197  	}
   198  
   199  	botName := "ci-robot"
   200  	expectedRepo := "foo/bar"
   201  	expectedTitle := "[stage] This is a fix for X"
   202  	expectedBody := "This is an automated cherry-pick of #2\n\n/assign wiseguy"
   203  	expectedBase := "stage"
   204  	expectedHead := fmt.Sprintf(botName+":"+cherryPickBranchFmt, 2, expectedBase)
   205  	expected := fmt.Sprintf(expectedFmt, expectedRepo, expectedTitle, expectedBody, expectedHead, expectedBase, true)
   206  
   207  	getSecret := func() []byte {
   208  		return []byte("sha=abcdefg")
   209  	}
   210  
   211  	s := &Server{
   212  		botName:        botName,
   213  		gc:             c,
   214  		push:           func(repo, newBranch string) error { return nil },
   215  		ghc:            ghc,
   216  		tokenGenerator: getSecret,
   217  		log:            logrus.StandardLogger().WithField("client", "cherrypicker"),
   218  		repos:          []github.Repo{{Fork: true, FullName: "ci-robot/bar"}},
   219  
   220  		prowAssignments: true,
   221  	}
   222  
   223  	if err := s.handleIssueComment(logrus.NewEntry(logrus.StandardLogger()), ic); err != nil {
   224  		t.Errorf("unexpected error: %v", err)
   225  	}
   226  	if ghc.prs[0] != expected {
   227  		t.Errorf("Expected (%d):\n%s\nGot (%d):\n%+v\n", len(expected), expected, len(ghc.prs[0]), ghc.prs[0])
   228  	}
   229  }
   230  
   231  func TestCherryPickPR(t *testing.T) {
   232  	lg, c, err := localgit.New()
   233  	if err != nil {
   234  		t.Fatalf("Making localgit: %v", err)
   235  	}
   236  	defer func() {
   237  		if err := lg.Clean(); err != nil {
   238  			t.Errorf("Cleaning up localgit: %v", err)
   239  		}
   240  		if err := c.Clean(); err != nil {
   241  			t.Errorf("Cleaning up client: %v", err)
   242  		}
   243  	}()
   244  	if err := lg.MakeFakeRepo("foo", "bar"); err != nil {
   245  		t.Fatalf("Making fake repo: %v", err)
   246  	}
   247  	if err := lg.AddCommit("foo", "bar", initialFiles); err != nil {
   248  		t.Fatalf("Adding initial commit: %v", err)
   249  	}
   250  	if err := lg.CheckoutNewBranch("foo", "bar", "release-1.5"); err != nil {
   251  		t.Fatalf("Checking out pull branch: %v", err)
   252  	}
   253  	if err := lg.CheckoutNewBranch("foo", "bar", "release-1.6"); err != nil {
   254  		t.Fatalf("Checking out pull branch: %v", err)
   255  	}
   256  
   257  	ghc := &fghc{
   258  		orgMembers: []github.TeamMember{
   259  			{
   260  				Login: "approver",
   261  			},
   262  			{
   263  				Login: "merge-bot",
   264  			},
   265  		},
   266  		prComments: []github.IssueComment{
   267  			{
   268  				User: github.User{
   269  					Login: "developer",
   270  				},
   271  				Body: "a review comment",
   272  			},
   273  			{
   274  				User: github.User{
   275  					Login: "approver",
   276  				},
   277  				Body: "/cherrypick release-1.5\r",
   278  			},
   279  			{
   280  				User: github.User{
   281  					Login: "approver",
   282  				},
   283  				Body: "/cherrypick release-1.6",
   284  			},
   285  			{
   286  				User: github.User{
   287  					Login: "fan",
   288  				},
   289  				Body: "/cherrypick release-1.7",
   290  			},
   291  			{
   292  				User: github.User{
   293  					Login: "approver",
   294  				},
   295  				Body: "/approve",
   296  			},
   297  			{
   298  				User: github.User{
   299  					Login: "merge-bot",
   300  				},
   301  				Body: "Automatic merge from submit-queue.",
   302  			},
   303  		},
   304  		isMember:   true,
   305  		createdNum: 3,
   306  		patch:      patch,
   307  	}
   308  	pr := github.PullRequestEvent{
   309  		Action: github.PullRequestActionClosed,
   310  		PullRequest: github.PullRequest{
   311  			Base: github.PullRequestBranch{
   312  				Ref: "master",
   313  				Repo: github.Repo{
   314  					Owner: github.User{
   315  						Login: "foo",
   316  					},
   317  					Name: "bar",
   318  				},
   319  			},
   320  			Number:   2,
   321  			Merged:   true,
   322  			MergeSHA: new(string),
   323  			Title:    "This is a fix for Y",
   324  		},
   325  	}
   326  
   327  	botName := "ci-robot"
   328  
   329  	getSecret := func() []byte {
   330  		return []byte("sha=abcdefg")
   331  	}
   332  
   333  	s := &Server{
   334  		botName:        botName,
   335  		gc:             c,
   336  		push:           func(repo, newBranch string) error { return nil },
   337  		ghc:            ghc,
   338  		tokenGenerator: getSecret,
   339  		log:            logrus.StandardLogger().WithField("client", "cherrypicker"),
   340  		repos:          []github.Repo{{Fork: true, FullName: "ci-robot/bar"}},
   341  
   342  		prowAssignments: false,
   343  	}
   344  
   345  	if err := s.handlePullRequest(logrus.NewEntry(logrus.StandardLogger()), pr); err != nil {
   346  		t.Errorf("unexpected error: %v", err)
   347  	}
   348  
   349  	var expectedFn = func(branch string) string {
   350  		expectedRepo := "foo/bar"
   351  		expectedTitle := fmt.Sprintf("[%s] This is a fix for Y", branch)
   352  		expectedBody := "This is an automated cherry-pick of #2"
   353  		expectedHead := fmt.Sprintf(botName+":"+cherryPickBranchFmt, 2, branch)
   354  		return fmt.Sprintf(expectedFmt, expectedRepo, expectedTitle, expectedBody, expectedHead, branch, true)
   355  	}
   356  
   357  	if len(ghc.prs) != 2 {
   358  		t.Fatalf("Expected %d PRs, got %d", 2, len(ghc.prs))
   359  	}
   360  
   361  	expectedBranches := []string{"release-1.5", "release-1.6"}
   362  	seenBranches := make(map[string]struct{})
   363  	for _, pr := range ghc.prs {
   364  		if pr != expectedFn("release-1.5") && pr != expectedFn("release-1.6") {
   365  			t.Errorf("Unexpected PR:\n%s\nExpected to target one of the following branches: %v", pr, expectedBranches)
   366  		}
   367  		if pr == expectedFn("release-1.5") {
   368  			seenBranches["release-1.5"] = struct{}{}
   369  		}
   370  		if pr == expectedFn("release-1.6") {
   371  			seenBranches["release-1.6"] = struct{}{}
   372  		}
   373  	}
   374  	if len(seenBranches) != 2 {
   375  		t.Fatalf("Expected to see PRs for %d branches, got %d (%v)", 2, len(seenBranches), seenBranches)
   376  	}
   377  }