sigs.k8s.io/prow@v0.0.0-20240503223140-c5e374dc7eb1/pkg/plugins/cherrypickunapproved/cherrypick-unapproved_test.go (about) 1 /* 2 Copyright 2018 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 cherrypickunapproved 18 19 import ( 20 "encoding/json" 21 "reflect" 22 "regexp" 23 "testing" 24 25 "github.com/sirupsen/logrus" 26 27 "sigs.k8s.io/prow/pkg/github" 28 "sigs.k8s.io/prow/pkg/labels" 29 ) 30 31 type fakeClient struct { 32 // current labels 33 labels []string 34 // labels that are added 35 added []string 36 // labels that are removed 37 removed []string 38 // commentsAdded tracks the comments in the client 39 commentsAdded map[int][]string 40 } 41 42 // AddLabel adds a label to the specified PR or issue 43 func (fc *fakeClient) AddLabel(owner, repo string, number int, label string) error { 44 fc.added = append(fc.added, label) 45 fc.labels = append(fc.labels, label) 46 return nil 47 } 48 49 // RemoveLabel removes the label from the specified PR or issue 50 func (fc *fakeClient) RemoveLabel(owner, repo string, number int, label string) error { 51 fc.removed = append(fc.removed, label) 52 53 // remove from existing labels 54 for k, v := range fc.labels { 55 if label == v { 56 fc.labels = append(fc.labels[:k], fc.labels[k+1:]...) 57 break 58 } 59 } 60 61 return nil 62 } 63 64 // GetIssueLabels gets the current labels on the specified PR or issue 65 func (fc *fakeClient) GetIssueLabels(owner, repo string, number int) ([]github.Label, error) { 66 var la []github.Label 67 for _, l := range fc.labels { 68 la = append(la, github.Label{Name: l}) 69 } 70 return la, nil 71 } 72 73 // CreateComment adds and tracks a comment in the client 74 func (fc *fakeClient) CreateComment(owner, repo string, number int, comment string) error { 75 fc.commentsAdded[number] = append(fc.commentsAdded[number], comment) 76 return nil 77 } 78 79 // NumComments counts the number of tracked comments 80 func (fc *fakeClient) NumComments() int { 81 n := 0 82 for _, comments := range fc.commentsAdded { 83 n += len(comments) 84 } 85 return n 86 } 87 88 type fakePruner struct{} 89 90 func (fp *fakePruner) PruneComments(shouldPrune func(github.IssueComment) bool) {} 91 92 func makeFakePullRequestEvent(action github.PullRequestEventAction, branch string, changes json.RawMessage) github.PullRequestEvent { 93 event := github.PullRequestEvent{ 94 Action: action, 95 PullRequest: github.PullRequest{ 96 Base: github.PullRequestBranch{ 97 Ref: branch, 98 }, 99 }, 100 } 101 102 if changes != nil { 103 event.Changes = changes 104 } 105 106 return event 107 } 108 109 func TestCherryPickUnapprovedLabel(t *testing.T) { 110 var testcases = []struct { 111 name string 112 branch string 113 changes json.RawMessage 114 action github.PullRequestEventAction 115 labels []string 116 added []string 117 removed []string 118 expectComment bool 119 }{ 120 { 121 name: "unsupported PR action -> no-op", 122 branch: "release-1.10", 123 action: github.PullRequestActionClosed, 124 labels: []string{}, 125 added: []string{}, 126 removed: []string{}, 127 expectComment: false, 128 }, 129 { 130 name: "branch that does match regexp -> no-op", 131 branch: "master", 132 action: github.PullRequestActionOpened, 133 labels: []string{}, 134 added: []string{}, 135 removed: []string{}, 136 expectComment: false, 137 }, 138 { 139 name: "has cpUnapproved -> no-op", 140 branch: "release-1.10", 141 action: github.PullRequestActionOpened, 142 labels: []string{labels.CpUnapproved}, 143 added: []string{}, 144 removed: []string{}, 145 expectComment: false, 146 }, 147 { 148 name: "has both cpApproved and cpUnapproved -> remove cpUnapproved", 149 branch: "release-1.10", 150 action: github.PullRequestActionOpened, 151 labels: []string{labels.CpApproved, labels.CpUnapproved}, 152 added: []string{}, 153 removed: []string{labels.CpUnapproved}, 154 expectComment: false, 155 }, 156 { 157 name: "does not have any labels, PR opened against a release branch -> add cpUnapproved and comment", 158 branch: "release-1.10", 159 action: github.PullRequestActionOpened, 160 labels: []string{}, 161 added: []string{labels.CpUnapproved}, 162 removed: []string{}, 163 expectComment: true, 164 }, 165 { 166 name: "does not have any labels, PR reopened against a release branch -> add cpUnapproved and comment", 167 branch: "release-1.10", 168 action: github.PullRequestActionReopened, 169 labels: []string{}, 170 added: []string{labels.CpUnapproved}, 171 removed: []string{}, 172 expectComment: true, 173 }, 174 { 175 name: "PR base branch master edited to release -> add cpUnapproved and comment", 176 branch: "release-1.10", 177 action: github.PullRequestActionEdited, 178 changes: json.RawMessage(`{"base": {"ref": {"from": "master"}, "sha": {"from": "sha"}}}`), 179 labels: []string{}, 180 added: []string{labels.CpUnapproved}, 181 removed: []string{}, 182 expectComment: true, 183 }, 184 { 185 name: "PR base branch edited from release to master -> remove cpApproved and cpUnapproved", 186 branch: "master", 187 action: github.PullRequestActionEdited, 188 changes: json.RawMessage(`{"base": {"ref": {"from": "release-1.10"}, "sha": {"from": "sha"}}}`), 189 labels: []string{labels.CpApproved, labels.CpUnapproved}, 190 added: []string{}, 191 removed: []string{labels.CpApproved, labels.CpUnapproved}, 192 expectComment: false, 193 }, 194 { 195 name: "PR title changed -> no-op", 196 branch: "release-1.10", 197 action: github.PullRequestActionEdited, 198 changes: json.RawMessage(`{"title": {"from": "Update README.md"}}`), 199 labels: []string{labels.CpApproved, labels.CpUnapproved}, 200 added: []string{}, 201 removed: []string{}, 202 expectComment: false, 203 }, 204 } 205 206 for _, tc := range testcases { 207 fc := &fakeClient{ 208 labels: tc.labels, 209 added: []string{}, 210 removed: []string{}, 211 commentsAdded: make(map[int][]string), 212 } 213 214 event := makeFakePullRequestEvent(tc.action, tc.branch, tc.changes) 215 branchRe := regexp.MustCompile(`^release-.*$`) 216 comment := "dummy cumment" 217 err := handlePR(fc, logrus.WithField("plugin", "fake-cherrypick-unapproved"), &event, &fakePruner{}, branchRe, comment) 218 switch { 219 case err != nil: 220 t.Errorf("%s: unexpected error: %v", tc.name, err) 221 case !reflect.DeepEqual(tc.added, fc.added): 222 t.Errorf("%s: added %v != actual %v", tc.name, tc.added, fc.added) 223 case !reflect.DeepEqual(tc.removed, fc.removed): 224 t.Errorf("%s: removed %v != actual %v", tc.name, tc.removed, fc.removed) 225 } 226 227 // if we expected a comment, verify that a comment was made 228 numComments := fc.NumComments() 229 if tc.expectComment && numComments != 1 { 230 t.Errorf("%s: expected 1 comment but received %d comments", tc.name, numComments) 231 } 232 if !tc.expectComment && numComments != 0 { 233 t.Errorf("%s: expected no comments but received %d comments", tc.name, numComments) 234 } 235 } 236 }