func validateTestGroup()

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
}