github.com/abayer/test-infra@v0.0.5/robots/issue-creator/sources/flakyjob-reporter_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 sources 18 19 import ( 20 "testing" 21 "time" 22 23 "k8s.io/test-infra/robots/issue-creator/creator" 24 25 githubapi "github.com/google/go-github/github" 26 ) 27 28 var ( 29 sampleFlakyJobJSON = []byte(` 30 { 31 "ci-kubernetes-e2e-non-cri-gce-etcd3": { 32 "consistency": 0.863, 33 "flakes": 43, 34 "flakiest": { 35 "[k8s.io] Volumes [Volume] [k8s.io] PD should be mountable": 24, 36 "[k8s.io] Services should preserve source pod IP for traffic thru service cluster IP": 7 37 } 38 }, 39 "pr:pull-kubernetes-e2e-gce-non-cri": { 40 "consistency": 0.929, 41 "flakes": 62, 42 "flakiest": { 43 "[k8s.io] Volumes [Volume] [k8s.io] PD should be mountable": 28 44 } 45 }, 46 "ci-kubernetes-e2e-non-cri-gce": { 47 "consistency": 0.864, 48 "flakes": 42, 49 "flakiest": { 50 "[k8s.io] Volumes [Volume] [k8s.io] PD should be mountable": 24, 51 "[k8s.io] Services should preserve source pod IP for traffic thru service cluster IP": 10 52 } 53 }, 54 "ci-kubernetes-e2e-gce-container-vm": { 55 "consistency": 0.863, 56 "flakes": 42, 57 "flakiest": { 58 "[k8s.io] Volumes [Volume] [k8s.io] PD should be mountable": 10, 59 "[k8s.io] Services should preserve source pod IP for traffic thru service cluster IP": 8 60 } 61 }, 62 "ci-kubernetes-e2e-non-cri-gce-proto": { 63 "consistency": 0.865, 64 "flakes": 41, 65 "flakiest": { 66 "[k8s.io] Volumes [Volume] [k8s.io] PD should be mountable": 22 67 } 68 }, 69 "ci-kubernetes-e2e-gce-gci-ci-master": { 70 "consistency": 0.868, 71 "flakes": 41, 72 "flakiest": { 73 "[k8s.io] Volumes [Volume] [k8s.io] PD should be mountable": 16, 74 "[k8s.io] Services should preserve source pod IP for traffic thru service cluster IP": 8 75 } 76 } 77 }`) 78 ) 79 80 func TestFJParseFlakyJobs(t *testing.T) { 81 reporter := &FlakyJobReporter{creator: &creator.IssueCreator{}} 82 jobs, err := reporter.parseFlakyJobs(sampleFlakyJobJSON) 83 if err != nil { 84 t.Fatalf("Error parsing flaky jobs: %v\n", err) 85 } 86 87 if len(jobs) != 6 { 88 t.Fatalf("ParseFlakyJobs parsed the wrong number of jobs. Expected 6, got %d.\n", len(jobs)) 89 } 90 91 if !checkFlakyJobsSorted(jobs) { 92 t.Fatal("The slice of *FlakyJob that was returned by parseFlakyJobs was not sorted.\n") 93 } 94 if jobs[0].Name != "pr:pull-kubernetes-e2e-gce-non-cri" { 95 t.Fatalf("The name of the top flaking job should be 'pr:pull-kubernetes-e2e-gce-non-cri' but is '%s'\n", jobs[0].Name) 96 } 97 if *jobs[0].Consistency != 0.929 { 98 t.Fatalf("The consistency of the top flaking job should be 0.926 but is '%v'\n", *jobs[0].Consistency) 99 } 100 if *jobs[0].FlakeCount != 62 { 101 t.Fatalf("The flake count of the top flaking job should be 63 but is '%d'\n", *jobs[0].FlakeCount) 102 } 103 if len(jobs[0].FlakyTests) != 1 || jobs[0].FlakyTests["[k8s.io] Volumes [Volume] [k8s.io] PD should be mountable"] != 28 { 104 t.Fatal("The dictionary of flaky tests for the top flaking job is invalid.\n") 105 } 106 for _, job := range jobs { 107 if job.reporter == nil { 108 t.Errorf("FlakyJob with name: '%s' does not have reporter set.\n", job.Name) 109 } 110 } 111 } 112 113 // TestFJPrevCloseInWindow checks that FlakyJob issues will abort issue creation by returning an 114 // empty body if there is a closed issue for the same flaky job that was closed in the past week. 115 func TestFJPrevCloseInWindow(t *testing.T) { 116 reporter := &FlakyJobReporter{creator: &creator.IssueCreator{}} 117 fjs, err := reporter.parseFlakyJobs(sampleFlakyJobJSON) 118 if err != nil { 119 t.Fatalf("Error parsing flaky jobs: %v\n", err) 120 } 121 122 lastWeek := time.Now().AddDate(0, 0, -8) 123 yesterday := time.Now().AddDate(0, 0, -1) 124 num := 1 125 // Only need to populate the ClosedAt and Number fields of the Issue. 126 prevIssues := []*githubapi.Issue{{ClosedAt: &yesterday, Number: &num}} 127 if fjs[0].Body(prevIssues) != "" { 128 t.Errorf("FlakyJob returned an issue body when there was a recently closed issue for the job.") 129 } 130 131 prevIssues = []*githubapi.Issue{{ClosedAt: &lastWeek, Number: &num}} 132 if fjs[0].Body(prevIssues) == "" { 133 t.Errorf("FlakyJob returned an empty issue body when it should have returned a valid body.") 134 } 135 } 136 137 func checkFlakyJobsSorted(jobs []*FlakyJob) bool { 138 for i := 1; i < len(jobs); i++ { 139 if *jobs[i-1].FlakeCount < *jobs[i].FlakeCount { 140 return false 141 } 142 } 143 return true 144 }