sigs.k8s.io/prow@v0.0.0-20240503223140-c5e374dc7eb1/pkg/plugins/cherrypickapproved/cherrypickapproved_test.go (about) 1 /* 2 Copyright 2023 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 cherrypickapproved 18 19 import ( 20 "errors" 21 "regexp" 22 "testing" 23 24 "github.com/sirupsen/logrus" 25 "github.com/stretchr/testify/assert" 26 "sigs.k8s.io/prow/pkg/github" 27 "sigs.k8s.io/prow/pkg/labels" 28 "sigs.k8s.io/prow/pkg/plugins" 29 "sigs.k8s.io/prow/pkg/plugins/cherrypickapproved/cherrypickapprovedfakes" 30 ) 31 32 const testOrgRepo = "kubernetes" 33 34 var errTest = errors.New("test") 35 36 func TestHandle(t *testing.T) { 37 t.Parallel() 38 39 successEvent := &github.ReviewEvent{ 40 Action: github.ReviewActionSubmitted, 41 Review: github.Review{ 42 State: github.ReviewStateApproved, 43 User: github.User{Login: "user"}, 44 }, 45 Repo: github.Repo{ 46 Name: testOrgRepo, 47 Owner: github.User{Login: testOrgRepo}, 48 }, 49 PullRequest: github.PullRequest{ 50 Base: github.PullRequestBranch{Ref: "release-1.29"}, 51 }, 52 } 53 54 testConfig := []plugins.CherryPickApproved{ 55 { 56 Org: testOrgRepo, 57 Repo: testOrgRepo, 58 BranchRe: regexp.MustCompile("^release-*"), 59 Approvers: []string{"user"}, 60 }, 61 } 62 63 for _, tc := range []struct { 64 name string 65 config []plugins.CherryPickApproved 66 modifyEvent func(*github.ReviewEvent) *github.ReviewEvent 67 prepare func(*cherrypickapprovedfakes.FakeImpl) 68 assert func(*cherrypickapprovedfakes.FakeImpl, error) 69 }{ 70 { 71 name: "success apply cherry-pick-approved label", 72 config: testConfig, 73 prepare: func(mock *cherrypickapprovedfakes.FakeImpl) { 74 mock.GetCombinedStatusReturns(&github.CombinedStatus{}, nil) 75 mock.GetIssueLabelsReturns( 76 []github.Label{ 77 {Name: labels.LGTM}, 78 {Name: labels.Approved}, 79 {Name: labels.CpUnapproved}, 80 }, 81 nil, 82 ) 83 }, 84 assert: func(mock *cherrypickapprovedfakes.FakeImpl, err error) { 85 assert.NoError(t, err) 86 assert.EqualValues(t, 1, mock.AddLabelCallCount()) 87 assert.EqualValues(t, 1, mock.RemoveLabelCallCount()) 88 }, 89 }, 90 { 91 name: "success but failed to apply/remove labels", 92 config: testConfig, 93 prepare: func(mock *cherrypickapprovedfakes.FakeImpl) { 94 mock.GetCombinedStatusReturns(&github.CombinedStatus{}, nil) 95 mock.GetIssueLabelsReturns( 96 []github.Label{ 97 {Name: labels.LGTM}, 98 {Name: labels.Approved}, 99 {Name: labels.CpUnapproved}, 100 }, 101 nil, 102 ) 103 mock.AddLabelReturns(errTest) 104 mock.RemoveLabelReturns(errTest) 105 }, 106 assert: func(mock *cherrypickapprovedfakes.FakeImpl, err error) { 107 assert.NoError(t, err) 108 assert.EqualValues(t, 1, mock.AddLabelCallCount()) 109 assert.EqualValues(t, 1, mock.RemoveLabelCallCount()) 110 }, 111 }, 112 { 113 name: "skip non approver", 114 config: []plugins.CherryPickApproved{{ 115 Org: testOrgRepo, 116 Repo: testOrgRepo, 117 BranchRe: regexp.MustCompile("^release-*"), 118 Approvers: []string{"wrong"}, 119 }}, 120 prepare: func(mock *cherrypickapprovedfakes.FakeImpl) { 121 mock.GetCombinedStatusReturns(&github.CombinedStatus{}, nil) 122 mock.GetIssueLabelsReturns( 123 []github.Label{ 124 {Name: labels.LGTM}, 125 {Name: labels.Approved}, 126 {Name: labels.CpUnapproved}, 127 }, 128 nil, 129 ) 130 }, 131 assert: func(mock *cherrypickapprovedfakes.FakeImpl, err error) { 132 assert.NoError(t, err) 133 assert.EqualValues(t, 0, mock.AddLabelCallCount()) 134 assert.EqualValues(t, 0, mock.RemoveLabelCallCount()) 135 }, 136 }, 137 { 138 name: "error on GetIssueLabels", 139 config: testConfig, 140 prepare: func(mock *cherrypickapprovedfakes.FakeImpl) { 141 mock.GetCombinedStatusReturns(&github.CombinedStatus{}, nil) 142 mock.GetIssueLabelsReturns(nil, errTest) 143 }, 144 assert: func(mock *cherrypickapprovedfakes.FakeImpl, err error) { 145 assert.Error(t, err) 146 }, 147 }, 148 { 149 name: "error on GetCombinedStatus", 150 config: testConfig, 151 prepare: func(mock *cherrypickapprovedfakes.FakeImpl) { 152 mock.GetCombinedStatusReturns(nil, errTest) 153 }, 154 assert: func(mock *cherrypickapprovedfakes.FakeImpl, err error) { 155 assert.Error(t, err) 156 }, 157 }, 158 { 159 name: "skip with failed tests", 160 config: testConfig, 161 prepare: func(mock *cherrypickapprovedfakes.FakeImpl) { 162 mock.GetCombinedStatusReturns(&github.CombinedStatus{ 163 Statuses: []github.Status{{State: github.StatusError}}, 164 }, nil) 165 }, 166 assert: func(mock *cherrypickapprovedfakes.FakeImpl, err error) { 167 assert.NoError(t, err) 168 assert.EqualValues(t, 0, mock.GetIssueLabelsCallCount()) 169 }, 170 }, 171 { 172 name: "skip with wrong review state", 173 config: testConfig, 174 modifyEvent: func(e *github.ReviewEvent) *github.ReviewEvent { 175 newEvent := *e 176 newEvent.Review.State = github.ReviewStateCommented 177 return &newEvent 178 }, 179 prepare: func(mock *cherrypickapprovedfakes.FakeImpl) {}, 180 assert: func(mock *cherrypickapprovedfakes.FakeImpl, err error) { 181 assert.NoError(t, err) 182 assert.EqualValues(t, 0, mock.GetCombinedStatusCallCount()) 183 }, 184 }, 185 { 186 name: "skip with wrong review action", 187 config: testConfig, 188 modifyEvent: func(e *github.ReviewEvent) *github.ReviewEvent { 189 newEvent := *e 190 newEvent.Action = github.ReviewActionEdited 191 return &newEvent 192 }, 193 prepare: func(mock *cherrypickapprovedfakes.FakeImpl) {}, 194 assert: func(mock *cherrypickapprovedfakes.FakeImpl, err error) { 195 assert.NoError(t, err) 196 assert.EqualValues(t, 0, mock.GetCombinedStatusCallCount()) 197 }, 198 }, 199 { 200 name: "skip with non matching branch", 201 config: testConfig, 202 modifyEvent: func(e *github.ReviewEvent) *github.ReviewEvent { 203 newEvent := *e 204 newEvent.PullRequest.Base.Ref = "invalid" 205 return &newEvent 206 }, 207 prepare: func(mock *cherrypickapprovedfakes.FakeImpl) {}, 208 assert: func(mock *cherrypickapprovedfakes.FakeImpl, err error) { 209 assert.NoError(t, err) 210 assert.EqualValues(t, 0, mock.GetCombinedStatusCallCount()) 211 }, 212 }, 213 { 214 name: "skip with no approvers", 215 config: []plugins.CherryPickApproved{{ 216 Org: testOrgRepo, 217 Repo: testOrgRepo, 218 BranchRe: regexp.MustCompile("^release-*"), 219 }}, 220 prepare: func(mock *cherrypickapprovedfakes.FakeImpl) {}, 221 assert: func(mock *cherrypickapprovedfakes.FakeImpl, err error) { 222 assert.NoError(t, err) 223 assert.EqualValues(t, 0, mock.GetCombinedStatusCallCount()) 224 }, 225 }, 226 { 227 name: "skip with non matching repo", 228 config: testConfig, 229 modifyEvent: func(e *github.ReviewEvent) *github.ReviewEvent { 230 newEvent := *e 231 newEvent.Repo.Name = "invalid" 232 return &newEvent 233 }, 234 prepare: func(mock *cherrypickapprovedfakes.FakeImpl) {}, 235 assert: func(mock *cherrypickapprovedfakes.FakeImpl, err error) { 236 assert.NoError(t, err) 237 assert.EqualValues(t, 0, mock.GetCombinedStatusCallCount()) 238 }, 239 }, 240 { 241 name: "skip with non matching org", 242 config: testConfig, 243 modifyEvent: func(e *github.ReviewEvent) *github.ReviewEvent { 244 newEvent := *e 245 newEvent.Repo.Owner.Login = "invalid" 246 return &newEvent 247 }, 248 prepare: func(mock *cherrypickapprovedfakes.FakeImpl) {}, 249 assert: func(mock *cherrypickapprovedfakes.FakeImpl, err error) { 250 assert.NoError(t, err) 251 assert.EqualValues(t, 0, mock.GetCombinedStatusCallCount()) 252 }, 253 }, 254 } { 255 t.Run(tc.name, func(t *testing.T) { 256 mock := &cherrypickapprovedfakes.FakeImpl{} 257 tc.prepare(mock) 258 259 event := successEvent 260 if tc.modifyEvent != nil { 261 event = tc.modifyEvent(event) 262 } 263 264 sut := newHandler() 265 sut.impl = mock 266 267 log := logrus.NewEntry(logrus.StandardLogger()) 268 err := sut.handle(log, nil, *event, tc.config) 269 270 tc.assert(mock, err) 271 }) 272 } 273 }