sigs.k8s.io/prow@v0.0.0-20240503223140-c5e374dc7eb1/pkg/plugins/slackevents/slackevents_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 slackevents 18 19 import ( 20 "encoding/json" 21 "strings" 22 "testing" 23 24 "sigs.k8s.io/prow/pkg/config" 25 "sigs.k8s.io/prow/pkg/github" 26 "sigs.k8s.io/prow/pkg/github/fakegithub" 27 "sigs.k8s.io/prow/pkg/plugins" 28 "sigs.k8s.io/prow/pkg/slack" 29 ) 30 31 type FakeClient struct { 32 SentMessages map[string][]string 33 } 34 35 func (fk *FakeClient) WriteMessage(text string, channel string) error { 36 fk.SentMessages[channel] = append(fk.SentMessages[channel], text) 37 return nil 38 } 39 40 func TestPush(t *testing.T) { 41 var pushStr = `{ 42 "ref": "refs/heads/master", 43 "before": "d73a75b4b1ddb63870954b9a60a63acaa4cb1ca5", 44 "after": "045a6dca07840efaf3311450b615e19b5c75f787", 45 "created": false, 46 "deleted": false, 47 "forced": false, 48 "compare": "https://github.com/kubernetes/kubernetes/compare/d73a75b4b1dd...045a6dca0784", 49 "commits": [ 50 { 51 "id": "8427d5a27478c80167fd66affe1bd7cd01d3f9a8", 52 "message": "Decrease fluentd cpu request", 53 "url": "https://github.com/kubernetes/kubernetes/commit/8427d5a27478c80167fd66affe1bd7cd01d3f9a8" 54 }, 55 { 56 "id": "045a6dca07840efaf3311450b615e19b5c75f787", 57 "message": "Merge pull request #47906 from gmarek/fluentd\n\nDecrese fluentd cpu request\n\nFix #47905\r\n\r\ncc @piosz - this should fix your tests.\r\ncc @dchen1107", 58 "url": "https://github.com/kubernetes/kubernetes/commit/045a6dca07840efaf3311450b615e19b5c75f787" 59 } 60 ], 61 "repository": { 62 "id": 20580498, 63 "name": "kubernetes", 64 "owner": { 65 "name": "kubernetes", 66 "login": "kubernetes" 67 }, 68 "url": "https://github.com/kubernetes/kubernetes" 69 }, 70 "pusher": { 71 "name": "k8s-merge-robot", 72 "email": "k8s-merge-robot@users.noreply.github.com" 73 } 74 }` 75 76 var pushEv github.PushEvent 77 if err := json.Unmarshal([]byte(pushStr), &pushEv); err != nil { 78 t.Fatalf("Failed to parse Push Notification: %s", err) 79 } 80 81 // Non bot user merged the PR 82 pushEvManual := pushEv 83 pushEvManual.Pusher.Name = "Jester Tester" 84 pushEvManual.Pusher.Email = "tester@users.noreply.github.com" 85 pushEvManual.Sender.Login = "tester" 86 pushEvManual.Ref = "refs/heads/master" 87 88 pushEvManualBranchExempted := pushEv 89 pushEvManualBranchExempted.Pusher.Name = "Warren Teened" 90 pushEvManualBranchExempted.Pusher.Email = "wteened@users.noreply.github.com" 91 pushEvManualBranchExempted.Sender.Login = "WTeened" 92 pushEvManualBranchExempted.Ref = "refs/heads/warrens-branch" 93 94 pushEvManualNotBranchExempted := pushEvManualBranchExempted 95 pushEvManualNotBranchExempted.Ref = "refs/heads/master" 96 97 pushEvManualCreated := pushEvManual 98 pushEvManualCreated.Created = true 99 pushEvManualCreated.Ref = "refs/heads/release-1.99" 100 pushEvManualCreated.Compare = "https://github.com/kubernetes/kubernetes/compare/045a6dca0784" 101 102 pushEvManualDeleted := pushEvManual 103 pushEvManualDeleted.Deleted = true 104 pushEvManualDeleted.Ref = "refs/heads/release-1.99" 105 pushEvManualDeleted.Compare = "https://github.com/kubernetes/kubernetes/compare/d73a75b4b1dd...000000000000" 106 107 pushEvManualForced := pushEvManual 108 pushEvManualForced.Forced = true 109 110 noMessages := map[string][]string{} 111 stdWarningMessages := map[string][]string{ 112 "sig-contribex": {"*Warning:* tester (<@tester>) manually merged 2 commit(s) into master: https://github.com/kubernetes/kubernetes/compare/d73a75b4b1dd...045a6dca0784"}, 113 "kubernetes-foo": {"*Warning:* tester (<@tester>) manually merged 2 commit(s) into master: https://github.com/kubernetes/kubernetes/compare/d73a75b4b1dd...045a6dca0784"}} 114 115 createdWarningMessages := map[string][]string{ 116 "sig-contribex": {"*Warning:* tester (<@tester>) pushed a new branch (release-1.99): https://github.com/kubernetes/kubernetes/compare/045a6dca0784"}, 117 "kubernetes-foo": {"*Warning:* tester (<@tester>) pushed a new branch (release-1.99): https://github.com/kubernetes/kubernetes/compare/045a6dca0784"}} 118 119 deletedWarningMessages := map[string][]string{ 120 "sig-contribex": {"*Warning:* tester (<@tester>) deleted a branch (release-1.99): https://github.com/kubernetes/kubernetes/compare/d73a75b4b1dd...000000000000"}, 121 "kubernetes-foo": {"*Warning:* tester (<@tester>) deleted a branch (release-1.99): https://github.com/kubernetes/kubernetes/compare/d73a75b4b1dd...000000000000"}} 122 123 forcedWarningMessages := map[string][]string{ 124 "sig-contribex": {"*Warning:* tester (<@tester>) *force* merged 2 commit(s) into master: https://github.com/kubernetes/kubernetes/compare/d73a75b4b1dd...045a6dca0784"}, 125 "kubernetes-foo": {"*Warning:* tester (<@tester>) *force* merged 2 commit(s) into master: https://github.com/kubernetes/kubernetes/compare/d73a75b4b1dd...045a6dca0784"}} 126 127 type testCase struct { 128 name string 129 pushReq github.PushEvent 130 expectedMessages map[string][]string 131 } 132 133 testcases := []testCase{ 134 { 135 name: "If PR merged manually by a user, we send message to sig-contribex and kubernetes-foo.", 136 pushReq: pushEvManual, 137 expectedMessages: stdWarningMessages, 138 }, 139 { 140 name: "If PR force merged by a user, we send message to sig-contribex and kubernetes-foo with force merge message.", 141 pushReq: pushEvManualForced, 142 expectedMessages: forcedWarningMessages, 143 }, 144 { 145 name: "If PR merged by k8s merge bot we should NOT send message to sig-contribex and kubernetes-foo.", 146 pushReq: pushEv, 147 expectedMessages: noMessages, 148 }, 149 { 150 name: "If PR merged by a user not in the exemption list but in THIS branch exemption list, we should NOT send a message to sig-contribex and kubernetes-foo.", 151 pushReq: pushEvManualBranchExempted, 152 expectedMessages: noMessages, 153 }, 154 { 155 name: "If PR merged by a user not in the exemption list, in a branch exemption list, but not THIS branch exemption list, we should send a message to sig-contribex and kubernetes-foo.", 156 pushReq: pushEvManualBranchExempted, 157 expectedMessages: noMessages, 158 }, 159 { 160 name: "If a branch is created by a non-exempted user, we send message to sig-contribex and kubernetes-foo with branch created message.", 161 pushReq: pushEvManualCreated, 162 expectedMessages: createdWarningMessages, 163 }, 164 { 165 name: "If a branch is deleted by a non-exempted user, we send message to sig-contribex and kubernetes-foo with branch deleted message.", 166 pushReq: pushEvManualDeleted, 167 expectedMessages: deletedWarningMessages, 168 }, 169 } 170 171 pc := client{ 172 SlackConfig: plugins.Slack{ 173 MergeWarnings: []plugins.MergeWarning{ 174 { 175 Repos: []string{"kubernetes/kubernetes"}, 176 Channels: []string{"kubernetes-foo", "sig-contribex"}, 177 ExemptUsers: []string{"k8s-merge-robot"}, 178 ExemptBranches: map[string][]string{ 179 "warrens-branch": {"wteened"}, 180 }, 181 }, 182 }, 183 }, 184 SlackClient: slack.NewFakeClient(), 185 } 186 187 //should not fail if slackClient is nil 188 for _, tc := range testcases { 189 if err := notifyOnSlackIfManualMerge(pc, tc.pushReq); err != nil { 190 t.Fatalf("Didn't expect error if slack client is nil: %s", err) 191 } 192 } 193 194 //repeat the tests with a fake slack client 195 for _, tc := range testcases { 196 slackClient := &FakeClient{ 197 SentMessages: make(map[string][]string), 198 } 199 pc.SlackClient = slackClient 200 201 if err := notifyOnSlackIfManualMerge(pc, tc.pushReq); err != nil { 202 t.Fatalf("Didn't expect error: %s", err) 203 } 204 if len(tc.expectedMessages) != len(slackClient.SentMessages) { 205 t.Fatalf("Test: %s The number of messages sent do not tally. Expecting %d messages but received %d messages.", 206 tc.name, len(tc.expectedMessages), len(slackClient.SentMessages)) 207 } 208 for k, v := range tc.expectedMessages { 209 if _, ok := slackClient.SentMessages[k]; !ok { 210 t.Fatalf("Test: %s Messages is not sent to channel %s", tc.name, k) 211 } 212 if strings.Compare(v[0], slackClient.SentMessages[k][0]) != 0 { 213 t.Fatalf("Expecting message: %s\nReceived message: %s", v, slackClient.SentMessages[k]) 214 } 215 if len(v) != len(slackClient.SentMessages[k]) { 216 t.Fatalf("Test: %s All messages are not delivered to the channel ", tc.name) 217 } 218 } 219 } 220 221 } 222 223 // Make sure we are sending message to proper sig mentions 224 func TestComment(t *testing.T) { 225 orgMember := "cjwagner" 226 bot := "k8s-ci-robot" 227 type testCase struct { 228 name string 229 action github.GenericCommentEventAction 230 body string 231 expectedMessages map[string][]string 232 issueLabels []string 233 commenter string 234 } 235 testcases := []testCase{ 236 { 237 name: "If sig mentioned then we send a message to the sig with the body of the comment", 238 action: github.GenericCommentActionCreated, 239 body: "@kubernetes/sig-node-misc This issue needs update.", 240 expectedMessages: map[string][]string{"sig-node": {"This issue needs update."}}, 241 commenter: orgMember, 242 }, 243 { 244 name: "Don't sent message if comment isn't new.", 245 action: github.GenericCommentActionEdited, 246 body: "@kubernetes/sig-node-misc This issue needs update.", 247 expectedMessages: map[string][]string{}, 248 commenter: orgMember, 249 }, 250 { 251 name: "Don't sent message if commenter is the bot.", 252 action: github.GenericCommentActionEdited, 253 body: "@kubernetes/sig-node-misc This issue needs update.", 254 expectedMessages: map[string][]string{}, 255 commenter: bot, 256 }, 257 { 258 name: "If multiple sigs mentioned, we send a message to each sig with the body of the comment", 259 action: github.GenericCommentActionCreated, 260 body: "@kubernetes/sig-node-misc, @kubernetes/sig-api-machinery-misc Message sent to multiple sigs.", 261 expectedMessages: map[string][]string{"sig-api-machinery": {"Message sent to multiple sigs."}, "sig-node": {"Message sent to multiple sigs."}}, 262 commenter: orgMember, 263 }, 264 { 265 name: "If multiple sigs mentioned, but only one channel is allowed, only send to one channel.", 266 action: github.GenericCommentActionCreated, 267 body: "@kubernetes/sig-node-misc, @kubernetes/sig-testing-misc Message sent to multiple sigs.", 268 expectedMessages: map[string][]string{"sig-node": {"Message sent to multiple sigs."}}, 269 issueLabels: []string{}, 270 commenter: orgMember, 271 }, 272 { 273 name: "Message should not be sent if the pattern for the channel does not match", 274 action: github.GenericCommentActionCreated, 275 body: "@kubernetes/node-misc No message sent", 276 expectedMessages: map[string][]string{}, 277 commenter: orgMember, 278 }, 279 { 280 name: "Message sent only if the pattern for the channel match", 281 action: github.GenericCommentActionCreated, 282 body: "@kubernetes/node-misc @kubernetes/sig-api-machinery-bugs Message sent to matching sigs.", 283 expectedMessages: map[string][]string{"sig-api-machinery": {"Message sent to matching sigs."}}, 284 commenter: orgMember, 285 }, 286 } 287 288 for _, tc := range testcases { 289 fakeSlackClient := &FakeClient{ 290 SentMessages: make(map[string][]string), 291 } 292 client := client{ 293 GitHubClient: fakegithub.NewFakeClient(), 294 SlackClient: fakeSlackClient, 295 SlackConfig: plugins.Slack{MentionChannels: []string{"sig-node", "sig-api-machinery"}}, 296 } 297 e := github.GenericCommentEvent{ 298 Action: tc.action, 299 Body: tc.body, 300 User: github.User{Login: tc.commenter}, 301 } 302 303 if err := echoToSlack(client, e); err != nil { 304 t.Fatalf("For case %s, didn't expect error from label test: %v", tc.name, err) 305 } 306 if len(tc.expectedMessages) != len(fakeSlackClient.SentMessages) { 307 t.Fatalf("The number of messages sent do not tally. Expecting %d messages but received %d messages.", 308 len(tc.expectedMessages), len(fakeSlackClient.SentMessages)) 309 } 310 for k, v := range tc.expectedMessages { 311 if _, ok := fakeSlackClient.SentMessages[k]; !ok { 312 t.Fatalf("Messages is not sent to channel %s", k) 313 } 314 if len(v) != len(fakeSlackClient.SentMessages[k]) { 315 t.Fatalf("All messages are not delivered to the channel %s", k) 316 } 317 } 318 } 319 } 320 321 func TestHelpProvider(t *testing.T) { 322 enabledRepos := []config.OrgRepo{ 323 {Org: "org1", Repo: "repo"}, 324 {Org: "org2", Repo: "repo"}, 325 } 326 cases := []struct { 327 name string 328 config *plugins.Configuration 329 enabledRepos []config.OrgRepo 330 err bool 331 }{ 332 { 333 name: "Empty config", 334 config: &plugins.Configuration{}, 335 enabledRepos: enabledRepos, 336 }, 337 { 338 name: "All configs enabled", 339 config: &plugins.Configuration{ 340 Slack: plugins.Slack{ 341 MentionChannels: []string{"chan1", "chan2"}, 342 MergeWarnings: []plugins.MergeWarning{ 343 { 344 Repos: []string{"org2/repo"}, 345 Channels: []string{"chan1", "chan2"}, 346 ExemptUsers: []string{"k8s-merge-robot"}, 347 ExemptBranches: map[string][]string{ 348 "warrens-branch": {"wteened"}, 349 }, 350 }, 351 }, 352 }, 353 }, 354 enabledRepos: enabledRepos, 355 }, 356 } 357 for _, c := range cases { 358 t.Run(c.name, func(t *testing.T) { 359 _, err := helpProvider(c.config, c.enabledRepos) 360 if err != nil && !c.err { 361 t.Fatalf("helpProvider error: %v", err) 362 } 363 }) 364 } 365 }