github.com/shashidharatd/test-infra@v0.0.0-20171006011030-71304e1ca560/testgrid/config/config_test.go (about) 1 /* 2 Copyright 2016 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 main 18 19 import ( 20 "io/ioutil" 21 "strings" 22 "testing" 23 24 "gopkg.in/yaml.v2" 25 "k8s.io/test-infra/testgrid/config/yaml2proto" 26 ) 27 28 type SQConfig struct { 29 Data map[string]string `yaml:"data,omitempty"` 30 } 31 32 func TestConfig(t *testing.T) { 33 yamlData, err := ioutil.ReadFile("config.yaml") 34 if err != nil { 35 t.Errorf("IO Error : Cannot Open File config.yaml") 36 } 37 38 c := yaml2proto.Config{} 39 if err := c.Update(yamlData); err != nil { 40 t.Errorf("Yaml2Proto - Conversion Error %v", err) 41 } 42 43 config, err := c.Raw() 44 if err != nil { 45 t.Errorf("Error validating config: %v", err) 46 } 47 48 // Validate config.yaml - 49 50 // testgroup - occurrence map, validate testgroups 51 testgroupMap := make(map[string]int32) 52 53 for testgroupidx, testgroup := range config.TestGroups { 54 // All testgroup must have a name and a query 55 if testgroup.Name == "" || testgroup.GcsPrefix == "" { 56 t.Errorf("Testgroup %v: - Must have a name and query", testgroupidx) 57 } 58 59 // All testgroup must not have duplicated names 60 if testgroupMap[testgroup.Name] > 0 { 61 t.Errorf("Duplicated Testgroup: %v", testgroup.Name) 62 } else { 63 testgroupMap[testgroup.Name] = 1 64 } 65 66 if !testgroup.IsExternal { 67 t.Errorf("Testgroup %v: IsExternal should always be true!", testgroup.Name) 68 } 69 if !testgroup.UseKubernetesClient { 70 t.Errorf("Testgroup %v: UseKubernetesClient should always be true!", testgroup.Name) 71 } 72 73 // All testgroup from kubernetes must have testgroup name match its bucket name 74 if strings.HasPrefix(testgroup.GcsPrefix, "kubernetes-jenkins/logs/") { 75 if strings.TrimPrefix(testgroup.GcsPrefix, "kubernetes-jenkins/logs/") != testgroup.Name { 76 t.Errorf("Kubernetes Testgroup %v, name does not match GCS Bucket %v", testgroup.Name, testgroup.GcsPrefix) 77 } 78 } 79 80 if testgroup.TestNameConfig != nil { 81 if testgroup.TestNameConfig.NameFormat == "" { 82 t.Errorf("Testgroup %v: NameFormat must not be empty!", testgroup.Name) 83 } 84 85 if len(testgroup.TestNameConfig.NameElements) != strings.Count(testgroup.TestNameConfig.NameFormat, "%") { 86 t.Errorf("Testgroup %v: TestNameConfig must have number NameElement equal to format count in NameFormat!", testgroup.Name) 87 } 88 } 89 90 // All PR testgroup has num_recent_column equals 20 91 if strings.HasPrefix(testgroup.GcsPrefix, "kubernetes-jenkins/pr-logs/directory/") { 92 if testgroup.NumColumnsRecent < 20 { 93 t.Errorf("Testgroup %v: num_recent_column must be greater than 20 for presubmit jobs!", testgroup.Name) 94 } 95 } 96 } 97 98 // dashboard name set 99 dashboardmap := make(map[string]bool) 100 101 for dashboardidx, dashboard := range config.Dashboards { 102 // All dashboard must have a name 103 if dashboard.Name == "" { 104 t.Errorf("Dashboard %v: - Must have a name", dashboardidx) 105 } 106 107 // All dashboard must not have duplicated names 108 if dashboardmap[dashboard.Name] { 109 t.Errorf("Duplicated dashboard: %v", dashboard.Name) 110 } else { 111 dashboardmap[dashboard.Name] = true 112 } 113 114 // All dashboard must have at least one tab 115 if len(dashboard.DashboardTab) == 0 { 116 t.Errorf("Dashboard %v: - Must have more than one dashboardtab", dashboard.Name) 117 } 118 119 // dashboardtab name set, to check duplicated tabs within each dashboard 120 dashboardtabmap := make(map[string]bool) 121 122 // All notifications in dashboard must have a summary 123 if len(dashboard.Notifications) != 0 { 124 for notificationindex, notification := range dashboard.Notifications { 125 if notification.Summary == "" { 126 t.Errorf("Notification %v in dashboard %v: - Must have a summary", notificationindex, dashboard.Name) 127 } 128 } 129 } 130 131 for tabindex, dashboardtab := range dashboard.DashboardTab { 132 133 // All dashboardtab must have a name and a testgroup 134 if dashboardtab.Name == "" || dashboardtab.TestGroupName == "" { 135 t.Errorf("Dashboard %v, tab %v: - Must have a name and a testgroup name", dashboard.Name, tabindex) 136 } 137 138 // All dashboardtab within a dashboard must not have duplicated names 139 if dashboardtabmap[dashboardtab.Name] { 140 t.Errorf("Duplicated dashboardtab: %v", dashboardtab.Name) 141 } else { 142 dashboardtabmap[dashboardtab.Name] = true 143 } 144 145 // All testgroup in dashboard must be defined in testgroups 146 if testgroupMap[dashboardtab.TestGroupName] == 0 { 147 t.Errorf("Dashboard %v, tab %v: - Testgroup %v must be defined first", 148 dashboard.Name, dashboardtab.Name, dashboardtab.TestGroupName) 149 } else { 150 testgroupMap[dashboardtab.TestGroupName] += 1 151 } 152 153 if dashboardtab.AlertOptions != nil && (dashboardtab.AlertOptions.AlertStaleResultsHours != 0 || dashboardtab.AlertOptions.NumFailuresToAlert != 0) { 154 for _, testgroup := range config.TestGroups { 155 // Disallow alert options in tab but not group. 156 // Disallow different alert options in tab vs. group. 157 if testgroup.Name == dashboardtab.TestGroupName { 158 if testgroup.AlertStaleResultsHours == 0 { 159 t.Errorf("Cannot define alert_stale_results_hours in DashboardTab %v and not TestGroup %v.", dashboardtab.Name, dashboardtab.TestGroupName) 160 } 161 if testgroup.NumFailuresToAlert == 0 { 162 t.Errorf("Cannot define num_failures_to_alert in DashboardTab %v and not TestGroup %v.", dashboardtab.Name, dashboardtab.TestGroupName) 163 } 164 if testgroup.AlertStaleResultsHours != dashboardtab.AlertOptions.AlertStaleResultsHours { 165 t.Errorf("alert_stale_results_hours for DashboardTab %v must match TestGroup %v.", dashboardtab.Name, dashboardtab.TestGroupName) 166 } 167 if testgroup.NumFailuresToAlert != dashboardtab.AlertOptions.NumFailuresToAlert { 168 t.Errorf("num_failures_to_alert for DashboardTab %v must match TestGroup %v.", dashboardtab.Name, dashboardtab.TestGroupName) 169 } 170 } 171 } 172 } 173 } 174 } 175 176 // No dup of dashboard groups, and no dup dashboard in a dashboard group 177 groups := make(map[string]bool) 178 tabs := make(map[string]string) 179 180 for idx, dashboardGroup := range config.DashboardGroups { 181 // All dashboard must have a name 182 if dashboardGroup.Name == "" { 183 t.Errorf("DashboardGroup %v: - DashboardGroup must have a name", idx) 184 } 185 186 // All dashboardgroup must not have duplicated names 187 if _, ok := groups[dashboardGroup.Name]; ok { 188 t.Errorf("Duplicated dashboard: %v", dashboardGroup.Name) 189 } else { 190 groups[dashboardGroup.Name] = true 191 } 192 193 for _, dashboard := range dashboardGroup.DashboardNames { 194 // All dashboard must not have duplicated names 195 if exist, ok := tabs[dashboard]; ok { 196 t.Errorf("Duplicated dashboard %v in dashboard group %v and %v", dashboard, exist, dashboardGroup.Name) 197 } else { 198 tabs[dashboard] = dashboardGroup.Name 199 } 200 201 if _, ok := dashboardmap[dashboard]; !ok { 202 t.Errorf("Dashboard %v needs to be defined before adding to a dashboard group!", dashboard) 203 } 204 } 205 } 206 207 // All Testgroup should be mapped to one or more tabs 208 for testgroupname, occurrence := range testgroupMap { 209 if occurrence == 1 { 210 t.Errorf("Testgroup %v - defined but not used in any dashboards", testgroupname) 211 } 212 } 213 214 // make sure items in sq-blocking dashboard matches sq configmap 215 sqJobPool := []string{} 216 for _, d := range config.Dashboards { 217 if d.Name != "sq-blocking" { 218 continue 219 } 220 221 for _, tab := range d.DashboardTab { 222 for _, t := range config.TestGroups { 223 if t.Name == tab.TestGroupName { 224 job := strings.TrimPrefix(t.GcsPrefix, "kubernetes-jenkins/logs/") 225 sqJobPool = append(sqJobPool, job) 226 break 227 } 228 } 229 } 230 } 231 232 sqConfigPath := "../../mungegithub/submit-queue/deployment/kubernetes/configmap.yaml" 233 configData, err := ioutil.ReadFile(sqConfigPath) 234 if err != nil { 235 t.Errorf("Read Buffer Error for SQ Data : %v", err) 236 } 237 238 sqData := &SQConfig{} 239 err = yaml.Unmarshal([]byte(configData), &sqData) 240 if err != nil { 241 t.Errorf("Unmarshal Error for SQ Data : %v", err) 242 } 243 244 for _, testgridJob := range sqJobPool { 245 t.Errorf("Err : testgrid job %v not found in SQ config", testgridJob) 246 } 247 248 sqNonBlockingJobs := strings.Split(sqData.Data["nonblocking-jobs"], ",") 249 for _, sqJob := range sqNonBlockingJobs { 250 if sqJob == "" { // ignore empty list of jobs 251 continue 252 } 253 found := false 254 for _, testgroup := range config.TestGroups { 255 if testgroup.Name == sqJob { 256 found = true 257 break 258 } 259 } 260 261 if !found { 262 t.Errorf("Err : %v not found in testgrid config", sqJob) 263 } 264 } 265 }