blob: 2b9c715b2df426e74baab8fa472d2f516d7ea348 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/attribution_reporting/aggregatable_attribution_utils.h"
#include <stdint.h>
#include <string>
#include <utility>
#include <vector>
#include "base/test/metrics/histogram_tester.h"
#include "base/time/time.h"
#include "base/values.h"
#include "components/aggregation_service/aggregation_service.mojom.h"
#include "components/attribution_reporting/aggregatable_trigger_data.h"
#include "components/attribution_reporting/aggregatable_values.h"
#include "components/attribution_reporting/aggregation_keys.h"
#include "components/attribution_reporting/filters.h"
#include "components/attribution_reporting/source_type.mojom.h"
#include "content/browser/attribution_reporting/aggregatable_histogram_contribution.h"
#include "content/browser/attribution_reporting/attribution_report.h"
#include "content/browser/attribution_reporting/attribution_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/numeric/int128.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace content {
namespace {
using ::attribution_reporting::FilterPair;
using ::attribution_reporting::mojom::SourceType;
using ::testing::ElementsAre;
using AttributionFilters = ::attribution_reporting::Filters;
} // namespace
TEST(AggregatableAttributionUtilsTest, CreateAggregatableHistogram) {
base::HistogramTester histograms;
auto source = attribution_reporting::AggregationKeys::FromKeys(
{{"key1", 345}, {"key2", 5}, {"key3", 123}});
ASSERT_TRUE(source.has_value());
std::vector<attribution_reporting::AggregatableTriggerData>
aggregatable_trigger_data{
// The first trigger data applies to "key1", "key3".
*attribution_reporting::AggregatableTriggerData::Create(
absl::MakeUint128(/*high=*/0, /*low=*/1024),
/*source_keys=*/{"key1", "key3"},
FilterPair{.positive =
AttributionFilters({{{"filter", {"value"}}}})}),
// The second trigger data applies to "key2", "key4" is ignored.
*attribution_reporting::AggregatableTriggerData::Create(
absl::MakeUint128(/*high=*/0, /*low=*/2688),
/*source_keys=*/{"key2", "key4"},
FilterPair{.positive =
AttributionFilters({{{"a", {"b", "c"}}}})}),
// The third trigger will be ignored due to mismatched filters.
*attribution_reporting::AggregatableTriggerData::Create(
absl::MakeUint128(/*high=*/0, /*low=*/4096),
/*source_keys=*/{"key1", "key2"},
FilterPair{.positive = AttributionFilters({{{"filter", {}}}})}),
// The fourth trigger will be ignored due to matched not_filters.
*attribution_reporting::AggregatableTriggerData::Create(
absl::MakeUint128(/*high=*/0, /*low=*/4096),
/*source_keys=*/{"key1", "key2"},
FilterPair{.negative =
AttributionFilters({{{"filter", {"value"}}}})})};
absl::optional<attribution_reporting::FilterData> source_filter_data =
attribution_reporting::FilterData::Create({{"filter", {"value"}}});
ASSERT_TRUE(source_filter_data.has_value());
auto aggregatable_values = *attribution_reporting::AggregatableValues::Create(
{{"key1", 32768}, {"key2", 1664}});
std::vector<AggregatableHistogramContribution> contributions =
CreateAggregatableHistogram(*source_filter_data, SourceType::kEvent,
*source, std::move(aggregatable_trigger_data),
aggregatable_values);
// "key3" is not present as no value is found.
EXPECT_THAT(
contributions,
ElementsAre(
AggregatableHistogramContribution(/*key=*/1369, /*value=*/32768u),
AggregatableHistogramContribution(/*key=*/2693, /*value=*/1664u)));
histograms.ExpectUniqueSample(
"Conversions.AggregatableReport.FilteredTriggerDataPercentage", 50, 1);
histograms.ExpectUniqueSample(
"Conversions.AggregatableReport.DroppedKeysPercentage", 33, 1);
histograms.ExpectUniqueSample(
"Conversions.AggregatableReport.NumContributionsPerReport", 2, 1);
}
TEST(AggregatableAttributionUtilsTest,
NoTriggerData_FilteredPercentageNotRecorded) {
base::HistogramTester histograms;
auto source =
attribution_reporting::AggregationKeys::FromKeys({{"key1", 345}});
ASSERT_TRUE(source.has_value());
std::vector<AggregatableHistogramContribution> contributions =
CreateAggregatableHistogram(
attribution_reporting::FilterData(), SourceType::kNavigation, *source,
/*aggregatable_trigger_data=*/{},
/*aggregatable_values=*/
*attribution_reporting::AggregatableValues::Create(
{{"key2", 32768}}));
histograms.ExpectTotalCount(
"Conversions.AggregatableReport.FilteredTriggerDataPercentage", 0);
histograms.ExpectUniqueSample(
"Conversions.AggregatableReport.DroppedKeysPercentage", 100, 1);
histograms.ExpectUniqueSample(
"Conversions.AggregatableReport.NumContributionsPerReport", 0, 1);
}
TEST(AggregatableAttributionUtilsTest, RoundsSourceRegistrationTime) {
const struct {
std::string description;
int64_t source_time;
std::string expected_serialized_time;
} kTestCases[] = {
{"14288 * 86400000", 1234483200000, "1234483200"},
{"14288 * 86400000 + 1", 1234483200001, "1234483200"},
{"14288.5 * 86400000 - 1", 1234526399999, "1234483200"},
{"14288.5 * 86400000", 1234526400000, "1234483200"},
{"14288.5 * 86400000 + 1", 1234526400001, "1234483200"},
{"14289 * 86400000 -1", 1234569599999, "1234483200"},
{"14289 * 86400000", 1234569600000, "1234569600"},
};
for (const auto& test_case : kTestCases) {
base::Time source_time = base::Time::FromJavaTime(test_case.source_time);
AttributionReport report =
ReportBuilder(
AttributionInfoBuilder(SourceBuilder(source_time).BuildStored())
.Build())
.SetAggregatableHistogramContributions(
{AggregatableHistogramContribution(/*key=*/1, /*value=*/2)})
.BuildAggregatableAttribution();
absl::optional<AggregatableReportRequest> request =
CreateAggregatableReportRequest(report);
ASSERT_TRUE(request.has_value());
const base::Value::Dict& additional_fields =
request->shared_info().additional_fields;
const std::string* actual_serialized_time =
additional_fields.FindString("source_registration_time");
ASSERT_TRUE(actual_serialized_time);
EXPECT_EQ(*actual_serialized_time, test_case.expected_serialized_time)
<< test_case.description;
}
}
TEST(AggregatableAttributionUtilsTest, AggregationCoordinatorSet) {
for (auto aggregation_coordinator :
{::aggregation_service::mojom::AggregationCoordinator::kAwsCloud}) {
AttributionReport report =
ReportBuilder(
AttributionInfoBuilder(SourceBuilder().BuildStored()).Build())
.SetAggregatableHistogramContributions(
{AggregatableHistogramContribution(/*key=*/1, /*value=*/2)})
.SetAggregationCoordinator(aggregation_coordinator)
.BuildAggregatableAttribution();
absl::optional<AggregatableReportRequest> request =
CreateAggregatableReportRequest(report);
ASSERT_TRUE(request.has_value()) << aggregation_coordinator;
EXPECT_EQ(request->payload_contents().aggregation_coordinator,
aggregation_coordinator)
<< aggregation_coordinator;
}
}
} // namespace content