blob: 8220eb4bc4120914f13702b2492cebdc895fec7c [file] [log] [blame]
// 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"
"errors"
"math"
"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_FLEETWIDE_OCCURRENCE_COUNTS)
}
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_FLEETWIDE_OCCURRENCE_COUNTS)
}
func makeValidReportWithNameAndType(name string, t config.ReportDefinition_ReportType) *config.ReportDefinition {
return &config.ReportDefinition{
Id: 10,
ReportName: name,
ReportType: t,
PrivacyLevel: config.ReportDefinition_NO_ADDED_PRIVACY,
PrivacyMechanism: config.ReportDefinition_DE_IDENTIFICATION,
}
}
// 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_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_OCCURRENCE)
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_OCCURRENCE)
r := makeValidReport()
r.Id += 1
if err := validateReportDefinition(m, r); err != nil {
t.Error("Reject report with different report id.")
}
}
func TestValidateReportHasNoAppVersionField(t *testing.T) {
r := makeValidReport()
r.SystemProfileField = []config.SystemProfileField{
config.SystemProfileField_CHANNEL, config.SystemProfileField_APP_VERSION}
if err := validateReportHasNoAppVersionField(r); err == nil {
t.Error("Did not detect app_version field.")
}
r.SystemProfileField = []config.SystemProfileField{
config.SystemProfileField_CHANNEL}
if err := validateReportHasNoAppVersionField(r); err != nil {
t.Error("Detected app_version field - although there was none.")
}
}
func TestNoAppVersionFieldOnFuchsiaErrorCase(t *testing.T) {
m := makeValidMetric(config.MetricDefinition_OCCURRENCE)
r := makeValidReport()
m.CustomerId = math.MaxInt32
r.SystemProfileField = []config.SystemProfileField{
config.SystemProfileField_APP_VERSION}
if err := validateReportDefinitionForMetric(m, r); err == nil {
t.Error("Accepted report with set app_version field on Fuchsia.")
}
}
func TestNoAppVersionFieldOnFuchsiaNoFuchsiaCase(t *testing.T) {
m := makeValidMetric(config.MetricDefinition_OCCURRENCE)
r := makeValidReport()
m.CustomerId = 3
r.SystemProfileField = []config.SystemProfileField{
config.SystemProfileField_APP_VERSION}
if err := validateReportDefinitionForMetric(m, r); err != nil {
t.Error("Didn't accept app_version field, although it wasn't Fuchsia.")
}
}
func TestNoAppVersionFieldOnFuchsiaNoAppVersionField(t *testing.T) {
m := makeValidMetric(config.MetricDefinition_OCCURRENCE)
r := makeValidReport()
m.CustomerId = 1
r.SystemProfileField = []config.SystemProfileField{
config.SystemProfileField_CHANNEL}
if err := validateReportDefinitionForMetric(m, r); err != nil {
t.Error("Did not accept ordinary report.")
}
}
func TestValidateInvalidName(t *testing.T) {
m := makeValidMetric(config.MetricDefinition_OCCURRENCE)
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_OCCURRENCE)
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_OCCURRENCE, config.ReportDefinition_REPORT_TYPE_UNSET); err == nil {
t.Error("Accepted report with no report type set.")
}
}
func TestValidatePoissonFields(t *testing.T) {
r := makeValidReport()
r.ReportType = config.ReportDefinition_UNIQUE_DEVICE_COUNTS
r.PrivacyLevel = config.ReportDefinition_NO_ADDED_PRIVACY
r.PoissonMean = 1.0
if err := validatePoissonFields(r); err == nil {
t.Error("Accepted report definition with `poisson_mean` set but with NO_ADDED_PRIVACY privacy level")
}
r.PrivacyLevel = config.ReportDefinition_HIGH_PRIVACY
r.PoissonMean = 0.0
if err := validatePoissonFields(r); err == nil {
t.Error("Accepted report definition with a nontrivial privacy level, but without `poisson_mean`")
}
r.PoissonMean = -1.0
if err := validatePoissonFields(r); err == nil {
t.Error("Accepted report definition with a nontrivial privacy level, but negative `poisson_mean`")
}
r.PoissonMean = 1.0
if err := validatePoissonFields(r); err == nil {
t.Error("Accepted report definition with a nontrivial privacy level, but `num_index_points` unset")
}
r.NumIndexPoints = 1
if err := validatePoissonFields(r); err != nil {
t.Error("Rejected report definition with a nontrivial privacy level and valid privacy settings")
}
stringSketchParams := config.StringSketchParameters{
NumCellsPerHash: 10,
NumHashes: 5,
}
r.ReportType = config.ReportDefinition_STRING_COUNTS
if err := validatePoissonFields(r); err == nil {
t.Error("Accepted STRING_COUNTS report definition with a nontrivial privacy level, but `string_sketch_params` unset")
}
r.ReportType = config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS
if err := validatePoissonFields(r); err == nil {
t.Error("Accepted UNIQUE_DEVICE_STRING_COUNTS report definition with a nontrivial privacy level, but `string_sketch_params` unset")
}
r.StringSketchParams = &stringSketchParams
r.ReportType = config.ReportDefinition_STRING_COUNTS
if err := validatePoissonFields(r); err != nil {
t.Error("Rejected STRING_COUNTS report definition with a nontrivial privacy level and valid privacy settings")
}
r.ReportType = config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS
if err := validatePoissonFields(r); err != nil {
t.Error("Rejected UNIQUE_DEVICE_STRING_COUTNS report definition with a nontrivial privacy level and valid privacy 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 int_buckets is not set if the report type is STRING_COUNTS.
func TestValidateReportDefinitionForStringCounts(t *testing.T) {
m := makeValidMetric(config.MetricDefinition_OCCURRENCE)
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_OCCURRENCE)
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.")
}
}
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)
}
}
func TestValidateMaxReleaseStage(t *testing.T) {
// Default valid metric uses DEBUG max_release_stage.
m := makeValidMetric(config.MetricDefinition_OCCURRENCE)
r := makeValidReportWithType(config.ReportDefinition_UNIQUE_DEVICE_COUNTS)
if err := validateMaxReleaseStage(m, r); err != nil {
t.Errorf("Rejected report with no max_release_stage: %v", err)
}
r.MaxReleaseStage = config.ReleaseStage_DEBUG
if err := validateMaxReleaseStage(m, r); err != nil {
t.Errorf("Rejected report with the same max_release_stage as the metric: %v", err)
}
r.MaxReleaseStage = config.ReleaseStage_FISHFOOD
if err := validateMaxReleaseStage(m, r); err == nil {
t.Error("Accepted report with max_release_stage later than in the metric")
}
m.MetaData.MaxReleaseStage = config.ReleaseStage_FISHFOOD
if err := validateMaxReleaseStage(m, r); err != nil {
t.Errorf("Rejected report with the same max_release_stage as the metric: %v", err)
}
m.MetaData.MaxReleaseStage = config.ReleaseStage_DOGFOOD
if err := validateMaxReleaseStage(m, r); err != nil {
t.Errorf("Rejected report with max_release_stage earlier than the metric: %v", err)
}
}
func TestValidateExemptFromConsent(t *testing.T) {
r := makeValidReportWithType(config.ReportDefinition_UNIQUE_DEVICE_COUNTS)
r.ExemptFromConsent = true
r.PrivacyLevel = config.ReportDefinition_NO_ADDED_PRIVACY
if err := validateExemptFromConsent(r); err == nil {
t.Error("Accepted report with no differential privacy and exempt_from_consent set")
}
r.PrivacyLevel = config.ReportDefinition_LOW_PRIVACY
if err := validateExemptFromConsent(r); err != nil {
t.Errorf("Rejected report with valid exempt_from_consent: %v", err)
}
}
func TestValidateMaxPrivateIndex(t *testing.T) {
m := makeValidMetric(config.MetricDefinition_OCCURRENCE)
r := makeValidReportWithType(config.ReportDefinition_UNIQUE_DEVICE_COUNTS)
r.PrivacyLevel = config.ReportDefinition_NO_ADDED_PRIVACY
if err := validateMaxPrivateIndex(m, r); err != nil {
t.Errorf("Rejected report with valid max private index: %v", err)
}
r.PrivacyLevel = config.ReportDefinition_HIGH_PRIVACY
if err := validateMaxPrivateIndex(m, r); err != nil {
t.Errorf("Rejected private UNIQUE_DEVICE_COUNTS report with valid max private index: %v", err)
}
m.MetricDimensions = append(m.MetricDimensions, &config.MetricDefinition_MetricDimension{
Dimension: "Dimension with lots of event codes",
MaxEventCode: math.MaxInt32 + 1, // > INT32_MAX
})
if err := validateMaxPrivateIndex(m, r); err == nil {
t.Error("Accepted private UNIQUE_DEVICE_COUNTS report with too many private indices")
}
m = makeValidMetric(config.MetricDefinition_OCCURRENCE)
m.MetricDimensions = append(m.MetricDimensions, &config.MetricDefinition_MetricDimension{
Dimension: "Dimension with lots of event codes",
MaxEventCode: 1000,
})
r = makeValidReportWithType(config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS)
r.PrivacyLevel = config.ReportDefinition_HIGH_PRIVACY
r.NumIndexPoints = 10
if err := validateMaxPrivateIndex(m, r); err != nil {
t.Errorf("Rejected private FLEETWIDE_OCCURRENCE_COUNTS report with valid max private index: %v", err)
}
r.NumIndexPoints = math.MaxInt32 / 10 // * 1,000 * 10 will be > INT32_MAX
if err := validateMaxPrivateIndex(m, r); err == nil {
t.Error("Accepted private FLEETWIDE_OCCURRENCE_COUNTS report with too many private indices")
}
m = makeValidMetric(config.MetricDefinition_INTEGER)
m.MetricDimensions = append(m.MetricDimensions, &config.MetricDefinition_MetricDimension{
Dimension: "Dimension with lots of event codes",
MaxEventCode: 1000,
})
r = makeValidReportWithType(config.ReportDefinition_FLEETWIDE_MEANS)
r.PrivacyLevel = config.ReportDefinition_HIGH_PRIVACY
r.NumIndexPoints = 10
if err := validateMaxPrivateIndex(m, r); err != nil {
t.Errorf("Rejected private FLEETWIDE_MEANS report with valid max private index: %v", err)
}
r.NumIndexPoints = math.MaxInt32 / 100 // * 1,000 * 10 will be > INT32_MAX
if err := validateMaxPrivateIndex(m, r); err == nil {
t.Error("Accepted private FLEETWIDE_MEANS report with too many private indices")
}
r = makeValidReportWithType(config.ReportDefinition_UNIQUE_DEVICE_HISTOGRAMS)
r.PrivacyLevel = config.ReportDefinition_HIGH_PRIVACY
r.IntBuckets = &config.IntegerBuckets{
Buckets: &config.IntegerBuckets_Linear{
Linear: &config.LinearIntegerBuckets{
NumBuckets: 1000,
},
},
}
if err := validateMaxPrivateIndex(m, r); err != nil {
t.Errorf("Rejected private UNIQUE_DEVICE_HISTOGRAMS report with valid max private index: %v", err)
}
r.IntBuckets.GetLinear().NumBuckets = 10000000 // 10,000,000 * 1,000 > INT32_MAX
if err := validateMaxPrivateIndex(m, r); err == nil {
t.Error("Accepted private UNIQUE_DEVICE_HISTOGRAMS report with too many private indices")
}
m = makeValidMetric(config.MetricDefinition_INTEGER_HISTOGRAM)
m.MetricDimensions = append(m.MetricDimensions, &config.MetricDefinition_MetricDimension{
Dimension: "Dimension with lots of event codes",
MaxEventCode: 1000,
})
m.IntBuckets = &config.IntegerBuckets{
Buckets: &config.IntegerBuckets_Linear{
Linear: &config.LinearIntegerBuckets{
NumBuckets: 1000,
},
},
}
r = makeValidReportWithType(config.ReportDefinition_FLEETWIDE_HISTOGRAMS)
r.PrivacyLevel = config.ReportDefinition_HIGH_PRIVACY
r.NumIndexPoints = 1000
if err := validateMaxPrivateIndex(m, r); err != nil {
t.Errorf("Rejected private FLEETWIDE_HISTOGRAMS report with valid max private index: %v", err)
}
m.IntBuckets.GetLinear().NumBuckets = 10000 // 10,000 * 1,000 * 1,000 > INT32_MAX
if err := validateMaxPrivateIndex(m, r); err == nil {
t.Error("Accepted private FLEETWIDE_HISTOGRAMS report with too many private indices")
}
m = makeValidMetric(config.MetricDefinition_STRING)
m.MetricDimensions = append(m.MetricDimensions, &config.MetricDefinition_MetricDimension{
Dimension: "Dimension with lots of event codes",
MaxEventCode: 1000,
})
r = makeValidReportWithType(config.ReportDefinition_STRING_COUNTS)
r.PrivacyLevel = config.ReportDefinition_HIGH_PRIVACY
if err := validateMaxPrivateIndex(m, r); err != nil {
t.Errorf("Rejected private STRING_COUNTS report with valid max private index: %v", err)
}
m.MetricDimensions = append(m.MetricDimensions, &config.MetricDefinition_MetricDimension{
Dimension: "Dimension with lots of event codes",
MaxEventCode: 1000000, // 1,000,000 * 1,000 * 50 (string count-min constants) will be > INT32_MAX
})
if err := validateMaxPrivateIndex(m, r); err == nil {
t.Error("Accepted private STRING_COUNTS report with too many private indices")
}
}
func TestValidateNoHourlyReports(t *testing.T) {
m := makeValidMetric(config.MetricDefinition_OCCURRENCE)
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_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 := validateNoHourlyReports(m, r); err != nil {
t.Errorf("Rejected daily report: %v", err)
}
}
for _, reportType := range hourlyReportTypes {
r := makeValidReportWithType(reportType)
if err := validateNoHourlyReports(m, r); err == nil {
t.Error("Accepted hourly report")
}
}
// Test FLEETWIDE_OCCURRENCE_COUNTS, which may define a non-hourly reporting
// interval.
r := makeValidReportWithType(config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS)
// Test unset reporting interval.
err := validateNoHourlyReports(m, r)
if err == nil {
t.Error("Accepted hourly FLEETWIDE_OCCURRENCE_COUNTS report with default reporting interval")
}
if !errors.Is(err, errIllegalHourlyReport) {
t.Errorf("Incorrect error return type: %v", err)
}
// Test HOURS_1 reporting interval.
r.ReportingInterval = config.ReportDefinition_HOURS_1
err = validateNoHourlyReports(m, r)
if err == nil {
t.Error("Accepted hourly FLEETWIDE_OCCURRENCE_COUNTS report with hourly reporting interval")
}
if !errors.Is(err, errIllegalHourlyReport) {
t.Errorf("Incorrect error return type: %v", err)
}
// Test DAYS_1 reporting interval.
r.ReportingInterval = config.ReportDefinition_DAYS_1
if err := validateNoHourlyReports(m, r); err != nil {
t.Errorf("Rejected daily FLEETWIDE_OCCURRENCE_COUNTS report with daily reporting interval: %v", err)
}
// Test STRING_COUNTS, which may define a non-hourly reporting
// interval.
r = makeValidReportWithType(config.ReportDefinition_STRING_COUNTS)
// Test unset reporting interval.
err = validateNoHourlyReports(m, r)
if err == nil {
t.Error("Accepted hourly STRING_COUNTS report with default reporting interval")
}
if !errors.Is(err, errIllegalHourlyReport) {
t.Errorf("Incorrect error return type: %v", err)
}
// Test HOURS_1 reporting interval.
r.ReportingInterval = config.ReportDefinition_HOURS_1
err = validateNoHourlyReports(m, r)
if err == nil {
t.Error("Accepted hourly STRING_COUNTS report with hourly reporting interval")
}
if !errors.Is(err, errIllegalHourlyReport) {
t.Errorf("Incorrect error return type: %v", err)
}
// Test DAYS_1 reporting interval.
r.ReportingInterval = config.ReportDefinition_DAYS_1
if err := validateNoHourlyReports(m, r); err != nil {
t.Errorf("Rejected daily STRING_COUNTS report with daily reporting interval: %v", err)
}
}
func TestValidateEnabledReportingInterval(t *testing.T) {
unsupportedReportTypes := []config.ReportDefinition_ReportType{
config.ReportDefinition_HOURLY_VALUE_HISTOGRAMS,
config.ReportDefinition_FLEETWIDE_HISTOGRAMS,
config.ReportDefinition_FLEETWIDE_MEANS,
config.ReportDefinition_HOURLY_VALUE_NUMERIC_STATS,
config.ReportDefinition_UNIQUE_DEVICE_COUNTS,
config.ReportDefinition_UNIQUE_DEVICE_HISTOGRAMS,
config.ReportDefinition_UNIQUE_DEVICE_NUMERIC_STATS,
config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS,
}
supportedReportTypes := []config.ReportDefinition_ReportType{
config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS,
config.ReportDefinition_STRING_COUNTS,
}
reportingIntervalValues := []config.ReportDefinition_ReportingInterval{
config.ReportDefinition_HOURS_1,
config.ReportDefinition_DAYS_1,
}
for _, reportType := range supportedReportTypes {
// Check supported report types.
r := makeValidReportWithType(reportType)
// Unset reporting interval is valid.
if err := validateReportingInterval(r, true); err != nil {
t.Errorf("Rejected report with no reporting interval set: %v", err)
}
// All reporting interval values are valid.
for _, reportingInterval := range reportingIntervalValues {
r.ReportingInterval = reportingInterval
if err := validateReportingInterval(r, true); err != nil {
t.Errorf("Rejected report with valid %v reporting interval set: %v", reportingInterval, err)
}
}
}
// Check unsupported report types.
for _, reportType := range unsupportedReportTypes {
r := makeValidReportWithType(reportType)
// Unset reporting interval is valid.
if err := validateReportingInterval(r, true); err != nil {
t.Errorf("Rejected report with no reporting interval set: %v", err)
}
// Only the unset reporting interval is allowed on non-supported report types.
for _, reportingInterval := range reportingIntervalValues {
r.ReportingInterval = reportingInterval
if err := validateReportingInterval(r, true); err == nil {
t.Errorf("No error returned for report type %v with reporting interval %v", r.ReportType, r.ReportingInterval)
}
}
}
}
func TestValidateDisabledReportingInterval(t *testing.T) {
allReportTypes := []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,
config.ReportDefinition_UNIQUE_DEVICE_COUNTS,
config.ReportDefinition_UNIQUE_DEVICE_HISTOGRAMS,
config.ReportDefinition_UNIQUE_DEVICE_NUMERIC_STATS,
config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS,
}
reportingIntervalValues := []config.ReportDefinition_ReportingInterval{
config.ReportDefinition_HOURS_1,
config.ReportDefinition_DAYS_1,
}
for _, reportType := range allReportTypes {
r := makeValidReportWithType(reportType)
// Unset reporting interval is valid.
if err := validateReportingInterval(r, false); err != nil {
t.Errorf("Rejected report with no reporting interval set: %v", err)
}
// Verify an error is returned when setting reporting interval when the feature is disabled.
for _, reportingInterval := range reportingIntervalValues {
r.ReportingInterval = reportingInterval
if err := validateReportingInterval(r, false); err == nil {
t.Errorf("No error returned for report type %v with reporting interval %v", r.ReportType, r.ReportingInterval)
}
}
}
}
// 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")
}
}
func TestValidatePrivacyMechanismAndConfig(t *testing.T) {
// Default valid metric uses DEBUG max_release_stage.
m := makeValidMetric(config.MetricDefinition_OCCURRENCE)
r := makeValidReportWithType(config.ReportDefinition_UNIQUE_DEVICE_COUNTS)
if err := validatePrivacyMechanismAndConfig(m, r); err != nil {
t.Errorf("Rejected report with no privacy mechanism: %v", err)
}
r.PrivacyMechanism = config.ReportDefinition_DE_IDENTIFICATION
if err := validatePrivacyMechanismAndConfig(m, r); err != nil {
t.Errorf("Rejected report with privacy mechanism DE_IDENTIFICATION: %v", err)
}
r.PrivacyMechanism = config.ReportDefinition_SHUFFLED_DIFFERENTIAL_PRIVACY
if err := validatePrivacyMechanismAndConfig(m, r); err == nil {
t.Errorf("Didn't rejected report with privacy mechanism SHUFFLED_DIFFERENTIAL_PRIVACY and empty config: %v", err)
}
r.PrivacyConfig = &config.ReportDefinition_ShuffledDp{
ShuffledDp: &config.ReportDefinition_ShuffledDifferentialPrivacyConfig{
Epsilon: 1,
Delta: 0.001,
ReportingThreshold: 10000,
PoissonMean: 1,
},
}
if err := validatePrivacyMechanismAndConfig(m, r); err != nil {
t.Errorf("Rejected report with privacy mechanism SHUFFLED_DIFFERENTIAL_PRIVACY and not empty config: %v", err)
}
}
func TestValidateShuffledDpReportPrivacy(t *testing.T) {
m := makeValidMetric(config.MetricDefinition_OCCURRENCE)
r := makeValidReportWithType(config.ReportDefinition_UNIQUE_DEVICE_COUNTS)
r.LocalAggregationProcedure = config.ReportDefinition_AT_LEAST_ONCE
r.PrivacyMechanism = config.ReportDefinition_SHUFFLED_DIFFERENTIAL_PRIVACY
r.PrivacyConfig = &config.ReportDefinition_ShuffledDp{
ShuffledDp: &config.ReportDefinition_ShuffledDifferentialPrivacyConfig{
Epsilon: 1,
Delta: 1e-10,
ReportingThreshold: 1000,
PoissonMean: 0.085937,
},
}
if err := validateReportPoissonMean(m, r); err != nil {
t.Errorf("Rejected report with valid privacy parameters with: %v", err)
}
r.PrivacyConfig.(*config.ReportDefinition_ShuffledDp).ShuffledDp.PoissonMean = 0.07
if err := validateReportPoissonMean(m, r); err == nil {
t.Error("Accepted report with invalid privacy parameters")
}
}
func TestValidateShuffledDpConfigWithValidConfig(t *testing.T) {
c := &config.ReportDefinition_ShuffledDifferentialPrivacyConfig{
Epsilon: 1,
Delta: 0.001,
ReportingThreshold: 10000,
PoissonMean: 1.0,
}
if err := validateShuffledDpConfig(c); err != nil {
t.Errorf("Rejected valid config: %v", err)
}
}
func TestValidateShuffledDpConfigWithInvalidEpsilon(t *testing.T) {
invalidEpsilons := [2]float64{-1, 0}
for _, e := range invalidEpsilons {
c := &config.ReportDefinition_ShuffledDifferentialPrivacyConfig{
Epsilon: e,
Delta: 0.001,
ReportingThreshold: 10000,
PoissonMean: 1,
}
if err := validateShuffledDpConfig(c); err == nil {
t.Errorf("Didn't reject config with invalid Epsilon: %f", e)
}
}
}
func TestValidateShuffledDpConfigWithInvalidDelta(t *testing.T) {
invalidDeltas := [4]float64{0, 1, 125, -1}
for _, d := range invalidDeltas {
c := &config.ReportDefinition_ShuffledDifferentialPrivacyConfig{
Epsilon: 1,
Delta: d,
ReportingThreshold: 10000,
}
if err := validateShuffledDpConfig(c); err == nil {
t.Errorf("Didn't reject config with invalid Delta: %f", d)
}
}
}
func TestValidateShuffledDpConfigWithInvalidReportingThreshold(t *testing.T) {
c := &config.ReportDefinition_ShuffledDifferentialPrivacyConfig{
Epsilon: 1,
Delta: 0.001,
ReportingThreshold: 0,
}
if err := validateShuffledDpConfig(c); err == nil {
t.Errorf("Didn't reject config with invalid ReportingThreshold: 0")
}
}
func TestValidateShuffledDpConfigWithInvalidPoissonMean(t *testing.T) {
invalidMeans := [4]float64{0, -1.0}
for _, pm := range invalidMeans {
c := &config.ReportDefinition_ShuffledDifferentialPrivacyConfig{
Epsilon: 1,
Delta: 0.01,
ReportingThreshold: 10000,
PoissonMean: pm,
}
if err := validateShuffledDpConfig(c); err == nil {
t.Errorf("Didn't reject config with invalid PoissonMean: %f", pm)
}
}
}
func TestValidateNewPrivacyFieldAndLegacyPrivacyFieldMatch(t *testing.T) {
// Default valid metric uses DEBUG max_release_stage.
r := makeValidReportWithType(config.ReportDefinition_UNIQUE_DEVICE_COUNTS)
if err := validateNewPrivacyFieldAndLegacyPrivacyFieldMatch(r); err != nil {
t.Errorf("Rejected report with matched privacy_level NO_ADDED_PRIVACY and privacy_mechanism DE_IDENTIFICATION: %v", err)
}
r.PrivacyLevel = config.ReportDefinition_LOW_PRIVACY
if err := validateNewPrivacyFieldAndLegacyPrivacyFieldMatch(r); err == nil {
t.Errorf("Didn't reject report with unmatched privacy_level LOW_PRIVACY and privacy_mechanism DE_IDENTIFICATION: %v", err)
}
r.PrivacyLevel = config.ReportDefinition_MEDIUM_PRIVACY
if err := validateNewPrivacyFieldAndLegacyPrivacyFieldMatch(r); err == nil {
t.Errorf("Didn't reject report with unmatched privacy_level MEDIUM_PRIVACY and privacy_mechanism DE_IDENTIFICATION: %v", err)
}
r.PrivacyLevel = config.ReportDefinition_HIGH_PRIVACY
if err := validateNewPrivacyFieldAndLegacyPrivacyFieldMatch(r); err == nil {
t.Errorf("Didn't reject report with unmatched privacy_level HIGH_PRIVACY and privacy_mechanism DE_IDENTIFICATION: %v", err)
}
r.PrivacyMechanism = config.ReportDefinition_SHUFFLED_DIFFERENTIAL_PRIVACY
r.PrivacyLevel = config.ReportDefinition_NO_ADDED_PRIVACY
if err := validateNewPrivacyFieldAndLegacyPrivacyFieldMatch(r); err == nil {
t.Errorf("Didn't reject report with unmatched privacy_level NO_ADDED_PRIVACY and privacy_mechanism SHUFFLED_DIFFERENTIAL_PRIVACY: %v", err)
}
r.PoissonMean = 1
r.ReportingThreshold = 10000
r.PrivacyConfig = &config.ReportDefinition_ShuffledDp{
ShuffledDp: &config.ReportDefinition_ShuffledDifferentialPrivacyConfig{
Epsilon: 1,
Delta: 0.001,
ReportingThreshold: 10000,
PoissonMean: 1,
},
}
r.PrivacyLevel = config.ReportDefinition_LOW_PRIVACY
if err := validateNewPrivacyFieldAndLegacyPrivacyFieldMatch(r); err != nil {
t.Errorf("Rejected report with matched privacy_level LOW_PRIVACY and privacy_mechanism SHUFFLED_DIFFERENTIAL_PRIVACY: %v", err)
}
r.PrivacyLevel = config.ReportDefinition_MEDIUM_PRIVACY
if err := validateNewPrivacyFieldAndLegacyPrivacyFieldMatch(r); err != nil {
t.Errorf("Rejected report with matched privacy_level MEDIUM_PRIVACY and privacy_mechanism SHUFFLED_DIFFERENTIAL_PRIVACY: %v", err)
}
r.PrivacyLevel = config.ReportDefinition_HIGH_PRIVACY
if err := validateNewPrivacyFieldAndLegacyPrivacyFieldMatch(r); err != nil {
t.Errorf("Rejected report with matched privacy_level HIGH_PRIVACY and privacy_mechanism SHUFFLED_DIFFERENTIAL_PRIVACY: %v", err)
}
r.PoissonMean = 0.1
if err := validateNewPrivacyFieldAndLegacyPrivacyFieldMatch(r); err == nil {
t.Errorf("Didn't Rejected report with unmatched poisson_mean and shuffled_dp possion_mean: %v", err)
}
r.PoissonMean = 1
r.ReportingThreshold = 1
if err := validateNewPrivacyFieldAndLegacyPrivacyFieldMatch(r); err == nil {
t.Errorf("Didn't Rejected report with unmatched reporting_threshold and shuffled_dp reporting_threshold: %v", err)
}
}