blob: 96700adc0ea175a20562709283a35de3ac7e5396 [file] [log] [blame]
// Copyright 2020 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 privacy
import (
"config"
"testing"
"github.com/golang/glog"
)
// The try-bots expect glog to be imported, but we do not use it.
var _ = glog.Info
var metric = config.MetricDefinition{
EventCodeBufferMax: 5,
}
func TestEstimateWithEpsilon(t *testing.T) {
privacyParamsCalculator, err := NewPrivacyEncodingParamsCalculatorForTesting(testParamRecords)
if err != nil {
t.Fatal("Failed to create PrivacyEncodingParamsCalculator")
}
errorCalculator := NewErrorCalculator(*privacyParamsCalculator)
testMetric := config.MetricDefinition{
MetricName: "Occurrence",
MetricType: config.MetricDefinition_OCCURRENCE,
}
uniqueDeviceCount := config.ReportDefinition{
ReportName: "UniqueDeviceCounts",
ReportType: config.ReportDefinition_UNIQUE_DEVICE_COUNTS,
LocalAggregationProcedure: config.ReportDefinition_SELECT_FIRST,
}
uniqueDeviceHistogram := config.ReportDefinition{
ReportName: "UniqueDeviceHistograms",
ReportType: config.ReportDefinition_UNIQUE_DEVICE_HISTOGRAMS,
LocalAggregationProcedure: config.ReportDefinition_SELECT_FIRST,
}
hourlyValueHistogram := config.ReportDefinition{
ReportName: "HourlyValueHistograms",
ReportType: config.ReportDefinition_HOURLY_VALUE_HISTOGRAMS,
LocalAggregationProcedure: config.ReportDefinition_SELECT_FIRST,
}
fleetwideOccurrenceCount := config.ReportDefinition{
ReportName: "FleetwideOccurrenceCounts",
ReportType: config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS,
LocalAggregationProcedure: config.ReportDefinition_SELECT_FIRST,
MaxValue: 5,
MinValue: 1,
}
fleetwideOccurrenceCountHighMax := config.ReportDefinition{
ReportName: "FleetwideOccurrenceCountsWithHighMaxValue",
ReportType: config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS,
LocalAggregationProcedure: config.ReportDefinition_SELECT_FIRST,
MaxValue: 20,
MinValue: 1,
}
fleetwideOccurrenceCountNegativeValue := config.ReportDefinition{
ReportName: "FleetwideOccurrenceCountsNegativeValue",
ReportType: config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS,
LocalAggregationProcedure: config.ReportDefinition_SELECT_FIRST,
MaxValue: -1,
MinValue: -5,
}
fleetwideHistogram := config.ReportDefinition{
ReportName: "FleetwideHistograms",
ReportType: config.ReportDefinition_FLEETWIDE_HISTOGRAMS,
LocalAggregationProcedure: config.ReportDefinition_SELECT_FIRST,
MaxCount: 5,
}
fleetwideHistogramHighMax := config.ReportDefinition{
ReportName: "FleetwideHistogramsWithHighMaxCount",
ReportType: config.ReportDefinition_FLEETWIDE_HISTOGRAMS,
LocalAggregationProcedure: config.ReportDefinition_SELECT_FIRST,
MaxCount: 20,
}
// uniqueDeviceNumericStats := config.ReportDefinition{
// ReportName: "UniqueDeviceNumericStats",
// ReportType: config.ReportDefinition_UNIQUE_DEVICE_NUMERIC_STATS,
// MaxValue: 1,
// }
// hourlyValueNumericStats := config.ReportDefinition{
// ReportName: "HourlyDeviceNumericStats",
// ReportType: config.ReportDefinition_HOURLY_VALUE_NUMERIC_STATS,
// MaxValue: 1,
// }
// uniqueDeviceNumericStatsMissingMaxValue := config.ReportDefinition{
// ReportName: "UniqueDeviceNumericStatsMissingMaxValue",
// ReportType: config.ReportDefinition_UNIQUE_DEVICE_NUMERIC_STATS,
// }
fleetwideMeans := config.ReportDefinition{
ReportName: "FleetwideMeans",
ReportType: config.ReportDefinition_FLEETWIDE_MEANS,
MinValue: 0,
MaxValue: 5,
MaxCount: 5,
}
fleetwideMeansHighMaxCount := config.ReportDefinition{
ReportName: "FleetwideMeansHighMaxCount",
ReportType: config.ReportDefinition_FLEETWIDE_MEANS,
MinValue: 0,
MaxValue: 5,
MaxCount: 20,
}
fleetwideMeansMissingMaxValue := config.ReportDefinition{
ReportName: "FleetwideMeansMissingMaxValue",
ReportType: config.ReportDefinition_FLEETWIDE_MEANS,
}
unsupportedReport := config.ReportDefinition{
ReportName: "UnsupportedReport",
}
type args struct {
metric *config.MetricDefinition
report *config.ReportDefinition
epsilon float64
population uint64
minDenominatorEstimate uint64
}
var tests = []struct {
input args
valid bool
expected float64
}{
// Single contribution reports
{args{&testMetric, &uniqueDeviceCount, 1, 10000, 0}, true, 4.935511431266572},
{args{&testMetric, &uniqueDeviceCount, 10, 10000, 0}, true, 3.014414887122711},
{args{&testMetric, &uniqueDeviceCount, 1, 20000, 0}, true, 6.979867203344631},
{args{&testMetric, &uniqueDeviceHistogram, 1, 10000, 0}, true, 4.935511431266572},
{args{&testMetric, &uniqueDeviceHistogram, 10, 10000, 0}, true, 3.014414887122711},
{args{&testMetric, &uniqueDeviceHistogram, 1, 20000, 0}, true, 6.979867203344631},
{args{&testMetric, &hourlyValueHistogram, 1, 10000, 0}, true, 24.178969252553177},
{args{&testMetric, &hourlyValueHistogram, 10, 10000, 0}, true, 14.767556692999985},
{args{&testMetric, &hourlyValueHistogram, 1, 20000, 0}, true, 34.19422624116276},
// Multi-contribution reports
{args{&testMetric, &fleetwideOccurrenceCount, 1, 10000, 0}, true, 211.57489543860999},
{args{&testMetric, &fleetwideOccurrenceCount, 10, 10000, 0}, true, 149.7228828879947},
{args{&testMetric, &fleetwideOccurrenceCount, 1, 20000, 0}, true, 299.2120865869517},
{args{&testMetric, &fleetwideOccurrenceCountHighMax, 1, 10000, 0}, true, 1004.9807533333975},
{args{&testMetric, &fleetwideOccurrenceCountNegativeValue, 1, 10000, 0}, true, 211.57489543860999},
{args{&testMetric, &fleetwideHistogram, 1, 10000, 0}, true, 264.4686192982625},
{args{&testMetric, &fleetwideHistogram, 10, 10000, 0}, true, 187.15360360999338},
{args{&testMetric, &fleetwideHistogram, 1, 20000, 0}, true, 374.0151082336897},
{args{&testMetric, &fleetwideHistogramHighMax, 1, 10000, 0}, true, 1057.87447719305},
// Mean reports
// {args{&testMetric, &uniqueDeviceNumericStats, 1, 10000, 500}, true, 0.027891803930152177},
// {args{&testMetric, &uniqueDeviceNumericStats, 10, 10000, 500}, true, 0.018650077285590205},
// {args{&testMetric, &uniqueDeviceNumericStats, 1, 20000, 500}, true, 0.039654432133364455},
// {args{&testMetric, &uniqueDeviceNumericStats, 1, 10000, 2000}, true, 0.006907368191507632},
// {args{&testMetric, &hourlyValueNumericStats, 1, 10000, 500}, true, 0.14403990551821316},
// {args{&testMetric, &hourlyValueNumericStats, 10, 10000, 500}, true, 0.09424308127635954},
// {args{&testMetric, &hourlyValueNumericStats, 1, 20000, 500}, true, 0.20996453488325503},
// {args{&testMetric, &hourlyValueNumericStats, 1, 10000, 2000}, true, 0.03425744055252169},
{args{&testMetric, &fleetwideMeans, 1, 10000, 500}, true, 1034.0131324817698},
{args{&testMetric, &fleetwideMeans, 10, 10000, 500}, true, 426.22967217469716},
{args{&testMetric, &fleetwideMeans, 1, 20000, 500}, true, 1619.5676003943095},
{args{&testMetric, &fleetwideMeans, 1, 10000, 2000}, true, 1.4456690853472534},
{args{&testMetric, &fleetwideMeansHighMaxCount, 1, 10000, 500}, true, 2373.764851498005},
{args{&testMetric, &fleetwideMeansHighMaxCount, 10, 10000, 500}, true, 2239.957602630985},
{args{&testMetric, &fleetwideMeansHighMaxCount, 1, 20000, 500}, true, 2453.988452255676},
{args{&testMetric, &fleetwideMeansHighMaxCount, 1, 10000, 2000}, true, 4098.700976333229},
// Invalid input
// {args{&testMetric, &uniqueDeviceNumericStats, 1, 10000, 0}, false, 0},
// {args{&testMetric, &hourlyValueNumericStats, 1, 10000, 0}, false, 0},
// {args{&testMetric, &uniqueDeviceNumericStatsMissingMaxValue, 1, 10000, 500}, false, 0},
{args{&testMetric, &fleetwideMeansMissingMaxValue, 1, 10000, 500}, false, 0},
// This report type is not currently supported.
{args{&testMetric, &unsupportedReport, 1, 10000, 0}, false, 0},
}
for _, test := range tests {
input := test.input
result, err := errorCalculator.Estimate(input.metric, input.report, input.epsilon, input.population, input.minDenominatorEstimate)
if test.valid && err != nil {
t.Errorf("Estimate failed for report %v: %v", input.report.ReportName, err)
} else if !test.valid && err == nil {
t.Errorf("Estimate accepted invalid report: %v", input.report.ReportName)
} else if test.valid && result != test.expected {
t.Errorf("Estimate for report %v (epsilon: %v, population: %v, minDenominator: %v): expected %v, got %v", input.report.ReportName, input.epsilon, input.population, input.minDenominatorEstimate, test.expected, result)
}
}
}