| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package config_validator |
| |
| import ( |
| "config" |
| "testing" |
| ) |
| |
| // makeValidReport returns a valid instance of config.ReportDefinition which |
| // can be modified to fail various validation checks for testing purposes. |
| func makeValidReport() config.ReportDefinition { |
| return makeValidReportWithNameAndType("the_report_name", config.ReportDefinition_EVENT_COMPONENT_OCCURRENCE_COUNT) |
| } |
| |
| func makeValidReportWithType(t config.ReportDefinition_ReportType) config.ReportDefinition { |
| return makeValidReportWithNameAndType("the_report_name", t) |
| } |
| |
| func makeValidReportWithName(name string) config.ReportDefinition { |
| return makeValidReportWithNameAndType(name, config.ReportDefinition_EVENT_COMPONENT_OCCURRENCE_COUNT) |
| } |
| |
| func makeValidReportWithNameAndType(name string, t config.ReportDefinition_ReportType) config.ReportDefinition { |
| return config.ReportDefinition{ |
| Id: 10, |
| ReportName: name, |
| ReportType: t, |
| } |
| } |
| |
| // Given a metric type |mt|, returns a valid report type for that metric type. |
| // Prefers to return a non-histogram report type if the given metric type supports |
| // one, to aid in checking where int_buckets get set in tests. |
| func getMatchingReportType(mt config.MetricDefinition_MetricType) config.ReportDefinition_ReportType { |
| switch mt { |
| case config.MetricDefinition_EVENT_OCCURRED: |
| return config.ReportDefinition_SIMPLE_OCCURRENCE_COUNT |
| case config.MetricDefinition_EVENT_COUNT: |
| return config.ReportDefinition_EVENT_COMPONENT_OCCURRENCE_COUNT |
| case config.MetricDefinition_ELAPSED_TIME: |
| return config.ReportDefinition_NUMERIC_AGGREGATION |
| case config.MetricDefinition_FRAME_RATE: |
| return config.ReportDefinition_NUMERIC_AGGREGATION |
| case config.MetricDefinition_MEMORY_USAGE: |
| return config.ReportDefinition_NUMERIC_AGGREGATION |
| case config.MetricDefinition_INT_HISTOGRAM: |
| return config.ReportDefinition_INT_RANGE_HISTOGRAM |
| case config.MetricDefinition_CUSTOM: |
| return config.ReportDefinition_CUSTOM_RAW_DUMP |
| case config.MetricDefinition_OCCURRENCE: |
| return config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS |
| case config.MetricDefinition_INTEGER: |
| return config.ReportDefinition_FLEETWIDE_MEANS |
| case config.MetricDefinition_INTEGER_HISTOGRAM: |
| return config.ReportDefinition_FLEETWIDE_HISTOGRAMS |
| case config.MetricDefinition_STRING: |
| return config.ReportDefinition_STRING_COUNTS |
| } |
| |
| return config.ReportDefinition_REPORT_TYPE_UNSET |
| } |
| |
| // Test that makeValidReport returns a valid report. |
| func TestValidateMakeValidReport(t *testing.T) { |
| m := makeValidMetric(config.MetricDefinition_EVENT_COUNT) |
| r := makeValidReport() |
| if err := validateReportDefinition(m, r); err != nil { |
| t.Errorf("Rejected valid report: %v", err) |
| } |
| } |
| |
| func TestDifferentReportId(t *testing.T) { |
| m := makeValidMetric(config.MetricDefinition_EVENT_COUNT) |
| r := makeValidReport() |
| r.Id += 1 |
| |
| if err := validateReportDefinition(m, r); err != nil { |
| t.Error("Reject report with different report id.") |
| } |
| } |
| |
| func TestValidateInvalidName(t *testing.T) { |
| m := makeValidMetric(config.MetricDefinition_EVENT_COUNT) |
| r := makeValidReportWithName("_invalid_name") |
| |
| if err := validateReportDefinition(m, r); err == nil { |
| t.Error("Accepted report with invalid name.") |
| } |
| } |
| |
| func TestValidateZeroReportId(t *testing.T) { |
| m := makeValidMetric(config.MetricDefinition_EVENT_COUNT) |
| r := makeValidReportWithName("NRaMinLNcqiYmgEypLLVGnXymNpxJzqabtbbjLycCMEohvVzZtAYpah") |
| r.Id = 0 |
| |
| if err := validateReportDefinition(m, r); err == nil { |
| t.Error("Accepted report with 0 id.") |
| } |
| } |
| |
| func TestValidateUnsetReportType(t *testing.T) { |
| if err := validateReportType(config.MetricDefinition_EVENT_OCCURRED, config.ReportDefinition_REPORT_TYPE_UNSET); err == nil { |
| t.Error("Accepted report with no report type set.") |
| } |
| } |
| |
| // Test that validateLocalPrivacyNoiseLevel accepts a ReportDefinition if and only if it has a local_privacy_noise_level field. |
| func TestValidateLocalPrivacyNoiseLevel(t *testing.T) { |
| r := makeValidReport() |
| |
| if err := validateLocalPrivacyNoiseLevel(r); err == nil { |
| t.Error("Accepted report definition with local_privacy_noise_level unset.") |
| } |
| |
| r.LocalPrivacyNoiseLevel = config.ReportDefinition_SMALL |
| if err := validateLocalPrivacyNoiseLevel(r); err != nil { |
| t.Errorf("Rejected report definition with local_privacy_noise_level set: %v", err) |
| } |
| } |
| |
| // Test that validateWindowSize rejects a ReportDefinition with no window_size field, and a ReportDefinition with a |
| // window_size field where one of the window sizes is UNSET. |
| func TestValidateWindowSize(t *testing.T) { |
| r := makeValidReport() |
| |
| if err := validateWindowSize(r); err == nil { |
| t.Error("Accepted report definition without window_size field.") |
| } |
| |
| r.WindowSize = []config.WindowSize{config.WindowSize_WINDOW_1_DAY, config.WindowSize_UNSET} |
| if err := validateWindowSize(r); err == nil { |
| t.Error("Accepted report definition with an UNSET window size.") |
| } |
| |
| r.WindowSize = []config.WindowSize{config.WindowSize_WINDOW_1_DAY, config.WindowSize_WINDOW_7_DAYS} |
| if err := validateWindowSize(r); err != nil { |
| t.Errorf("Rejected report definition with valid window_size field: %v", err) |
| } |
| } |
| |
| func TestValidatePoissonFields(t *testing.T) { |
| r := makeValidReport() |
| |
| r.PrivacyLevel = config.ReportDefinition_NO_ADDED_PRIVACY |
| r.UsePoissonMechanismForPrivacy = true |
| if err := validatePoissonFields(r); err == nil { |
| t.Error("Accepted report definition with `use_poisson_mechanism_for_privacy` set but with NO_ADDED_PRIVACY privacy level") |
| } |
| |
| r.PrivacyLevel = config.ReportDefinition_HIGH_PRIVACY |
| if err := validatePoissonFields(r); err == nil { |
| t.Error("Accepted report definition with a nontrivial privacy level and `use_poisson_mechanism_for_privacy` set, but without `poisson_mean`") |
| } |
| |
| r.UsePoissonMechanismForPrivacy = false |
| r.PoissonMean = 1.0 |
| if err := validatePoissonFields(r); err == nil { |
| t.Error("Accepted report definition with `poisson_mean` set while `use_poisson_mechanism_for_privacy` was not selected") |
| } |
| |
| r.UsePoissonMechanismForPrivacy = true |
| r.PoissonMean = -1.0 |
| if err := validatePoissonFields(r); err == nil { |
| t.Error("Accepted report definition with negative `poisson_mean`") |
| } |
| |
| r.PoissonMean = 1.0 |
| if err := validatePoissonFields(r); err != nil { |
| t.Error("Rejected report definition with valid `use_poisson_mechanism_for_privacy` and `poisson_mean` settings") |
| } |
| } |
| |
| func TestValidateMinValueMaxValueNoAddedPrivacy(t *testing.T) { |
| var reportTypes = []config.ReportDefinition_ReportType{ |
| config.ReportDefinition_UNIQUE_DEVICE_COUNTS, |
| config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS, |
| config.ReportDefinition_UNIQUE_DEVICE_NUMERIC_STATS, |
| config.ReportDefinition_HOURLY_VALUE_NUMERIC_STATS, |
| config.ReportDefinition_UNIQUE_DEVICE_HISTOGRAMS, |
| config.ReportDefinition_HOURLY_VALUE_HISTOGRAMS, |
| config.ReportDefinition_FLEETWIDE_HISTOGRAMS, |
| config.ReportDefinition_FLEETWIDE_MEANS, |
| config.ReportDefinition_STRING_COUNTS, |
| config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS, |
| } |
| type args struct { |
| minValue int64 |
| maxValue int64 |
| } |
| var tests = []struct { |
| input args |
| valid bool |
| }{ |
| // Valid reports: no added privacy, no bounds set |
| {args{0, 0}, true}, |
| // Invalid reports: no added privacy, at least one of min_value and max_value set |
| {args{0, 1}, false}, |
| {args{1, 0}, false}, |
| {args{1, 1}, false}, |
| } |
| for _, reportType := range reportTypes { |
| for _, test := range tests { |
| r := makeValidReportWithType(reportType) |
| r.PrivacyLevel = config.ReportDefinition_NO_ADDED_PRIVACY |
| r.MinValue = test.input.minValue |
| r.MaxValue = test.input.maxValue |
| err := validateMinValueMaxValue(r) |
| |
| if test.valid && err != nil { |
| t.Errorf("rejected valid report with type %v and (min_value, max_value) = %v error: %v", |
| reportType, test.input, err) |
| } else if !test.valid && err == nil { |
| t.Errorf("accepted invalid report with type %v and (min_value, max_value) = %v", |
| reportType, test.input) |
| } |
| } |
| } |
| } |
| |
| func TestValidateMinValueMaxValueWithAddedPrivacy(t *testing.T) { |
| var required = []config.ReportDefinition_ReportType{ |
| config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS, |
| config.ReportDefinition_UNIQUE_DEVICE_NUMERIC_STATS, |
| config.ReportDefinition_HOURLY_VALUE_NUMERIC_STATS, |
| config.ReportDefinition_FLEETWIDE_MEANS, |
| } |
| var notAllowed = []config.ReportDefinition_ReportType{ |
| config.ReportDefinition_UNIQUE_DEVICE_COUNTS, |
| config.ReportDefinition_UNIQUE_DEVICE_HISTOGRAMS, |
| config.ReportDefinition_HOURLY_VALUE_HISTOGRAMS, |
| config.ReportDefinition_FLEETWIDE_HISTOGRAMS, |
| config.ReportDefinition_STRING_COUNTS, |
| config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS, |
| } |
| type args struct { |
| reportTypes []config.ReportDefinition_ReportType |
| minValue int64 |
| maxValue int64 |
| } |
| var tests = []struct { |
| input args |
| valid bool |
| }{ |
| // Valid reports: min value and max value should not be set |
| {args{notAllowed, 0, 0}, true}, |
| // Valid reports: at least one of min value and max value should be set |
| {args{required, 0, 1}, true}, |
| {args{required, -1, 1}, true}, |
| {args{required, 1, 1}, true}, |
| // Invalid reports: min value and max value should not be set |
| {args{notAllowed, 0, 1}, false}, |
| {args{notAllowed, -1, 0}, false}, |
| // Invalid reports: at least one of min value and max value should be set |
| {args{required, 0, 0}, false}, |
| // Invalid reports: min value is larger than max value |
| {args{required, 2, 1}, false}, |
| } |
| for _, test := range tests { |
| for _, reportType := range test.input.reportTypes { |
| r := makeValidReportWithType(reportType) |
| r.PrivacyLevel = config.ReportDefinition_LOW_PRIVACY |
| r.MinValue = test.input.minValue |
| r.MaxValue = test.input.maxValue |
| err := validateMinValueMaxValue(r) |
| |
| if test.valid && err != nil { |
| t.Errorf("rejected valid report of type %v with error: %v", reportType, err) |
| } else if !test.valid && err == nil { |
| t.Errorf("accepted invalid report of type %v and (min_value, max_value) = (%d, %d)", |
| reportType, test.input.minValue, test.input.maxValue) |
| } |
| } |
| } |
| } |
| |
| func TestValidateMaxCountNoAddedPrivacy(t *testing.T) { |
| var reportTypes = []config.ReportDefinition_ReportType{ |
| config.ReportDefinition_UNIQUE_DEVICE_COUNTS, |
| config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS, |
| config.ReportDefinition_UNIQUE_DEVICE_NUMERIC_STATS, |
| config.ReportDefinition_HOURLY_VALUE_NUMERIC_STATS, |
| config.ReportDefinition_UNIQUE_DEVICE_HISTOGRAMS, |
| config.ReportDefinition_HOURLY_VALUE_HISTOGRAMS, |
| config.ReportDefinition_FLEETWIDE_HISTOGRAMS, |
| config.ReportDefinition_FLEETWIDE_MEANS, |
| config.ReportDefinition_STRING_COUNTS, |
| config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS, |
| } |
| var tests = []struct { |
| maxCount uint64 |
| valid bool |
| }{ |
| // Valid reports: no added privacy, no bounds set |
| {0, true}, |
| // Invalid reports: no added privacy, max_count set |
| {1, false}, |
| } |
| for _, reportType := range reportTypes { |
| for _, test := range tests { |
| r := makeValidReportWithType(reportType) |
| r.PrivacyLevel = config.ReportDefinition_NO_ADDED_PRIVACY |
| r.MaxCount = test.maxCount |
| err := validateMaxCount(r) |
| |
| if test.valid && err != nil { |
| t.Errorf("rejected valid report with type %v and max_count = %d error: %v", |
| reportType, test.maxCount, err) |
| } else if !test.valid && err == nil { |
| t.Errorf("accepted invalid report with type %v and max_count = %d", |
| reportType, test.maxCount) |
| } |
| } |
| } |
| } |
| |
| func TestValidateMaxCountWithAddedPrivacy(t *testing.T) { |
| var required = []config.ReportDefinition_ReportType{ |
| config.ReportDefinition_FLEETWIDE_HISTOGRAMS, |
| config.ReportDefinition_FLEETWIDE_MEANS, |
| config.ReportDefinition_STRING_COUNTS, |
| } |
| var notAllowed = []config.ReportDefinition_ReportType{ |
| config.ReportDefinition_UNIQUE_DEVICE_COUNTS, |
| config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS, |
| config.ReportDefinition_UNIQUE_DEVICE_NUMERIC_STATS, |
| config.ReportDefinition_HOURLY_VALUE_NUMERIC_STATS, |
| config.ReportDefinition_UNIQUE_DEVICE_HISTOGRAMS, |
| config.ReportDefinition_HOURLY_VALUE_HISTOGRAMS, |
| config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS, |
| } |
| type args struct { |
| reportTypes []config.ReportDefinition_ReportType |
| maxCount uint64 |
| } |
| var tests = []struct { |
| input args |
| valid bool |
| }{ |
| // Valid reports: max count should be set |
| {args{required, 1}, true}, |
| // Valid reports: max count should not be set |
| {args{notAllowed, 0}, true}, |
| // Valid reports: max count should be set |
| {args{required, 1}, true}, |
| // Invalid reports: max count should not be set |
| {args{notAllowed, 1}, false}, |
| // Invalid reports: max count should be set |
| {args{required, 0}, false}, |
| } |
| for _, test := range tests { |
| for _, reportType := range test.input.reportTypes { |
| r := makeValidReportWithType(reportType) |
| r.PrivacyLevel = config.ReportDefinition_LOW_PRIVACY |
| r.MaxCount = test.input.maxCount |
| err := validateMaxCount(r) |
| |
| if test.valid && err != nil { |
| t.Errorf("rejected valid report of type %v with error: %v", reportType, err) |
| } else if !test.valid && err == nil { |
| t.Errorf("accepted invalid report of type %v and max_count = %d", |
| reportType, test.input.maxCount) |
| } |
| } |
| } |
| } |
| |
| // Test that local_privacy_noise_level must be set if the report type is SIMPLE_OCCURRENCE_COUNT. |
| func TestValidateReportDefinitionForSimpleOccurrenceCount(t *testing.T) { |
| m := makeValidMetric(config.MetricDefinition_EVENT_COUNT) |
| r := makeValidReport() |
| r.ReportType = config.ReportDefinition_SIMPLE_OCCURRENCE_COUNT |
| |
| if err := validateReportDefinition(m, r); err == nil { |
| t.Error("Accepted report definition of type SIMPLE_OCCURRENCE_COUNT with local_privacy_noise_level unset.") |
| } |
| } |
| |
| // Test that local_privacy_noise_level and window_size must be set if the report type is UNIQUE_N_DAY_ACTIVES. |
| func TestValidateReportDefinitionForUniqueActives(t *testing.T) { |
| m := makeValidMetric(config.MetricDefinition_EVENT_COUNT) |
| r := makeValidReport() |
| r.ReportType = config.ReportDefinition_UNIQUE_N_DAY_ACTIVES |
| |
| // Add a valid window_size, but not a local_privacy_noise_level. |
| r.WindowSize = []config.WindowSize{config.WindowSize_WINDOW_1_DAY} |
| if err := validateReportDefinition(m, r); err == nil { |
| t.Error("Accepted report definition of type UNIQUE_N_DAY_ACTIVES with local_privacy_noise_level unset.") |
| } |
| |
| // Remove window_size and add a local_privacy_noise_level. |
| r.WindowSize = []config.WindowSize{} |
| r.LocalPrivacyNoiseLevel = config.ReportDefinition_SMALL |
| if err := validateReportDefinition(m, r); err == nil { |
| t.Error("Accepted report definition of type UNIQUE_N_DAY_ACTIVES without window_size field.") |
| } |
| |
| // Add a valid window size to window_size, but also add an UNSET window size. |
| r.WindowSize = []config.WindowSize{config.WindowSize_WINDOW_1_DAY, config.WindowSize_UNSET} |
| if err := validateReportDefinition(m, r); err == nil { |
| t.Error("Accepted report definition of type UNIQUE_N_DAY_ACTIVES with window_size field containing an UNSET window size.") |
| } |
| } |
| |
| // Test that window_size must be set if the report type is PER_DEVICE_NUMERIC_STATS. |
| func TestValidateReportDefinitionForPerDeviceNumericStats(t *testing.T) { |
| m := makeValidMetric(config.MetricDefinition_EVENT_COUNT) |
| r := makeValidReport() |
| r.ReportType = config.ReportDefinition_PER_DEVICE_NUMERIC_STATS |
| |
| if err := validateReportDefinition(m, r); err == nil { |
| t.Error("Accepted report definition of type PER_DEVICE_NUMERIC_STATS without window_size field.") |
| } |
| |
| // Add a valid window size to window_size, but also add an UNSET window size. |
| r.WindowSize = []config.WindowSize{config.WindowSize_WINDOW_1_DAY, config.WindowSize_UNSET} |
| if err := validateReportDefinition(m, r); err == nil { |
| t.Error("Accepted report definition of type PER_DEVICE_NUMERIC_STATS with window_size field containing an UNSET window size.") |
| } |
| } |
| |
| // Test that window_size must be set if the report type is PER_DEVICE_HISTOGRAM. |
| func TestValidateReportDefinitionForPerDeviceHistogram(t *testing.T) { |
| m := makeValidMetric(config.MetricDefinition_EVENT_COUNT) |
| r := makeValidReport() |
| r.ReportType = config.ReportDefinition_PER_DEVICE_HISTOGRAM |
| |
| if err := validateReportDefinition(m, r); err == nil { |
| t.Error("No int_buckets specified for report of type PER_DEVICE_HISTOGRAM.") |
| } |
| |
| r.IntBuckets = &config.IntegerBuckets{} |
| if err := validateReportDefinition(m, r); err == nil { |
| t.Error("Accepted report definition of type PER_DEVICE_HISTOGRAM without window_size field.") |
| } |
| |
| // Add a valid window size to window_size, but also add an UNSET window size. |
| r.WindowSize = []config.WindowSize{config.WindowSize_WINDOW_1_DAY, config.WindowSize_UNSET} |
| if err := validateReportDefinition(m, r); err == nil { |
| t.Error("Accepted report definition of type PER_DEVICE_HISTOGRAM with window_size field containing an UNSET window size.") |
| } |
| } |
| |
| // Test percentiles range for NUMERIC_AGGREGATION report types. |
| func TestValidateReportDefinitionForNumericAggregation(t *testing.T) { |
| m := makeValidMetric(config.MetricDefinition_EVENT_COUNT) |
| r := makeValidReport() |
| r.ReportType = config.ReportDefinition_NUMERIC_AGGREGATION |
| |
| // Test that percentiles are optional. |
| if err := validateReportDefinition(m, r); err != nil { |
| t.Error("Rejected report definition of type NUMERIC_AGGREGATION with no percentiles set.") |
| } |
| |
| // Test that percentiles between 0 and 100 are accepted. |
| r.Percentiles = []uint32{0, 25, 50, 75, 90, 99, 100} |
| if err := validateReportDefinition(m, r); err != nil { |
| t.Error("Rejected report definition of type NUMERIC_AGGREGATION with valid percentiles.") |
| } |
| |
| // Test that out of bounds percentiles are rejected. |
| r.Percentiles = []uint32{0, 25, 50, 75, 100, 101} |
| if err := validateReportDefinition(m, r); err == nil { |
| t.Error("Accepted report definition of type NUMERIC_AGGREGATION with invalid percentiles.") |
| } |
| } |
| |
| // Test that int_buckets is not set if the report type is STRING_COUNTS. |
| func TestValidateReportDefinitionForStringCounts(t *testing.T) { |
| m := makeValidMetric(config.MetricDefinition_EVENT_COUNT) |
| r := makeValidReport() |
| r.ReportType = config.ReportDefinition_STRING_COUNTS |
| r.PrivacyLevel = config.ReportDefinition_NO_ADDED_PRIVACY |
| r.StringBufferMax = 10 |
| |
| if err := validateReportDefinition(m, r); err != nil { |
| t.Errorf("Failed validation for valid report of type STRING_COUNTS: %v", err) |
| } |
| |
| r.IntBuckets = &config.IntegerBuckets{} |
| if err := validateReportDefinition(m, r); err == nil { |
| t.Error("Accepted report definition of type STRING_COUNTS with int_buckets specified.") |
| } |
| } |
| |
| // Test that int_buckets is not set if the report type is UNIQUE_DEVICE_STRING_COUNTS. |
| func TestValidateReportDefitionForUniqueDeviceStringCounts(t *testing.T) { |
| m := makeValidMetric(config.MetricDefinition_EVENT_COUNT) |
| r := makeValidReport() |
| r.ReportType = config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS |
| r.PrivacyLevel = config.ReportDefinition_NO_ADDED_PRIVACY |
| r.LocalAggregationPeriod = config.WindowSize_WINDOW_1_DAY |
| r.StringBufferMax = 10 |
| |
| if err := validateReportDefinition(m, r); err != nil { |
| t.Errorf("Failed validation for valid report of type UNIQUE_DEVICE_STRING_COUNTS: %v", err) |
| } |
| |
| r.IntBuckets = &config.IntegerBuckets{} |
| if err := validateReportDefinition(m, r); err == nil { |
| t.Errorf("Accepted report definition of type UNIQUE_DEVICE_STRING_COUNTS with int_buckets specified.") |
| } |
| } |
| |
| // Test that Histogram report types get properly validated for int_buckets in main validation functions. |
| func TestHistogramReportsHaveIntBuckets(t *testing.T) { |
| // ================================================================================ |
| // Test PER_DEVICE_HISTOGRAM reports with int_buckets set in the report definition. |
| // ================================================================================ |
| m := makeValidCobalt10BaseMetric(config.MetricDefinition_EVENT_COUNT) |
| r := makeValidReportWithType(config.ReportDefinition_PER_DEVICE_HISTOGRAM) |
| r.WindowSize = []config.WindowSize{config.WindowSize_WINDOW_1_DAY, config.WindowSize_WINDOW_7_DAYS} |
| |
| // Test that no IntBuckets defined returns an error. |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted PER_DEVICE_HISTOGRAM report with no int_bucket defined: %v", err) |
| } |
| |
| // Test that an IntBuckets without a linear or exponential bucket defined returns an error. |
| r.IntBuckets = &config.IntegerBuckets{} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted PER_DEVICE_HISTOGRAM report with an uninitialized int_buckets set in the report: %v", err) |
| } |
| |
| // Test that an empty Linear bucket config returns an error. |
| r.IntBuckets.Buckets = &config.IntegerBuckets_Linear{} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted PER_DEVICE_HISTOGRAM report with an empty linear bucket config in the report: %v", err) |
| } |
| |
| // Test that a Linear bucket config with invalid num_buckets returns an error. |
| linear := &config.LinearIntegerBuckets{Floor: 0, NumBuckets: 0, StepSize: 10} |
| r.IntBuckets.Buckets = &config.IntegerBuckets_Linear{Linear: linear} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted PER_DEVICE_HISTOGRAM report with an invalid linear num_buckets in the report: %v", err) |
| } |
| |
| // Test that a Linear bucket config with invalid step_size returns an error. |
| linear = &config.LinearIntegerBuckets{Floor: 0, NumBuckets: 10, StepSize: 0} |
| r.IntBuckets.Buckets = &config.IntegerBuckets_Linear{Linear: linear} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted PER_DEVICE_HISTOGRAM report with an invalid linear step_size in the report: %v", err) |
| } |
| |
| // Test that a valid Linear bucket config passes. |
| linear = &config.LinearIntegerBuckets{Floor: 0, NumBuckets: 20, StepSize: 10} |
| r.IntBuckets.Buckets = &config.IntegerBuckets_Linear{Linear: linear} |
| if err := validateReportDefinitionForMetric(m, r); err != nil { |
| t.Errorf("Rejected PER_DEVICE_HISTOGRAM report with a valid linear int_config in the report: %v", err) |
| } |
| |
| // Test that an empty Exponential bucket config returns an error. |
| r.IntBuckets.Buckets = &config.IntegerBuckets_Exponential{} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted PER_DEVICE_HISTOGRAM report with an empty exponential bucket config in the report: %v", err) |
| } |
| |
| // Test that an Exponential bucket config with invalid num_buckets returns an error. |
| exponential := &config.ExponentialIntegerBuckets{Floor: 0, NumBuckets: 0, InitialStep: 10, StepMultiplier: 2} |
| r.IntBuckets.Buckets = &config.IntegerBuckets_Exponential{Exponential: exponential} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted PER_DEVICE_HISTOGRAM report with an invalid exponential num_buckets in the report: %v", err) |
| } |
| |
| // Test that an Exponential bucket config with invalid initial_step returns an error. |
| exponential = &config.ExponentialIntegerBuckets{Floor: 0, NumBuckets: 10, InitialStep: 0, StepMultiplier: 2} |
| r.IntBuckets.Buckets = &config.IntegerBuckets_Exponential{Exponential: exponential} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted PER_DEVICE_HISTOGRAM report with an invalid exponential initial_step in the report: %v", err) |
| } |
| |
| // Test that an Exponential bucket config with invalid step_multiplier returns an error. |
| exponential = &config.ExponentialIntegerBuckets{Floor: 0, NumBuckets: 20, InitialStep: 2, StepMultiplier: 0} |
| r.IntBuckets.Buckets = &config.IntegerBuckets_Exponential{Exponential: exponential} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted PER_DEVICE_HISTOGRAM report with an invalid exponential step_multiplier in the report: %v", err) |
| } |
| |
| // Test that a valid Exponential bucket config passes. |
| exponential = &config.ExponentialIntegerBuckets{Floor: 0, NumBuckets: 30, InitialStep: 2, StepMultiplier: 2} |
| r.IntBuckets.Buckets = &config.IntegerBuckets_Exponential{Exponential: exponential} |
| if err := validateReportDefinitionForMetric(m, r); err != nil { |
| t.Errorf("Accepted PER_DEVICE_HISTOGRAM report with an invalid exponential step_multiplier in the report: %v", err) |
| } |
| |
| // ================================================================================ |
| // Test INT_RANGE_HISTOGRAM reports with int_buckets set in the report definition. |
| // ================================================================================ |
| |
| r = makeValidReportWithType(config.ReportDefinition_INT_RANGE_HISTOGRAM) |
| |
| // Test that no IntBuckets defined returns an error. |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with no int_bucket defined: %v", err) |
| } |
| |
| // Test that an IntBuckets without a linear or exponential bucket defined returns an error. |
| r.IntBuckets = &config.IntegerBuckets{} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with an uninitialized int_buckets set in the report: %v", err) |
| } |
| |
| // Test that an empty Linear bucket config returns an error. |
| r.IntBuckets.Buckets = &config.IntegerBuckets_Linear{} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with an empty linear bucket config in the report: %v", err) |
| } |
| |
| // Test that a Linear bucket config with invalid num_buckets returns an error. |
| linear = &config.LinearIntegerBuckets{Floor: 0, NumBuckets: 0, StepSize: 10} |
| r.IntBuckets.Buckets = &config.IntegerBuckets_Linear{Linear: linear} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with an invalid linear num_buckets in the report: %v", err) |
| } |
| |
| // Test that a Linear bucket config with invalid step_size returns an error. |
| linear = &config.LinearIntegerBuckets{Floor: 0, NumBuckets: 10, StepSize: 0} |
| r.IntBuckets.Buckets = &config.IntegerBuckets_Linear{Linear: linear} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with an invalid linear step_size in the report: %v", err) |
| } |
| |
| // Test that a valid Linear bucket config passes. |
| linear = &config.LinearIntegerBuckets{Floor: 0, NumBuckets: 20, StepSize: 10} |
| r.IntBuckets.Buckets = &config.IntegerBuckets_Linear{Linear: linear} |
| if err := validateReportDefinitionForMetric(m, r); err != nil { |
| t.Errorf("Rejected INT_RANGE_HISTOGRAM report with a valid linear int_config in the report: %v", err) |
| } |
| |
| // Test that an empty Exponential bucket config returns an error. |
| r.IntBuckets.Buckets = &config.IntegerBuckets_Exponential{} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with an empty exponential bucket config in the report: %v", err) |
| } |
| |
| // Test that an Exponential bucket config with invalid num_buckets returns an error. |
| exponential = &config.ExponentialIntegerBuckets{Floor: 0, NumBuckets: 0, InitialStep: 10, StepMultiplier: 2} |
| r.IntBuckets.Buckets = &config.IntegerBuckets_Exponential{Exponential: exponential} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with an invalid exponential num_buckets in the report: %v", err) |
| } |
| |
| // Test that an Exponential bucket config with invalid initial_step returns an error. |
| exponential = &config.ExponentialIntegerBuckets{Floor: 0, NumBuckets: 10, InitialStep: 0, StepMultiplier: 2} |
| r.IntBuckets.Buckets = &config.IntegerBuckets_Exponential{Exponential: exponential} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with an invalid exponential initial_step in the report: %v", err) |
| } |
| |
| // Test that an Exponential bucket config with invalid step_multiplier returns an error. |
| exponential = &config.ExponentialIntegerBuckets{Floor: 0, NumBuckets: 20, InitialStep: 2, StepMultiplier: 0} |
| r.IntBuckets.Buckets = &config.IntegerBuckets_Exponential{Exponential: exponential} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with an invalid exponential step_multiplier in the report: %v", err) |
| } |
| |
| // Test that a valid Exponential bucket config passes. |
| exponential = &config.ExponentialIntegerBuckets{Floor: 0, NumBuckets: 30, InitialStep: 2, StepMultiplier: 2} |
| r.IntBuckets.Buckets = &config.IntegerBuckets_Exponential{Exponential: exponential} |
| if err := validateReportDefinitionForMetric(m, r); err != nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with an invalid exponential step_multiplier in the report: %v", err) |
| } |
| |
| // ================================================================================ |
| // Test INT_RANGE_HISTOGRAM reports with int_buckets set in the metric definition. |
| // ================================================================================ |
| m = makeValidCobalt10BaseMetric(config.MetricDefinition_INT_HISTOGRAM) |
| r = makeValidReportWithType(config.ReportDefinition_INT_RANGE_HISTOGRAM) |
| |
| // Test that an IntBuckets without a linear or exponential bucket defined returns an error. |
| m.IntBuckets = &config.IntegerBuckets{} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with an uninitialized int_buckets set in the metric: %v", err) |
| } |
| |
| // Test that an empty Linear bucket config returns an error. |
| m.IntBuckets.Buckets = &config.IntegerBuckets_Linear{} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with an empty linear bucket config in the metric: %v", err) |
| } |
| |
| // Test that a Linear bucket config with invalid num_buckets returns an error. |
| linear = &config.LinearIntegerBuckets{Floor: 0, NumBuckets: 0, StepSize: 10} |
| m.IntBuckets.Buckets = &config.IntegerBuckets_Linear{Linear: linear} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with an invalid linear num_buckets in the metric: %v", err) |
| } |
| |
| // Test that a Linear bucket config with invalid step_size returns an error. |
| linear = &config.LinearIntegerBuckets{Floor: 0, NumBuckets: 10, StepSize: 0} |
| m.IntBuckets.Buckets = &config.IntegerBuckets_Linear{Linear: linear} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with an invalid linear step_size in the metric: %v", err) |
| } |
| |
| // Test that a valid Linear bucket config passes. |
| linear = &config.LinearIntegerBuckets{Floor: 0, NumBuckets: 20, StepSize: 10} |
| m.IntBuckets.Buckets = &config.IntegerBuckets_Linear{Linear: linear} |
| if err := validateReportDefinitionForMetric(m, r); err != nil { |
| t.Errorf("Rejected INT_RANGE_HISTOGRAM report with a valid linear int_config in the metric: %v", err) |
| } |
| |
| // Test that an empty Exponential bucket config returns an error. |
| m.IntBuckets.Buckets = &config.IntegerBuckets_Exponential{} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with an empty exponential bucket config in the metric: %v", err) |
| } |
| |
| // Test that an Exponential bucket config with invalid num_buckets returns an error. |
| exponential = &config.ExponentialIntegerBuckets{Floor: 0, NumBuckets: 0, InitialStep: 10, StepMultiplier: 2} |
| m.IntBuckets.Buckets = &config.IntegerBuckets_Exponential{Exponential: exponential} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with an invalid exponential num_buckets in the metric: %v", err) |
| } |
| |
| // Test that an Exponential bucket config with invalid initial_step returns an error. |
| exponential = &config.ExponentialIntegerBuckets{Floor: 0, NumBuckets: 10, InitialStep: 0, StepMultiplier: 2} |
| m.IntBuckets.Buckets = &config.IntegerBuckets_Exponential{Exponential: exponential} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with an invalid exponential initial_step in the metric: %v", err) |
| } |
| |
| // Test that an Exponential bucket config with invalid step_multiplier returns an error. |
| exponential = &config.ExponentialIntegerBuckets{Floor: 0, NumBuckets: 20, InitialStep: 2, StepMultiplier: 0} |
| m.IntBuckets.Buckets = &config.IntegerBuckets_Exponential{Exponential: exponential} |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with an invalid exponential step_multiplier in the metric: %v", err) |
| } |
| |
| // Test that a valid Exponential bucket config passes. |
| exponential = &config.ExponentialIntegerBuckets{Floor: 0, NumBuckets: 30, InitialStep: 2, StepMultiplier: 2} |
| m.IntBuckets.Buckets = &config.IntegerBuckets_Exponential{Exponential: exponential} |
| if err := validateReportDefinitionForMetric(m, r); err != nil { |
| t.Errorf("Accepted INT_RANGE_HISTOGRAM report with an invalid exponential step_multiplier in the metric: %v", err) |
| } |
| } |
| |
| func TestValidateHasNoCobalt11OnlyFields(t *testing.T) { |
| r := config.ReportDefinition{ |
| PrivacyLevel: config.ReportDefinition_NO_ADDED_PRIVACY, |
| } |
| |
| if err := validateHasNoCobalt11OnlyFields(r); err == nil { |
| t.Error("Accepted non-Cobalt 1.1 report with privacy_level set.") |
| } |
| |
| r = config.ReportDefinition{ |
| MinValue: 10, |
| } |
| |
| if err := validateHasNoCobalt11OnlyFields(r); err == nil { |
| t.Error("Accepted non-Cobalt 1.1 report with min_value set.") |
| } |
| |
| r = config.ReportDefinition{ |
| MaxValue: 10, |
| } |
| |
| if err := validateHasNoCobalt11OnlyFields(r); err == nil { |
| t.Error("Accepted non-Cobalt 1.1 report with max_value set.") |
| } |
| |
| r = config.ReportDefinition{ |
| MaxCount: 10, |
| } |
| |
| if err := validateHasNoCobalt11OnlyFields(r); err == nil { |
| t.Error("Accepted non-Cobalt 1.1 report with max_count set.") |
| } |
| |
| r = config.ReportDefinition{ |
| LocalAggregationProcedure: config.ReportDefinition_MEAN, |
| } |
| |
| if err := validateHasNoCobalt11OnlyFields(r); err == nil { |
| t.Error("Accepted non-Cobalt 1.1 report with local_aggregation_procedure set.") |
| } |
| |
| r = config.ReportDefinition{ |
| LocalAggregationProcedurePercentileN: 2, |
| } |
| |
| if err := validateHasNoCobalt11OnlyFields(r); err == nil { |
| t.Error("Accepted non-Cobalt 1.1 report with local_aggregation_procedure_percentile_n set.") |
| } |
| |
| r = config.ReportDefinition{ |
| LocalAggregationPeriod: config.WindowSize_WINDOW_1_DAY, |
| } |
| |
| if err := validateHasNoCobalt11OnlyFields(r); err == nil { |
| t.Error("Accepted non-Cobalt 1.1 report with local_aggregation_period set.") |
| } |
| |
| r = config.ReportDefinition{ |
| ReportingThreshold: 2, |
| } |
| |
| if err := validateHasNoCobalt11OnlyFields(r); err == nil { |
| t.Error("Accepted non-Cobalt 1.1 report with reporting_threshold set.") |
| } |
| } |
| |
| func TestValidateHasNoFieldsDeprecatedInCobalt11(t *testing.T) { |
| r := config.ReportDefinition{ |
| LocalPrivacyNoiseLevel: config.ReportDefinition_NONE, |
| } |
| |
| if err := validateHasNoFieldsDeprecatedInCobalt11(r); err == nil { |
| t.Error("Accepted non-Cobalt 1.1 report with local_privacy_noise_level set.") |
| } |
| |
| r = config.ReportDefinition{ |
| CandidateList: []string{"hello"}, |
| } |
| |
| if err := validateHasNoFieldsDeprecatedInCobalt11(r); err == nil { |
| t.Error("Accepted non-Cobalt 1.1 report with candidate_list set.") |
| } |
| |
| r = config.ReportDefinition{ |
| WindowSize: []config.WindowSize{config.WindowSize_WINDOW_1_DAY}, |
| } |
| |
| if err := validateHasNoFieldsDeprecatedInCobalt11(r); err == nil { |
| t.Error("Accepted non-Cobalt 1.1 report with window_size set.") |
| } |
| |
| r = config.ReportDefinition{ |
| AggregationWindow: []*config.OnDeviceAggregationWindow{ |
| &config.OnDeviceAggregationWindow{}, |
| }, |
| } |
| |
| if err := validateHasNoFieldsDeprecatedInCobalt11(r); err == nil { |
| t.Error("Accepted non-Cobalt 1.1 report with aggregation_window set.") |
| } |
| } |
| |
| func TestValidateLocalAggregationPeriod(t *testing.T) { |
| dailyReportTypes := []config.ReportDefinition_ReportType{ |
| config.ReportDefinition_UNIQUE_DEVICE_COUNTS, |
| config.ReportDefinition_UNIQUE_DEVICE_HISTOGRAMS, |
| config.ReportDefinition_UNIQUE_DEVICE_NUMERIC_STATS, |
| config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS, |
| } |
| hourlyReportTypes := []config.ReportDefinition_ReportType{ |
| config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS, |
| config.ReportDefinition_HOURLY_VALUE_HISTOGRAMS, |
| config.ReportDefinition_FLEETWIDE_HISTOGRAMS, |
| config.ReportDefinition_FLEETWIDE_MEANS, |
| config.ReportDefinition_HOURLY_VALUE_NUMERIC_STATS, |
| config.ReportDefinition_STRING_COUNTS, |
| } |
| |
| for _, reportType := range dailyReportTypes { |
| r := makeValidReportWithType(reportType) |
| |
| if err := validateLocalAggregationPeriod(r); err == nil { |
| t.Error("Accepted daily report with no local_aggregation_period") |
| } |
| |
| r.LocalAggregationPeriod = config.WindowSize_WINDOW_1_DAY |
| if err := validateLocalAggregationPeriod(r); err != nil { |
| t.Errorf("Rejected daily report with valid local_aggregation_period: %v", err) |
| } |
| } |
| |
| for _, reportType := range hourlyReportTypes { |
| r := makeValidReportWithType(reportType) |
| |
| r.LocalAggregationPeriod = config.WindowSize_WINDOW_1_DAY |
| if err := validateLocalAggregationPeriod(r); err == nil { |
| t.Error("Accepted hourly report with local_aggregation_period") |
| } |
| |
| r.LocalAggregationPeriod = config.WindowSize_UNSET |
| if err := validateLocalAggregationPeriod(r); err != nil { |
| t.Errorf("Rejected hourly report with no local_aggregation_period: %v", err) |
| } |
| } |
| } |
| |
| func TestValidateLocalAggregationProcedure(t *testing.T) { |
| intLocalAggregationProcedureTypes := []config.ReportDefinition_ReportType{ |
| config.ReportDefinition_UNIQUE_DEVICE_HISTOGRAMS, |
| config.ReportDefinition_HOURLY_VALUE_HISTOGRAMS, |
| config.ReportDefinition_UNIQUE_DEVICE_NUMERIC_STATS, |
| config.ReportDefinition_HOURLY_VALUE_NUMERIC_STATS, |
| } |
| |
| for _, reportType := range intLocalAggregationProcedureTypes { |
| m := makeValidMetric(config.MetricDefinition_INTEGER) |
| r := makeValidReportWithType(reportType) |
| |
| if err := validateLocalAggregationProcedure(m, r); err == nil { |
| t.Error("Accepted invalid report with no local_aggregation_procedure") |
| } |
| |
| r.LocalAggregationProcedure = config.ReportDefinition_AT_LEAST_ONCE |
| if err := validateLocalAggregationProcedure(m, r); err == nil { |
| t.Error("Accepted report with invalid local_aggregation_procedure") |
| } |
| |
| r.LocalAggregationProcedure = config.ReportDefinition_MEDIAN |
| if err := validateLocalAggregationProcedure(m, r); err != nil { |
| t.Errorf("Rejected report with valid local_aggregation_procedure: %v", err) |
| } |
| |
| r.LocalAggregationProcedure = config.ReportDefinition_PERCENTILE_N |
| if err := validateLocalAggregationProcedure(m, r); err == nil { |
| t.Error("Accepted PERCENTILE_N report with no local_aggregation_procedure_percentile_n set") |
| } |
| r.LocalAggregationProcedurePercentileN = 110 |
| if err := validateLocalAggregationProcedure(m, r); err == nil { |
| t.Error("Accepted PERCENTILE_N report with invalid local_aggregation_procedure_percentile_n set") |
| } |
| r.LocalAggregationProcedurePercentileN = 5 |
| if err := validateLocalAggregationProcedure(m, r); err != nil { |
| t.Errorf("Rejected PERCENTILE_N report with valid local_aggregation_procedure_percentile_n: %v", err) |
| } |
| |
| m = makeValidMetric(config.MetricDefinition_OCCURRENCE) |
| if err := validateLocalAggregationProcedure(m, r); err == nil { |
| t.Error("Accepted daily report with no local_aggregation_procedure") |
| } |
| |
| r.LocalAggregationProcedure = config.ReportDefinition_LOCAL_AGGREGATION_PROCEDURE_UNSET |
| if err := validateLocalAggregationProcedure(m, r); err != nil { |
| t.Errorf("Rejected daily report with valid local_aggregation_procedure: %v", err) |
| } |
| } |
| |
| m := makeValidMetric(config.MetricDefinition_OCCURRENCE) |
| r := makeValidReportWithType(config.ReportDefinition_UNIQUE_DEVICE_COUNTS) |
| if err := validateLocalAggregationProcedure(m, r); err == nil { |
| t.Error("Accepted invalid report with no local_aggregation_procedure") |
| } |
| r.LocalAggregationProcedure = config.ReportDefinition_MEDIAN |
| if err := validateLocalAggregationProcedure(m, r); err == nil { |
| t.Error("Accepted report with invalid local_aggregation_procedure") |
| } |
| r.LocalAggregationProcedure = config.ReportDefinition_AT_LEAST_ONCE |
| if err := validateLocalAggregationProcedure(m, r); err != nil { |
| t.Errorf("Rejected report with valid local_aggregation_procedure: %v", err) |
| } |
| |
| r.LocalAggregationProcedure = config.ReportDefinition_SELECT_FIRST |
| r.EventVectorBufferMax = 1 |
| if err := validateLocalAggregationProcedure(m, r); err != nil { |
| t.Errorf("Rejected report with valid event_vector_buffer_max config: %v", err) |
| } |
| |
| r.EventVectorBufferMax = 100 |
| if err := validateLocalAggregationProcedure(m, r); err == nil { |
| t.Errorf("Accepted report with invalid event_vector_buffer_max config") |
| } |
| |
| r = makeValidReportWithType(config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS) |
| r.LocalAggregationProcedure = config.ReportDefinition_AT_LEAST_ONCE |
| if err := validateLocalAggregationProcedure(m, r); err == nil { |
| t.Error("Accepted report with unnecessary local_aggregation_procedure") |
| } |
| } |
| |
| func TestValidateExpeditedSending(t *testing.T) { |
| m := makeValidMetric(config.MetricDefinition_OCCURRENCE) |
| r := makeValidReportWithType(config.ReportDefinition_UNIQUE_DEVICE_COUNTS) |
| r.ExpeditedSending = true |
| r.LocalAggregationProcedure = config.ReportDefinition_SELECT_MOST_COMMON |
| r.PrivacyLevel = config.ReportDefinition_NO_ADDED_PRIVACY |
| if err := validateExpeditedSending(m, r); err == nil { |
| t.Error("Accepted report with invalid local_aggregation_procedure for expedited_sending") |
| } |
| r.LocalAggregationProcedure = config.ReportDefinition_AT_LEAST_ONCE |
| if err := validateExpeditedSending(m, r); err != nil { |
| t.Errorf("Rejected report with expedited_sending and valid local_aggregation_procedure: %v", err) |
| } |
| r.LocalAggregationProcedure = config.ReportDefinition_SELECT_FIRST |
| if err := validateExpeditedSending(m, r); err != nil { |
| t.Errorf("Rejected report with expedited_sending and valid local_aggregation_procedure: %v", err) |
| } |
| r.PrivacyLevel = config.ReportDefinition_LOW_PRIVACY |
| if err := validateExpeditedSending(m, r); err == nil { |
| t.Error("Accepted report with invalid privacy_level for expedited_sending") |
| } |
| |
| r = makeValidReportWithType(config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS) |
| r.ExpeditedSending = true |
| r.LocalAggregationProcedure = config.ReportDefinition_AT_LEAST_ONCE |
| if err := validateExpeditedSending(m, r); err == nil { |
| t.Error("Accepted report with invalid type for expedited_sending") |
| } |
| r.ExpeditedSending = false |
| r.LocalAggregationProcedure = config.ReportDefinition_SELECT_MOST_COMMON |
| if err := validateExpeditedSending(m, r); err != nil { |
| t.Errorf("Rejected report with expedited_sending unset: %v", err) |
| } |
| |
| m = makeValidMetric(config.MetricDefinition_STRING) |
| r = makeValidReportWithType(config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS) |
| r.ExpeditedSending = true |
| r.LocalAggregationProcedure = config.ReportDefinition_LOCAL_AGGREGATION_PROCEDURE_UNSET |
| r.PrivacyLevel = config.ReportDefinition_NO_ADDED_PRIVACY |
| if err := validateExpeditedSending(m, r); err != nil { |
| t.Errorf("Rejected report with expedited_sending and valid report type: %v", err) |
| } |
| } |
| |
| // Test that deleted report IDs are not reused. |
| func TestDeletedReportIds(t *testing.T) { |
| m := makeValidMetric(config.MetricDefinition_OCCURRENCE) |
| r := makeValidReportWithType(config.ReportDefinition_UNIQUE_DEVICE_COUNTS) |
| r.LocalAggregationPeriod = config.WindowSize_WINDOW_1_DAY |
| r.LocalAggregationProcedure = config.ReportDefinition_AT_LEAST_ONCE |
| r.PrivacyLevel = config.ReportDefinition_NO_ADDED_PRIVACY |
| m.DeletedReportIds = append(m.DeletedReportIds, r.Id+10) |
| |
| // Test that using a new report ID returns no error. |
| if err := validateReportDefinitionForMetric(m, r); err != nil { |
| t.Errorf("Rejected report with new report ID: %v", err) |
| } |
| |
| // Test that reusing a previously deleted report ID returns an error. |
| m.DeletedReportIds = append(m.DeletedReportIds, r.Id) |
| if err := validateReportDefinitionForMetric(m, r); err == nil { |
| t.Errorf("Accepted invalid report with reused deleted report ID") |
| } |
| } |