sigs.k8s.io/prow@v0.0.0-20240503223140-c5e374dc7eb1/pkg/plugins/mergecommitblocker/mergecommitblocker_test.go (about)

     1  /*
     2  Copyright 2019 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 mergecommitblocker
    18  
    19  import (
    20  	"fmt"
    21  	"testing"
    22  
    23  	"github.com/sirupsen/logrus"
    24  	"sigs.k8s.io/prow/pkg/commentpruner"
    25  	"sigs.k8s.io/prow/pkg/git/localgit"
    26  	"sigs.k8s.io/prow/pkg/github"
    27  	"sigs.k8s.io/prow/pkg/labels"
    28  )
    29  
    30  var defaultBranch = localgit.DefaultBranch("")
    31  
    32  type strSet map[string]struct{}
    33  
    34  type fakeGHClient struct {
    35  	labels   strSet
    36  	comments map[int]string
    37  }
    38  
    39  func (f *fakeGHClient) AddLabel(org, repo string, number int, label string) error {
    40  	f.labels[label] = struct{}{}
    41  	return nil
    42  }
    43  
    44  func (f *fakeGHClient) RemoveLabel(org, repo string, number int, label string) error {
    45  	delete(f.labels, label)
    46  	return nil
    47  }
    48  
    49  func (f *fakeGHClient) GetIssueLabels(org, repo string, number int) ([]github.Label, error) {
    50  	var labels []github.Label
    51  	for l := range f.labels {
    52  		labels = append(labels, github.Label{Name: l})
    53  	}
    54  	return labels, nil
    55  }
    56  
    57  func (f *fakeGHClient) CreateComment(org, repo string, number int, comment string) error {
    58  	if _, ok := f.comments[number]; ok {
    59  		return fmt.Errorf("comment id %d already exists", number)
    60  	}
    61  	f.comments[number] = comment
    62  	return nil
    63  }
    64  
    65  func (f *fakeGHClient) DeleteComment(org, repo string, id int) error {
    66  	delete(f.comments, id)
    67  	return nil
    68  }
    69  
    70  func (f *fakeGHClient) BotUserChecker() (func(candidate string) bool, error) {
    71  	return func(candidate string) bool {
    72  		return candidate == "foo"
    73  	}, nil
    74  }
    75  
    76  func (f *fakeGHClient) ListIssueComments(org, repo string, number int) ([]github.IssueComment, error) {
    77  	var ghComments []github.IssueComment
    78  	for id, c := range f.comments {
    79  		ghComment := github.IssueComment{
    80  			ID:   id,
    81  			Body: c,
    82  			User: github.User{Login: "foo"},
    83  		}
    84  		ghComments = append(ghComments, ghComment)
    85  	}
    86  	return ghComments, nil
    87  }
    88  
    89  func TestHandleV2(t *testing.T) {
    90  	testHandle(localgit.NewV2, t)
    91  }
    92  
    93  func testHandle(clients localgit.Clients, t *testing.T) {
    94  	lg, c, err := clients()
    95  	if err != nil {
    96  		t.Fatalf("Making localgit: %v", err)
    97  	}
    98  	defer func() {
    99  		if err := lg.Clean(); err != nil {
   100  			t.Errorf("Cleaning up localgit: %v", err)
   101  		}
   102  		if err := c.Clean(); err != nil {
   103  			t.Errorf("Cleaning up client: %v", err)
   104  		}
   105  	}()
   106  	if err := lg.MakeFakeRepo("foo", "bar"); err != nil {
   107  		t.Fatalf("Making fake repo: %v", err)
   108  	}
   109  	var (
   110  		checkoutPR = func(prNum int) {
   111  			if err := lg.CheckoutNewBranch("foo", "bar", fmt.Sprintf("pull/%d/head", prNum)); err != nil {
   112  				t.Fatalf("Creating & checking out pull branch pull/%d/head: %v", prNum, err)
   113  			}
   114  		}
   115  		checkoutBranch = func(branch string) {
   116  			if err := lg.Checkout("foo", "bar", branch); err != nil {
   117  				t.Fatalf("Checking out branch %s: %v", branch, err)
   118  			}
   119  		}
   120  		addCommit = func(file string) {
   121  			if err := lg.AddCommit("foo", "bar", map[string][]byte{file: {}}); err != nil {
   122  				t.Fatalf("Adding commit: %v", err)
   123  			}
   124  		}
   125  		mergeMaster = func() {
   126  			if _, err := lg.Merge("foo", "bar", defaultBranch); err != nil {
   127  				t.Fatalf("Rebasing commit: %v", err)
   128  			}
   129  		}
   130  		rebaseMaster = func() {
   131  			if _, err := lg.Rebase("foo", "bar", defaultBranch); err != nil {
   132  				t.Fatalf("Rebasing commit: %v", err)
   133  			}
   134  		}
   135  	)
   136  
   137  	type testCase struct {
   138  		name          string
   139  		fakeGHClient  *fakeGHClient
   140  		prNum         int
   141  		checkout      func()
   142  		mergeOrRebase func()
   143  		wantLabel     bool
   144  		wantComment   bool
   145  	}
   146  	testcases := []testCase{
   147  		{
   148  			name: "merge commit label not exist, PR has merge commits",
   149  			fakeGHClient: &fakeGHClient{
   150  				labels:   strSet{},
   151  				comments: make(map[int]string),
   152  			},
   153  			prNum:         11,
   154  			checkout:      func() { checkoutBranch("pull/11/head") },
   155  			mergeOrRebase: mergeMaster,
   156  			wantLabel:     true,
   157  			wantComment:   true,
   158  		},
   159  		{
   160  			name: "merge commit label exists, PR has merge commits",
   161  			fakeGHClient: &fakeGHClient{
   162  				labels:   strSet{labels.MergeCommits: struct{}{}},
   163  				comments: map[int]string{12: commentBody},
   164  			},
   165  			prNum:         12,
   166  			checkout:      func() { checkoutBranch("pull/12/head") },
   167  			mergeOrRebase: mergeMaster,
   168  			wantLabel:     true,
   169  			wantComment:   true,
   170  		},
   171  		{
   172  			name: "merge commit label not exists, PR doesn't have merge commits",
   173  			fakeGHClient: &fakeGHClient{
   174  				labels:   strSet{},
   175  				comments: make(map[int]string),
   176  			},
   177  			prNum:         13,
   178  			checkout:      func() { checkoutBranch("pull/13/head") },
   179  			mergeOrRebase: rebaseMaster,
   180  			wantLabel:     false,
   181  			wantComment:   false,
   182  		},
   183  		{
   184  			name: "merge commit label exists, PR doesn't have merge commits",
   185  			fakeGHClient: &fakeGHClient{
   186  				labels:   strSet{labels.MergeCommits: struct{}{}},
   187  				comments: map[int]string{14: commentBody},
   188  			},
   189  			prNum:         14,
   190  			checkout:      func() { checkoutBranch("pull/14/head") },
   191  			mergeOrRebase: rebaseMaster,
   192  			wantLabel:     false,
   193  			wantComment:   false,
   194  		},
   195  	}
   196  
   197  	addCommit("wow")
   198  	// preparation work: branch off all prs upon commit 'wow'
   199  	for _, tt := range testcases {
   200  		checkoutPR(tt.prNum)
   201  	}
   202  	// switch back to master and create a new commit 'ouch'
   203  	checkoutBranch(defaultBranch)
   204  	addCommit("ouch")
   205  	masterSHA, err := lg.RevParse("foo", "bar", "HEAD")
   206  	if err != nil {
   207  		t.Fatalf("Fetching SHA: %v", err)
   208  	}
   209  
   210  	for _, tt := range testcases {
   211  		tt.checkout()
   212  		tt.mergeOrRebase()
   213  		prSHA, err := lg.RevParse("foo", "bar", "HEAD")
   214  		if err != nil {
   215  			t.Fatalf("Fetching SHA: %v", err)
   216  		}
   217  		pre := &github.PullRequestEvent{
   218  			Action: github.PullRequestActionOpened,
   219  			PullRequest: github.PullRequest{
   220  				Number: tt.prNum,
   221  				Base: github.PullRequestBranch{
   222  					Repo: github.Repo{
   223  						Owner: github.User{Login: "foo"},
   224  						Name:  "bar",
   225  					},
   226  					SHA: masterSHA,
   227  				},
   228  				Head: github.PullRequestBranch{
   229  					Repo: github.Repo{
   230  						Owner: github.User{Login: "foo"},
   231  						Name:  "bar",
   232  					},
   233  					SHA: prSHA,
   234  				},
   235  			},
   236  		}
   237  		log := logrus.NewEntry(logrus.New())
   238  		fakePruner := commentpruner.NewEventClient(tt.fakeGHClient, log, "foo", "bar", tt.prNum)
   239  		if err := handle(tt.fakeGHClient, c, fakePruner, log, pre); err != nil {
   240  			t.Errorf("Expect err is nil, but got %v", err)
   241  		}
   242  		// verify if MergeCommits label as expected
   243  		if _, got := tt.fakeGHClient.labels[labels.MergeCommits]; got != tt.wantLabel {
   244  			t.Errorf("Case: %v. Expect MergeCommits=%v, but got %v", tt.name, tt.wantLabel, got)
   245  		}
   246  		// verify if github comment is created/pruned as expected
   247  		if _, got := tt.fakeGHClient.comments[tt.prNum]; got != tt.wantComment {
   248  			t.Errorf("Case: %v. Expect wantComment=%v, but got %v", tt.name, tt.wantComment, got)
   249  		}
   250  	}
   251  }