github.com/abayer/test-infra@v0.0.5/prow/report/report_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 report 18 19 import ( 20 "fmt" 21 "strings" 22 "testing" 23 24 "k8s.io/test-infra/prow/github" 25 "k8s.io/test-infra/prow/kube" 26 ) 27 28 func TestParseIssueComment(t *testing.T) { 29 var testcases = []struct { 30 name string 31 context string 32 state string 33 ics []github.IssueComment 34 expectedDeletes []int 35 expectedContexts []string 36 expectedUpdate int 37 }{ 38 { 39 name: "should delete old style comments", 40 context: "Jenkins foo test", 41 state: github.StatusSuccess, 42 ics: []github.IssueComment{ 43 { 44 User: github.User{Login: "k8s-ci-robot"}, 45 Body: "Jenkins foo test **failed** for such-and-such.", 46 ID: 12345, 47 }, 48 { 49 User: github.User{Login: "someone-else"}, 50 Body: "Jenkins foo test **failed**!? Why?", 51 ID: 12356, 52 }, 53 { 54 User: github.User{Login: "k8s-ci-robot"}, 55 Body: "Jenkins foo test **failed** for so-and-so.", 56 ID: 12367, 57 }, 58 { 59 User: github.User{Login: "k8s-ci-robot"}, 60 Body: "Jenkins bar test **failed** for something-or-other.", 61 ID: 12378, 62 }, 63 }, 64 expectedDeletes: []int{12345, 12367}, 65 }, 66 { 67 name: "should create a new comment", 68 context: "bla test", 69 state: github.StatusFailure, 70 expectedContexts: []string{"bla test"}, 71 }, 72 { 73 name: "should not delete an up-to-date comment", 74 context: "bla test", 75 state: github.StatusSuccess, 76 ics: []github.IssueComment{ 77 { 78 User: github.User{Login: "k8s-ci-robot"}, 79 Body: "--- | --- | ---\nfoo test | something | or other\n\n", 80 }, 81 }, 82 }, 83 { 84 name: "should delete when all tests pass", 85 context: "bla test", 86 state: github.StatusSuccess, 87 ics: []github.IssueComment{ 88 { 89 User: github.User{Login: "k8s-ci-robot"}, 90 Body: "--- | --- | ---\nbla test | something | or other\n\n" + commentTag, 91 ID: 123, 92 }, 93 }, 94 expectedDeletes: []int{123}, 95 expectedContexts: []string{}, 96 }, 97 { 98 name: "should delete a passing test with \\r", 99 context: "bla test", 100 state: github.StatusSuccess, 101 ics: []github.IssueComment{ 102 { 103 User: github.User{Login: "k8s-ci-robot"}, 104 Body: "--- | --- | ---\r\nbla test | something | or other\r\n\r\n" + commentTag, 105 ID: 123, 106 }, 107 }, 108 expectedDeletes: []int{123}, 109 expectedContexts: []string{}, 110 }, 111 112 { 113 name: "should update a failed test", 114 context: "bla test", 115 state: github.StatusFailure, 116 ics: []github.IssueComment{ 117 { 118 User: github.User{Login: "k8s-ci-robot"}, 119 Body: "--- | --- | ---\nbla test | something | or other\n\n" + commentTag, 120 ID: 123, 121 }, 122 }, 123 expectedDeletes: []int{123}, 124 expectedContexts: []string{"bla test"}, 125 }, 126 { 127 name: "should preserve old results when updating", 128 context: "bla test", 129 state: github.StatusFailure, 130 ics: []github.IssueComment{ 131 { 132 User: github.User{Login: "k8s-ci-robot"}, 133 Body: "--- | --- | ---\nbla test | something | or other\nfoo test | wow | aye\n\n" + commentTag, 134 ID: 123, 135 }, 136 }, 137 expectedDeletes: []int{123}, 138 expectedContexts: []string{"bla test", "foo test"}, 139 }, 140 { 141 name: "should merge duplicates", 142 context: "bla test", 143 state: github.StatusFailure, 144 ics: []github.IssueComment{ 145 { 146 User: github.User{Login: "k8s-ci-robot"}, 147 Body: "--- | --- | ---\nbla test | something | or other\nfoo test | wow such\n\n" + commentTag, 148 ID: 123, 149 }, 150 { 151 User: github.User{Login: "k8s-ci-robot"}, 152 Body: "--- | --- | ---\nfoo test | beep | boop\n\n" + commentTag, 153 ID: 124, 154 }, 155 }, 156 expectedDeletes: []int{123, 124}, 157 expectedContexts: []string{"bla test", "foo test"}, 158 }, 159 { 160 name: "should update an old comment when a test passes", 161 context: "bla test", 162 state: github.StatusSuccess, 163 ics: []github.IssueComment{ 164 { 165 User: github.User{Login: "k8s-ci-robot"}, 166 Body: "--- | --- | ---\nbla test | something | or other\nfoo test | wow | aye\n\n" + commentTag, 167 ID: 123, 168 }, 169 }, 170 expectedDeletes: []int{}, 171 expectedContexts: []string{"foo test"}, 172 expectedUpdate: 123, 173 }, 174 } 175 for _, tc := range testcases { 176 pj := kube.ProwJob{ 177 Spec: kube.ProwJobSpec{ 178 Context: tc.context, 179 Refs: &kube.Refs{Pulls: []kube.Pull{{}}}, 180 }, 181 Status: kube.ProwJobStatus{ 182 State: kube.ProwJobState(tc.state), 183 }, 184 } 185 deletes, entries, update := parseIssueComments(pj, "k8s-ci-robot", tc.ics) 186 if len(deletes) != len(tc.expectedDeletes) { 187 t.Errorf("It %s: wrong number of deletes. Got %v, expected %v", tc.name, deletes, tc.expectedDeletes) 188 } else { 189 for _, edel := range tc.expectedDeletes { 190 found := false 191 for _, del := range deletes { 192 if del == edel { 193 found = true 194 break 195 } 196 } 197 if !found { 198 t.Errorf("It %s: expected to find %d in %v", tc.name, edel, deletes) 199 } 200 } 201 } 202 if len(entries) != len(tc.expectedContexts) { 203 t.Errorf("It %s: wrong number of entries. Got %v, expected %v", tc.name, entries, tc.expectedContexts) 204 } else { 205 for _, econt := range tc.expectedContexts { 206 found := false 207 for _, ent := range entries { 208 if strings.Contains(ent, econt) { 209 found = true 210 break 211 } 212 } 213 if !found { 214 t.Errorf("It %s: expected to find %s in %v", tc.name, econt, entries) 215 } 216 } 217 } 218 if tc.expectedUpdate != update { 219 t.Errorf("It %s: expected update %d, got %d", tc.name, tc.expectedUpdate, update) 220 } 221 } 222 } 223 224 type fakeGhClient struct { 225 status []github.Status 226 } 227 228 func (gh fakeGhClient) BotName() (string, error) { 229 return "BotName", nil 230 } 231 func (gh *fakeGhClient) CreateStatus(org, repo, ref string, s github.Status) error { 232 gh.status = append(gh.status, s) 233 return nil 234 235 } 236 func (gh fakeGhClient) ListIssueComments(org, repo string, number int) ([]github.IssueComment, error) { 237 return nil, nil 238 } 239 func (gh fakeGhClient) CreateComment(org, repo string, number int, comment string) error { 240 return nil 241 } 242 func (gh fakeGhClient) DeleteComment(org, repo string, ID int) error { 243 return nil 244 } 245 func (gh fakeGhClient) EditComment(org, repo string, ID int, comment string) error { 246 return nil 247 } 248 249 func createChildren(pj *kube.ProwJobSpec, d int) { 250 for i := 0; i < d; i++ { 251 npj := &kube.ProwJobSpec{ 252 // TODO: Support testing this via defining expected behavior in TestReportStatus 253 Type: kube.PresubmitJob, 254 Report: true, 255 Context: fmt.Sprintf("%s/child_%d", pj.Context, i), 256 Refs: &kube.Refs{ 257 Org: "k8s", 258 Repo: "test-infra", 259 Pulls: []kube.Pull{{ 260 Author: "me", 261 Number: 1, 262 SHA: "abcdef", 263 }}, 264 }, 265 } 266 pj.RunAfterSuccess = append(pj.RunAfterSuccess, *npj) 267 } 268 } 269 270 func TestReportStatus(t *testing.T) { 271 tests := []struct { 272 name string 273 274 // TODO: This should be the RunAfterSuccess spec and not a single int. 275 children int 276 state kube.ProwJobState 277 report bool 278 279 expectedStatuses []string 280 }{ 281 { 282 name: "successful_job-report_true", 283 284 children: 3, 285 state: kube.SuccessState, 286 report: true, 287 288 expectedStatuses: []string{"success"}, 289 }, 290 { 291 name: "successful_job-report_false", 292 293 children: 3, 294 state: kube.SuccessState, 295 report: false, 296 297 expectedStatuses: []string{}, 298 }, 299 { 300 name: "pending_job-report_true", 301 302 children: 3, 303 state: kube.PendingState, 304 report: true, 305 306 expectedStatuses: []string{"pending", "pending", "pending", "pending"}, 307 }, 308 { 309 name: "pending_job-report_false", 310 311 children: 3, 312 state: kube.PendingState, 313 report: false, 314 315 expectedStatuses: []string{"pending", "pending", "pending"}, 316 }, 317 { 318 name: "aborted_job-report_true", 319 320 state: kube.AbortedState, 321 report: true, 322 323 expectedStatuses: []string{"failure"}, 324 }, 325 } 326 327 createPJ := func(state kube.ProwJobState, report bool, children int) kube.ProwJob { 328 pj := kube.ProwJob{ 329 Status: kube.ProwJobStatus{ 330 State: state, 331 Description: "message", 332 URL: "http://mytest.com", 333 }, 334 Spec: kube.ProwJobSpec{ 335 Job: "job-name", 336 Type: kube.PresubmitJob, 337 Context: "parent", 338 Report: report, 339 Refs: &kube.Refs{ 340 Org: "k8s", 341 Repo: "test-infra", 342 Pulls: []kube.Pull{{ 343 Author: "me", 344 Number: 1, 345 SHA: "abcdef", 346 }}, 347 }, 348 }, 349 } 350 createChildren(&pj.Spec, children) 351 return pj 352 } 353 for _, tc := range tests { 354 t.Logf("Running scenario %q", tc.name) 355 // Setup 356 ghc := &fakeGhClient{} 357 pj := createPJ(tc.state, tc.report, tc.children) 358 // Run 359 if err := reportStatus(ghc, pj, "Parent Status Changed"); err != nil { 360 t.Error(err) 361 } 362 // Check 363 if len(ghc.status) != len(tc.expectedStatuses) { 364 t.Errorf("expected %d status(es), found %d", len(tc.expectedStatuses), len(ghc.status)) 365 continue 366 } 367 for i, status := range ghc.status { 368 if status.State != tc.expectedStatuses[i] { 369 t.Errorf("unexpected status: %s, expected: %s", status.State, tc.expectedStatuses[i]) 370 } 371 } 372 } 373 }