in config/config.go [303:421]
func validateTestGroup(tg *configpb.TestGroup) error {
var mErr error
if tg == nil {
return multierror.Append(mErr, errors.New("got an empty TestGroup"))
}
// Check that required fields are a non-zero-value.
if tg.GetGcsPrefix() == "" && tg.GetResultSource() == nil {
mErr = multierror.Append(mErr, errors.New("require one of gcs_prefix or result_source"))
}
if tg.GetDaysOfResults() <= 0 {
mErr = multierror.Append(mErr, errors.New("days_of_results should be positive"))
}
if tg.GetNumColumnsRecent() <= 0 {
mErr = multierror.Append(mErr, errors.New("num_columns_recent should be positive"))
}
// Result source should be valid.
if err := validateResultStoreSource(tg); err != nil {
mErr = multierror.Append(mErr, fmt.Errorf("error in ResultStore result source: %v", err))
}
if err := validateGCSSource(tg); err != nil {
mErr = multierror.Append(mErr, fmt.Errorf("error in GCS result source: %v", err))
}
// Regexes should be valid.
if _, err := regexp.Compile(tg.GetTestMethodMatchRegex()); err != nil {
mErr = multierror.Append(mErr, fmt.Errorf("test_method_match_regex doesn't compile: %v", err))
}
// Email address for alerts should be valid.
if tg.GetAlertMailToAddresses() != "" {
if err := validateEmails(tg.GetAlertMailToAddresses()); err != nil {
mErr = multierror.Append(mErr, err)
}
}
// Test metadata options should be reasonable, valid values.
metadataOpts := tg.GetTestMetadataOptions()
for _, opt := range metadataOpts {
if opt.GetMessageRegex() == "" && opt.GetTestNameRegex() == "" {
mErr = multierror.Append(mErr, errors.New("at least one of message_regex or test_name_regex must be specified"))
}
if _, err := regexp.Compile(opt.GetMessageRegex()); err != nil {
mErr = multierror.Append(mErr, fmt.Errorf("message_regex doesn't compile: %v", err))
}
if _, err := regexp.Compile(opt.GetTestNameRegex()); err != nil {
mErr = multierror.Append(mErr, fmt.Errorf("test_name_regex doesn't compile: %v", err))
}
}
for _, notification := range tg.GetNotifications() {
if notification.GetSummary() == "" {
mErr = multierror.Append(mErr, errors.New("summary is required"))
}
}
annotations := tg.GetTestAnnotations()
for _, annotation := range annotations {
if annotation.GetPropertyName() == "" {
mErr = multierror.Append(mErr, errors.New("property_name is required"))
}
if annotation.GetShortText() == "" || utf8.RuneCountInString(annotation.GetShortText()) > 5 {
mErr = multierror.Append(mErr, errors.New("short_text must be 1-5 characters long"))
}
}
fallbackConfigSettingSet := tg.GetFallbackGrouping() == configpb.TestGroup_FALLBACK_GROUPING_CONFIGURATION_VALUE
fallbackConfigValueSet := tg.GetFallbackGroupingConfigurationValue() != ""
if fallbackConfigSettingSet != fallbackConfigValueSet {
mErr = multierror.Append(
mErr,
errors.New("fallback_grouping_configuration_value and fallback_grouping = FALLBACK_GROUPING_CONFIGURATION_VALUE require each other"),
)
}
// For each defined column_header, verify it has exactly one value set.
for idx, header := range tg.GetColumnHeader() {
if cv, p, l := header.ConfigurationValue, header.Property, header.Label; cv == "" && p == "" && l == "" {
mErr = multierror.Append(mErr, &ValidationError{tg.GetName(), "TestGroup", fmt.Sprintf("Column Header %d is empty", idx)})
} else if cv != "" && (p != "" || l != "") || p != "" && (cv != "" || l != "") {
mErr = multierror.Append(
mErr,
fmt.Errorf("Column Header %d must only set one value, got configuration_value: %q, property: %q, label: %q", idx, cv, p, l),
)
}
}
// test_name_config should have a matching number of format strings and name elements.
if tg.GetTestNameConfig() != nil {
nameFormat := tg.GetTestNameConfig().GetNameFormat()
nameElements := tg.GetTestNameConfig().GetNameElements()
if len(nameElements) == 0 {
mErr = multierror.Append(mErr, errors.New("TestNameConfig.NameElements must be specified"))
}
if nameFormat == "" {
mErr = multierror.Append(mErr, errors.New("TestNameConfig.NameFormat must be specified"))
} else {
if got, want := len(nameElements), strings.Count(nameFormat, "%"); got != want {
mErr = multierror.Append(
mErr,
fmt.Errorf("TestNameConfig has %d elements, format %s wants %d", got, nameFormat, want),
)
}
elements := make([]interface{}, 0)
for range nameElements {
elements = append(elements, "")
}
s := fmt.Sprintf(nameFormat, elements...)
if strings.Contains(s, "%!") {
return fmt.Errorf("number of format strings and name_elements must match; got %s (%d)", s, len(elements))
}
}
}
return mErr
}