blob: dcbec6f99a453e8bb961f674dc6bfa7125bfe9cf [file] [log] [blame]
package config_validator
import (
"config"
"config_parser"
"fmt"
"testing"
"time"
"github.com/google/go-cmp/cmp"
)
func TestEmptyValidationErrors(t *testing.T) {
if newValidationErrors("err").err() != nil {
t.Errorf("Empty validation errors .err() should return nil")
}
}
func TestSingleValidationErrors(t *testing.T) {
errs := newValidationErrors("err")
errs.addError("an", fmt.Errorf("error"))
expectedError := "err `an`: error"
if diff := cmp.Diff(errs.err().Error(), expectedError); diff != "" {
t.Errorf("Output error does not match expected error: %s", diff)
}
}
func TestMultipleValidationErrors(t *testing.T) {
errs := newValidationErrors("err")
errs.addError("an", fmt.Errorf("error"))
errs.addError("another", fmt.Errorf("error"))
expectedError := "err `an`: error\nerr `another`: error"
if diff := cmp.Diff(errs.err().Error(), expectedError); diff != "" {
t.Errorf("Output error does not match expected error: %s", diff)
}
}
func TestNestedValidationErrors(t *testing.T) {
innerErr := newValidationErrors("inner")
innerErr.addError("an", fmt.Errorf("error"))
errs := newValidationErrors("err")
errs.addError("nested", innerErr.err())
expectedError := "err `nested`:\n inner `an`: error"
if diff := cmp.Diff(errs.err().Error(), expectedError); diff != "" {
t.Errorf("Output error does not match expected error: %s", diff)
}
}
func TestMultipleNestedValidationErrors(t *testing.T) {
innerErr := newValidationErrors("inner")
innerErr.addError("an", fmt.Errorf("error"))
errs := newValidationErrors("err")
errs.addError("nested2", innerErr.err())
errs.addError("nested1", innerErr.err())
expectedError := "err `nested1`:\n inner `an`: error\nerr `nested2`:\n inner `an`: error"
if diff := cmp.Diff(errs.err().Error(), expectedError); diff != "" {
t.Errorf("Output error does not match expected error: %s", diff)
}
}
func TestMultipleErrorsForLevel(t *testing.T) {
errs := newValidationErrors("err")
errs.addError("an", fmt.Errorf("error"))
errs.addError("an", fmt.Errorf("error"))
expectedError := "err `an`:\n error\n error"
if diff := cmp.Diff(errs.err().Error(), expectedError); diff != "" {
t.Errorf("Output error does not match expected error: %s", diff)
}
}
func TestValidateProjectConfigDatasWithDeletedCustomerIds(t *testing.T) {
projectConfigFile := config.ProjectConfigFile{
MetricDefinitions: []*config.MetricDefinition{
{
CustomerId: 5,
ProjectId: 3,
MetricName: "the_metric_name",
Id: 1,
TimeZonePolicy: config.MetricDefinition_UTC,
MetricSemantics: []config.MetricSemantics{
config.MetricSemantics_METRIC_SEMANTICS_UNSPECIFIED,
},
MetricType: config.MetricDefinition_OCCURRENCE,
Reports: []*config.ReportDefinition{
{
ReportName: "the_report",
Id: 10,
ReportType: config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS,
PrivacyLevel: config.ReportDefinition_NO_ADDED_PRIVACY,
PrivacyMechanism: config.ReportDefinition_DE_IDENTIFICATION,
SystemProfileSelection: config.SystemProfileSelectionPolicy_REPORT_ALL,
},
{
ReportName: "the_other_report",
Id: 20,
ReportType: config.ReportDefinition_HOURLY_VALUE_NUMERIC_STATS,
PrivacyLevel: config.ReportDefinition_NO_ADDED_PRIVACY,
PrivacyMechanism: config.ReportDefinition_DE_IDENTIFICATION,
SystemProfileSelection: config.SystemProfileSelectionPolicy_REPORT_ALL,
},
},
MetaData: &config.MetricDefinition_Metadata{
ExpirationDate: time.Now().AddDate(1, 0, 0).Format(dateFormat),
MaxReleaseStage: config.ReleaseStage_DEBUG,
},
},
},
}
configs := []config_parser.ProjectConfigData{
{
CustomerName: "customer5",
CustomerId: 5,
ProjectName: "project3",
ProjectId: 3,
Contact: "project3@customer5.com",
ProjectConfigFile: &projectConfigFile,
},
{
CustomerName: "customer5",
CustomerId: 5,
ProjectName: "project4",
ProjectId: 4,
Contact: "project4@customer5.com",
ProjectConfigFile: &projectConfigFile,
},
{
CustomerId: 1,
IsDeletedCustomer: true,
},
{
CustomerId: 2,
IsDeletedCustomer: true,
},
}
err := ValidateProjectConfigDatas(configs)
if err != nil {
t.Errorf("Validation incorrectly rejected deleted customer IDs: %v", err)
}
}
func TestValidateProjectConfigDatasWithReusedDeletedCustomerIds(t *testing.T) {
projectConfigFile := config.ProjectConfigFile{
MetricDefinitions: []*config.MetricDefinition{
{
CustomerId: 5,
ProjectId: 3,
MetricName: "the_metric_name",
Id: 1,
TimeZonePolicy: config.MetricDefinition_UTC,
MetricSemantics: []config.MetricSemantics{
config.MetricSemantics_METRIC_SEMANTICS_UNSPECIFIED,
},
MetricType: config.MetricDefinition_OCCURRENCE,
Reports: []*config.ReportDefinition{
{
ReportName: "the_report",
Id: 10,
ReportType: config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS,
PrivacyLevel: config.ReportDefinition_NO_ADDED_PRIVACY,
PrivacyMechanism: config.ReportDefinition_DE_IDENTIFICATION,
SystemProfileSelection: config.SystemProfileSelectionPolicy_REPORT_ALL,
},
{
ReportName: "the_other_report",
Id: 20,
ReportType: config.ReportDefinition_HOURLY_VALUE_NUMERIC_STATS,
PrivacyLevel: config.ReportDefinition_NO_ADDED_PRIVACY,
PrivacyMechanism: config.ReportDefinition_DE_IDENTIFICATION,
SystemProfileSelection: config.SystemProfileSelectionPolicy_REPORT_ALL,
},
},
MetaData: &config.MetricDefinition_Metadata{
ExpirationDate: time.Now().AddDate(1, 0, 0).Format(dateFormat),
MaxReleaseStage: config.ReleaseStage_DEBUG,
},
},
},
}
configs := []config_parser.ProjectConfigData{
{
CustomerName: "customer5",
CustomerId: 5,
ProjectName: "project3",
ProjectId: 3,
Contact: "project3@customer5.com",
ProjectConfigFile: &projectConfigFile,
},
{
CustomerName: "customer5",
CustomerId: 5,
ProjectName: "project4",
ProjectId: 4,
Contact: "project4@customer5.com",
ProjectConfigFile: &projectConfigFile,
},
{
CustomerId: 1,
IsDeletedCustomer: true,
},
{
CustomerId: 5,
IsDeletedCustomer: true,
},
}
err := ValidateProjectConfigDatas(configs)
if err == nil {
t.Errorf("Validation did not catch expected error for reusing deleted customer IDs")
}
}
func TestValidateProjectConfigDatasCustomerExperimentNamespaces(t *testing.T) {
configs := []config_parser.ProjectConfigData{
{
CustomerName: "cobalt_internal",
CustomerId: 2147483647,
ProjectName: "project3",
ProjectId: 3,
Contact: "project3@customer5.com",
CustomerExperimentsNamespaces: []interface{}{"customer_experiment_namespace"},
},
}
err := ValidateProjectConfigDatas(configs)
if err == nil {
t.Errorf("Validation did not catch expected error for experiments in internal customers")
}
}
func TestValidateProjectConfigDatasProjectExperimentNamespaces(t *testing.T) {
configs := []config_parser.ProjectConfigData{
{
CustomerName: "cobalt_internal",
CustomerId: 2147483647,
ProjectName: "project3",
ProjectId: 3,
Contact: "project3@customer5.com",
ProjectExperimentsNamespaces: []interface{}{"customer_experiment_namespace"},
},
}
err := ValidateProjectConfigDatas(configs)
if err == nil {
t.Errorf("Validation did not catch expected error for experiments in internal projects")
}
}
func TestValidateProjectConfigDatasDeletedProject(t *testing.T) {
projectConfigFile := config.ProjectConfigFile{
MetricDefinitions: []*config.MetricDefinition{
{
CustomerId: 5,
ProjectId: 3,
MetricName: "the_metric_name",
Id: 1,
TimeZonePolicy: config.MetricDefinition_UTC,
Reports: []*config.ReportDefinition{
{
ReportName: "the_report",
Id: 10,
ReportType: config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS,
},
{
ReportName: "the_other_report",
Id: 20,
ReportType: config.ReportDefinition_HOURLY_VALUE_NUMERIC_STATS,
},
},
},
},
}
configs := []config_parser.ProjectConfigData{
{
CustomerName: "customer5",
CustomerId: 5,
ProjectName: "project3",
ProjectId: 3,
Contact: "project3@customer5.com",
DeletedProjectIds: []uint32{4, 5},
ProjectConfigFile: &projectConfigFile,
},
{
CustomerName: "customer5",
CustomerId: 5,
ProjectName: "project4",
ProjectId: 4,
Contact: "project4@customer5.com",
DeletedProjectIds: []uint32{4, 5},
ProjectConfigFile: &projectConfigFile,
},
}
err := ValidateProjectConfigDatas(configs)
if err == nil {
t.Errorf("Validation did not catch expected error for reusing deleted project ID")
}
}
func TestValidateProjectConfigDatasDeletedMetric(t *testing.T) {
projectConfigFile := config.ProjectConfigFile{
MetricDefinitions: []*config.MetricDefinition{
{
CustomerId: 5,
ProjectId: 3,
MetricName: "the_metric_name",
Id: 1,
TimeZonePolicy: config.MetricDefinition_UTC,
Reports: []*config.ReportDefinition{
{
ReportName: "the_report",
Id: 10,
ReportType: config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS,
},
{
ReportName: "the_other_report",
Id: 20,
ReportType: config.ReportDefinition_HOURLY_VALUE_NUMERIC_STATS,
},
},
},
{
CustomerId: 5,
ProjectId: 3,
MetricName: "the_other_metric_name",
Id: 2,
TimeZonePolicy: config.MetricDefinition_LOCAL,
Reports: []*config.ReportDefinition{
{
ReportName: "the_report",
Id: 10,
ReportType: config.ReportDefinition_HOURLY_VALUE_NUMERIC_STATS,
},
},
},
},
DeletedMetricIds: []uint32{2},
}
configs := []config_parser.ProjectConfigData{
{
CustomerName: "customer5",
CustomerId: 5,
ProjectName: "project3",
ProjectId: 3,
Contact: "project3@customer5.com",
ProjectConfigFile: &projectConfigFile,
},
}
err := ValidateProjectConfigDatas(configs)
if err == nil {
t.Errorf("Validation did not catch expected error for reusing deleted metric ID")
}
}