blob: 89df399cd2c8a5e76d0b2123c8669e38d1f791f5 [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,
MaxCount: 1,
}
fleetwideOccurrenceCountHighMax := config.ReportDefinition{
ReportName: "FleetwideOccurrenceCountsWithHighMaxCount",
ReportType: config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS,
LocalAggregationProcedure: config.ReportDefinition_SELECT_FIRST,
MaxCount: 4,
}
fleetwideHistogram := config.ReportDefinition{
ReportName: "FleetwideHistograms",
ReportType: config.ReportDefinition_FLEETWIDE_HISTOGRAMS,
LocalAggregationProcedure: config.ReportDefinition_SELECT_FIRST,
}
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,
MaxValue: 1,
MaxCount: 1,
}
fleetwideMeansHighMaxCount := config.ReportDefinition{
ReportName: "FleetwideMeansHighMaxCount",
ReportType: config.ReportDefinition_FLEETWIDE_MEANS,
MaxValue: 1,
MaxCount: 4,
}
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, 52.893723859652496},
{args{&testMetric, &fleetwideOccurrenceCount, 10, 10000, 0}, true, 37.430720721998675},
{args{&testMetric, &fleetwideOccurrenceCount, 1, 20000, 0}, true, 74.80302164673793},
{args{&testMetric, &fleetwideOccurrenceCountHighMax, 1, 10000, 0}, true, 211.57489543860999},
{args{&testMetric, &fleetwideHistogram, 1, 10000, 0}, true, 52.893723859652496},
{args{&testMetric, &fleetwideHistogram, 10, 10000, 0}, true, 37.430720721998675},
{args{&testMetric, &fleetwideHistogram, 1, 20000, 0}, true, 74.80302164673793},
// 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, 0.14403990551821316},
{args{&testMetric, &fleetwideMeans, 10, 10000, 500}, true, 0.09424308127635954},
{args{&testMetric, &fleetwideMeans, 1, 20000, 500}, true, 0.20996453488325503},
{args{&testMetric, &fleetwideMeans, 1, 10000, 2000}, true, 0.03425744055252169},
{args{&testMetric, &fleetwideMeansHighMaxCount, 1, 10000, 500}, true, 14.67564563395404},
{args{&testMetric, &fleetwideMeansHighMaxCount, 10, 10000, 500}, true, 0.3612570115350953},
{args{&testMetric, &fleetwideMeansHighMaxCount, 1, 20000, 500}, true, 86.18119817858194},
{args{&testMetric, &fleetwideMeansHighMaxCount, 1, 10000, 2000}, true, 0.11189363618734707},
// Invalid input
// Mean Report missing minDenominatorEstimate
{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)
}
}
}