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  }