910e62b5创建于 1月15日历史提交
// Copyright 2020 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/attribution_test_utils.h"

#include <stdint.h>

#include <algorithm>
#include <optional>
#include <tuple>
#include <utility>
#include <variant>
#include <vector>

#include "base/check.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
#include "components/attribution_reporting/aggregatable_debug_reporting_config.h"
#include "components/attribution_reporting/aggregatable_dedup_key.h"
#include "components/attribution_reporting/aggregatable_filtering_id_max_bytes.h"
#include "components/attribution_reporting/aggregatable_named_budget_candidate.h"
#include "components/attribution_reporting/aggregatable_named_budget_defs.h"
#include "components/attribution_reporting/aggregatable_trigger_config.h"
#include "components/attribution_reporting/aggregatable_trigger_data.h"
#include "components/attribution_reporting/aggregatable_values.h"
#include "components/attribution_reporting/attribution_scopes_data.h"
#include "components/attribution_reporting/constants.h"
#include "components/attribution_reporting/destination_set.h"
#include "components/attribution_reporting/event_report_windows.h"
#include "components/attribution_reporting/event_trigger_data.h"
#include "components/attribution_reporting/filters.h"
#include "components/attribution_reporting/max_event_level_reports.h"
#include "components/attribution_reporting/os_registration.h"
#include "components/attribution_reporting/source_type.mojom.h"
#include "components/attribution_reporting/suitable_origin.h"
#include "components/attribution_reporting/test_utils.h"
#include "components/attribution_reporting/trigger_config.h"
#include "components/attribution_reporting/trigger_data_matching.mojom-forward.h"
#include "components/attribution_reporting/trigger_registration.h"
#include "content/browser/attribution_reporting/aggregatable_attribution_utils.h"
#include "content/browser/attribution_reporting/aggregatable_named_budget_pair.h"
#include "content/browser/attribution_reporting/attribution_observer.h"
#include "content/browser/attribution_reporting/attribution_reporting.mojom.h"
#include "content/browser/attribution_reporting/attribution_trigger.h"
#include "content/browser/attribution_reporting/attribution_utils.h"
#include "content/browser/attribution_reporting/os_registration.h"
#include "content/browser/attribution_reporting/rate_limit_result.h"
#include "content/browser/attribution_reporting/send_result.h"
#include "content/browser/attribution_reporting/stored_source.h"
#include "content/public/browser/attribution_data_model.h"
#include "net/base/net_errors.h"
#include "net/base/schemeful_site.h"
#include "net/http/structured_headers.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/functional/overload.h"
#include "third_party/abseil-cpp/absl/numeric/int128.h"
#include "url/gurl.h"
#include "url/origin.h"

namespace content {

namespace {

using ::attribution_reporting::FilterPair;
using ::attribution_reporting::OsRegistrationItem;
using ::attribution_reporting::SuitableOrigin;
using ::attribution_reporting::mojom::SourceType;

const char kDefaultSourceOrigin[] = "https://impression.test/";
const char kDefaultDestinationOrigin[] = "https://sub.conversion.test/";
const char kDefaultReportOrigin[] = "https://report.test/";

}  // namespace

base::Uuid DefaultExternalReportID() {
  return base::Uuid::ParseLowercase("21abd97f-73e8-4b88-9389-a9fee6abda5e");
}

// Builds an impression with default values. This is done as a builder because
// all values needed to be provided at construction time.
SourceBuilder::SourceBuilder(base::Time time)
    : source_time_(time),
      source_origin_(*SuitableOrigin::Deserialize(kDefaultSourceOrigin)),
      registration_(*attribution_reporting::DestinationSet::Create(
          {net::SchemefulSite::Deserialize(kDefaultDestinationOrigin)})),
      reporting_origin_(*SuitableOrigin::Deserialize(kDefaultReportOrigin)) {
  registration_.source_event_id = 123;
  registration_.trigger_data =
      attribution_reporting::TriggerDataSet(source_type_);
  registration_.max_event_level_reports =
      attribution_reporting::MaxEventLevelReports::Max();
}

SourceBuilder::~SourceBuilder() = default;

SourceBuilder::SourceBuilder(const SourceBuilder&) = default;

SourceBuilder::SourceBuilder(SourceBuilder&&) = default;

SourceBuilder& SourceBuilder::operator=(const SourceBuilder&) = default;

SourceBuilder& SourceBuilder::operator=(SourceBuilder&&) = default;

SourceBuilder& SourceBuilder::SetExpiry(base::TimeDelta delta) {
  registration_.expiry = delta;
  return *this;
}

SourceBuilder& SourceBuilder::SetAggregatableReportWindow(
    base::TimeDelta delta) {
  registration_.aggregatable_report_window = delta;
  return *this;
}

SourceBuilder& SourceBuilder::SetSourceEventId(uint64_t source_event_id) {
  registration_.source_event_id = source_event_id;
  return *this;
}

SourceBuilder& SourceBuilder::SetSourceOrigin(SuitableOrigin origin) {
  source_origin_ = std::move(origin);
  return *this;
}

SourceBuilder& SourceBuilder::SetDestinationSites(
    base::flat_set<net::SchemefulSite> sites) {
  registration_.destination_set =
      *attribution_reporting::DestinationSet::Create(std::move(sites));
  return *this;
}

SourceBuilder& SourceBuilder::SetReportingOrigin(SuitableOrigin origin) {
  reporting_origin_ = std::move(origin);
  return *this;
}

SourceBuilder& SourceBuilder::SetSourceType(SourceType source_type) {
  source_type_ = source_type;
  registration_.trigger_data =
      attribution_reporting::TriggerDataSet(source_type_);
  registration_.max_event_level_reports =
      attribution_reporting::MaxEventLevelReports(source_type);
  return *this;
}

SourceBuilder& SourceBuilder::SetPriority(int64_t priority) {
  registration_.priority = priority;
  return *this;
}

SourceBuilder& SourceBuilder::SetFilterData(
    attribution_reporting::FilterData filter_data) {
  registration_.filter_data = std::move(filter_data);
  return *this;
}

SourceBuilder& SourceBuilder::SetDebugKey(std::optional<uint64_t> debug_key) {
  registration_.debug_key = debug_key;
  return *this;
}

SourceBuilder& SourceBuilder::SetAttributionLogic(
    StoredSource::AttributionLogic attribution_logic) {
  attribution_logic_ = attribution_logic;
  return *this;
}

SourceBuilder& SourceBuilder::SetActiveState(
    StoredSource::ActiveState active_state) {
  active_state_ = active_state;
  return *this;
}

SourceBuilder& SourceBuilder::SetSourceId(StoredSource::Id source_id) {
  source_id_ = source_id;
  return *this;
}

SourceBuilder& SourceBuilder::SetDedupKeys(std::vector<uint64_t> dedup_keys) {
  dedup_keys_ = std::move(dedup_keys);
  return *this;
}

SourceBuilder& SourceBuilder::SetAggregationKeys(
    attribution_reporting::AggregationKeys aggregation_keys) {
  registration_.aggregation_keys = std::move(aggregation_keys);
  return *this;
}

SourceBuilder& SourceBuilder::SetRemainingAggregatableAttributionBudget(
    int remaining_aggregatable_attribution_budget) {
  remaining_aggregatable_attribution_budget_ =
      remaining_aggregatable_attribution_budget;
  return *this;
}

SourceBuilder& SourceBuilder::SetRemainingAggregatableDebugBudget(
    int remaining_aggregatable_debug_budget) {
  remaining_aggregatable_debug_budget_ = remaining_aggregatable_debug_budget;
  return *this;
}

SourceBuilder& SourceBuilder::SetRandomizedResponseRate(
    double randomized_response_rate) {
  randomized_response_rate_ = randomized_response_rate;
  return *this;
}

SourceBuilder& SourceBuilder::SetAggregatableDedupKeys(
    std::vector<uint64_t> dedup_keys) {
  aggregatable_dedup_keys_ = std::move(dedup_keys);
  return *this;
}

SourceBuilder& SourceBuilder::SetIsWithinFencedFrame(
    bool is_within_fenced_frame) {
  is_within_fenced_frame_ = is_within_fenced_frame;
  return *this;
}

SourceBuilder& SourceBuilder::SetDebugReporting(bool debug_reporting) {
  registration_.debug_reporting = debug_reporting;
  return *this;
}

SourceBuilder& SourceBuilder::SetTriggerData(
    attribution_reporting::TriggerDataSet trigger_data) {
  registration_.trigger_data = std::move(trigger_data);
  return *this;
}

SourceBuilder& SourceBuilder::SetEventReportWindows(
    attribution_reporting::EventReportWindows event_report_windows) {
  registration_.event_report_windows = std::move(event_report_windows);
  return *this;
}

SourceBuilder& SourceBuilder::SetMaxEventLevelReports(
    int max_event_level_reports) {
  registration_.max_event_level_reports =
      attribution_reporting::MaxEventLevelReports(max_event_level_reports);
  return *this;
}

SourceBuilder& SourceBuilder::SetTriggerDataMatching(
    attribution_reporting::mojom::TriggerDataMatching trigger_data_matching) {
  registration_.trigger_data_matching = trigger_data_matching;
  return *this;
}

SourceBuilder& SourceBuilder::SetCookieBasedDebugAllowed(
    bool cookie_based_debug_allowed) {
  cookie_based_debug_allowed_ = cookie_based_debug_allowed;
  return *this;
}

SourceBuilder& SourceBuilder::SetAggregatableDebugReportingConfig(
    attribution_reporting::SourceAggregatableDebugReportingConfig
        aggregatable_debug_reporting_config) {
  registration_.aggregatable_debug_reporting_config =
      std::move(aggregatable_debug_reporting_config);
  return *this;
}

SourceBuilder& SourceBuilder::SetDestinationLimitPriority(int64_t priority) {
  registration_.destination_limit_priority = priority;
  return *this;
}

SourceBuilder& SourceBuilder::SetAttributionScopesData(
    attribution_reporting::AttributionScopesData attribution_scopes) {
  registration_.attribution_scopes_data = std::move(attribution_scopes);
  return *this;
}

SourceBuilder& SourceBuilder::SetAggregatableNamedBudgetDefs(
    attribution_reporting::AggregatableNamedBudgetDefs budgets) {
  registration_.aggregatable_named_budget_defs = std::move(budgets);
  return *this;
}

StorableSource SourceBuilder::Build() const {
  StorableSource source(reporting_origin_, registration_, source_origin_,
                        source_type_, is_within_fenced_frame_,
                        ukm::kInvalidSourceId);
  source.set_cookie_based_debug_allowed(cookie_based_debug_allowed_);
  return source;
}

StoredSource SourceBuilder::BuildStored() const {
  base::Time expiry_time = source_time_ + registration_.expiry;
  StoredSource::AggregatableNamedBudgets named_budgets =
      ConvertNamedBudgetsMap(registration_.aggregatable_named_budget_defs);
  StoredSource source = *StoredSource::Create(
      CommonSourceInfo(source_origin_, reporting_origin_, source_type_,
                       cookie_based_debug_allowed_),
      registration_.source_event_id, registration_.destination_set,
      source_time_, expiry_time, registration_.trigger_data,
      registration_.event_report_windows, registration_.max_event_level_reports,
      source_time_ + registration_.aggregatable_report_window,
      registration_.priority, registration_.filter_data,
      registration_.debug_key, registration_.aggregation_keys,
      attribution_logic_, active_state_, source_id_,
      remaining_aggregatable_attribution_budget_, randomized_response_rate_,
      registration_.trigger_data_matching, registration_.event_level_epsilon,
      registration_.aggregatable_debug_reporting_config.config().key_piece,
      remaining_aggregatable_debug_budget_,
      registration_.attribution_scopes_data, named_budgets);
  source.dedup_keys() = dedup_keys_;
  source.aggregatable_dedup_keys() = aggregatable_dedup_keys_;
  return source;
}

AttributionTrigger DefaultTrigger() {
  return TriggerBuilder().Build();
}

TriggerBuilder::TriggerBuilder()
    : destination_origin_(
          *SuitableOrigin::Deserialize(kDefaultDestinationOrigin)),
      reporting_origin_(*SuitableOrigin::Deserialize(kDefaultReportOrigin)) {}

TriggerBuilder::~TriggerBuilder() = default;

TriggerBuilder::TriggerBuilder(const TriggerBuilder&) = default;

TriggerBuilder::TriggerBuilder(TriggerBuilder&&) = default;

TriggerBuilder& TriggerBuilder::operator=(const TriggerBuilder&) = default;

TriggerBuilder& TriggerBuilder::operator=(TriggerBuilder&&) = default;

TriggerBuilder& TriggerBuilder::SetTriggerData(uint64_t trigger_data) {
  trigger_data_ = trigger_data;
  return *this;
}

TriggerBuilder& TriggerBuilder::SetDestinationOrigin(SuitableOrigin origin) {
  destination_origin_ = std::move(origin);
  return *this;
}

TriggerBuilder& TriggerBuilder::SetReportingOrigin(SuitableOrigin origin) {
  reporting_origin_ = std::move(origin);
  return *this;
}

TriggerBuilder& TriggerBuilder::SetPriority(int64_t priority) {
  priority_ = priority;
  return *this;
}

TriggerBuilder& TriggerBuilder::SetDedupKey(std::optional<uint64_t> dedup_key) {
  dedup_key_ = dedup_key;
  return *this;
}

TriggerBuilder& TriggerBuilder::SetDebugKey(std::optional<uint64_t> debug_key) {
  debug_key_ = debug_key;
  return *this;
}

TriggerBuilder& TriggerBuilder::SetAggregatableTriggerData(
    std::vector<attribution_reporting::AggregatableTriggerData>
        aggregatable_trigger_data) {
  aggregatable_trigger_data_ = std::move(aggregatable_trigger_data);
  return *this;
}

TriggerBuilder& TriggerBuilder::SetAggregatableValues(
    std::vector<attribution_reporting::AggregatableValues>
        aggregatable_values) {
  aggregatable_values_ = std::move(aggregatable_values);
  return *this;
}

TriggerBuilder& TriggerBuilder::SetAggregatableDedupKey(
    std::optional<uint64_t> aggregatable_dedup_key) {
  aggregatable_dedup_key_ = aggregatable_dedup_key;
  return *this;
}

TriggerBuilder& TriggerBuilder::SetIsWithinFencedFrame(
    bool is_within_fenced_frame) {
  is_within_fenced_frame_ = is_within_fenced_frame;
  return *this;
}

TriggerBuilder& TriggerBuilder::SetDebugReporting(bool debug_reporting) {
  debug_reporting_ = debug_reporting;
  return *this;
}

TriggerBuilder& TriggerBuilder::SetAggregationCoordinatorOrigin(
    SuitableOrigin aggregation_coordinator_origin) {
  aggregation_coordinator_origin_ = std::move(aggregation_coordinator_origin);
  return *this;
}

TriggerBuilder& TriggerBuilder::SetSourceRegistrationTimeConfig(
    attribution_reporting::mojom::SourceRegistrationTimeConfig
        source_registration_time_config) {
  source_registration_time_config_ = source_registration_time_config;
  return *this;
}

TriggerBuilder& TriggerBuilder::SetFilterPair(
    attribution_reporting::FilterPair filter_pair) {
  filter_pair_ = std::move(filter_pair);
  return *this;
}

TriggerBuilder& TriggerBuilder::SetAggregatableDedupKeyFilterPair(
    attribution_reporting::FilterPair filter_pair) {
  aggregatable_dedup_key_filter_pair_ = std::move(filter_pair);
  return *this;
}

TriggerBuilder& TriggerBuilder::SetTriggerContextId(
    std::string trigger_context_id) {
  trigger_context_id_ = std::move(trigger_context_id);
  return *this;
}

TriggerBuilder& TriggerBuilder::SetAggregatableDebugReportingConfig(
    attribution_reporting::AggregatableDebugReportingConfig
        aggregatable_trigger_config) {
  aggregatable_debug_reporting_config_ = std::move(aggregatable_trigger_config);
  return *this;
}

TriggerBuilder& TriggerBuilder::SetAggregatableFilteringIdMaxBytes(
    attribution_reporting::AggregatableFilteringIdsMaxBytes max_bytes) {
  aggregatable_filtering_id_max_bytes_ = max_bytes;
  return *this;
}

TriggerBuilder& TriggerBuilder::SetAttributionScopes(
    attribution_reporting::AttributionScopesSet attribution_scopes) {
  attribution_scopes_ = std::move(attribution_scopes);
  return *this;
}

TriggerBuilder& TriggerBuilder::SetAggregatableNamedBudgetCandidates(
    std::vector<attribution_reporting::AggregatableNamedBudgetCandidate>
        budgets) {
  aggregatable_named_budget_candidates_ = std::move(budgets);
  return *this;
}

AttributionTrigger TriggerBuilder::Build(
    bool generate_event_trigger_data) const {
  attribution_reporting::TriggerRegistration reg;
  reg.filters = filter_pair_;
  reg.debug_key = debug_key_;
  reg.aggregatable_dedup_keys.emplace_back(
      /*dedup_key=*/aggregatable_dedup_key_,
      aggregatable_dedup_key_filter_pair_);

  if (generate_event_trigger_data) {
    reg.event_triggers.emplace_back(trigger_data_, priority_, dedup_key_,
                                    FilterPair());
  }

  reg.aggregatable_trigger_data = aggregatable_trigger_data_;
  reg.aggregatable_values = aggregatable_values_;
  reg.debug_reporting = debug_reporting_;
  reg.aggregation_coordinator_origin = aggregation_coordinator_origin_;
  reg.aggregatable_trigger_config =
      *attribution_reporting::AggregatableTriggerConfig::Create(
          source_registration_time_config_, trigger_context_id_,
          aggregatable_filtering_id_max_bytes_);
  reg.aggregatable_debug_reporting_config =
      aggregatable_debug_reporting_config_;
  reg.attribution_scopes = attribution_scopes_;
  reg.aggregatable_named_budget_candidates =
      aggregatable_named_budget_candidates_;

  return AttributionTrigger(reporting_origin_, std::move(reg),
                            destination_origin_, is_within_fenced_frame_,
                            ukm::kInvalidSourceId);
}

AttributionInfoBuilder::AttributionInfoBuilder(SuitableOrigin context_origin)
    : context_origin_(std::move(context_origin)) {}

AttributionInfoBuilder::~AttributionInfoBuilder() = default;

AttributionInfoBuilder& AttributionInfoBuilder::SetTime(base::Time time) {
  time_ = time;
  return *this;
}

AttributionInfoBuilder& AttributionInfoBuilder::SetDebugKey(
    std::optional<uint64_t> debug_key) {
  debug_key_ = debug_key;
  return *this;
}

AttributionInfo AttributionInfoBuilder::Build() const {
  return AttributionInfo(time_, debug_key_, context_origin_);
}

ReportBuilder::ReportBuilder(AttributionInfo attribution_info,
                             StoredSource source)
    : attribution_info_(std::move(attribution_info)),
      source_(std::move(source)),
      external_report_id_(DefaultExternalReportID()) {}

ReportBuilder::~ReportBuilder() = default;

ReportBuilder& ReportBuilder::SetTriggerData(uint64_t trigger_data) {
  trigger_data_ = trigger_data;
  return *this;
}

ReportBuilder& ReportBuilder::SetReportTime(base::Time time) {
  report_time_ = time;
  return *this;
}

ReportBuilder& ReportBuilder::SetPriority(int64_t priority) {
  priority_ = priority;
  return *this;
}

ReportBuilder& ReportBuilder::SetExternalReportId(
    base::Uuid external_report_id) {
  external_report_id_ = std::move(external_report_id);
  return *this;
}

ReportBuilder& ReportBuilder::SetReportId(AttributionReport::Id id) {
  report_id_ = id;
  return *this;
}

ReportBuilder& ReportBuilder::SetAggregatableHistogramContributions(
    std::vector<blink::mojom::AggregatableReportHistogramContribution>
        contributions) {
  DCHECK(!contributions.empty());
  contributions_ = std::move(contributions);
  return *this;
}

ReportBuilder& ReportBuilder::SetAggregationCoordinatorOrigin(
    SuitableOrigin aggregation_coordinator_origin) {
  aggregation_coordinator_origin_ = std::move(aggregation_coordinator_origin);
  return *this;
}

ReportBuilder& ReportBuilder::SetSourceRegistrationTimeConfig(
    attribution_reporting::mojom::SourceRegistrationTimeConfig
        source_registration_time_config) {
  source_registration_time_config_ = source_registration_time_config;
  return *this;
}

ReportBuilder& ReportBuilder::SetAggregatableFilteringIdsMaxBytes(
    attribution_reporting::AggregatableFilteringIdsMaxBytes max_bytes) {
  aggregatable_filtering_ids_max_bytes_ = max_bytes;
  return *this;
}

ReportBuilder& ReportBuilder::SetTriggerContextId(
    std::string trigger_context_id) {
  trigger_context_id_ = std::move(trigger_context_id);
  return *this;
}

AttributionReport ReportBuilder::Build() const {
  return AttributionReport(
      attribution_info_, report_id_, report_time_,
      /*initial_report_time=*/report_time_, external_report_id_,
      /*failed_send_attempts=*/0,
      AttributionReport::EventLevelData(trigger_data_, priority_, source_),
      source_.common_info().reporting_origin(), source_.debug_key());
}

AttributionReport ReportBuilder::BuildAggregatableAttribution() const {
  return AttributionReport(
      attribution_info_, report_id_, report_time_,
      /*initial_report_time=*/report_time_, external_report_id_,
      /*failed_send_attempts=*/0,
      AttributionReport::AggregatableData(
          aggregation_coordinator_origin_,
          *attribution_reporting::AggregatableTriggerConfig::Create(
              source_registration_time_config_, trigger_context_id_,
              aggregatable_filtering_ids_max_bytes_),
          source_.source_time(), contributions_,
          source_.common_info().source_origin()),
      source_.common_info().reporting_origin(), source_.debug_key());
}

AttributionReport ReportBuilder::BuildNullAggregatable() const {
  return AttributionReport(
      attribution_info_, report_id_, report_time_,
      /*initial_report_time=*/report_time_, external_report_id_,
      /*failed_send_attempts=*/0,
      AttributionReport::AggregatableData(
          aggregation_coordinator_origin_,
          *attribution_reporting::AggregatableTriggerConfig::Create(
              source_registration_time_config_, trigger_context_id_,
              attribution_reporting::AggregatableFilteringIdsMaxBytes()),
          source_.source_time(),
          /*contributions=*/{}, /*source_origin=*/std::nullopt),
      source_.common_info().reporting_origin(),
      /*source_debug_key=*/std::nullopt);
}

// Does not compare source IDs, as they are set by the underlying sqlite DB and
// should not be tested.
bool operator==(const StoredSource& a, const StoredSource& b) {
  const auto tie = [](const StoredSource& source) {
    return std::make_tuple(
        source.common_info(), source.source_event_id(),
        source.destination_sites(), source.source_time(), source.expiry_time(),
        source.trigger_data(), source.aggregatable_report_window_time(),
        source.priority(), source.filter_data(), source.debug_key(),
        source.aggregation_keys(), source.attribution_logic(),
        source.active_state(), source.dedup_keys(),
        source.remaining_aggregatable_attribution_budget(),
        source.aggregatable_dedup_keys(), source.randomized_response_rate(),
        source.trigger_data_matching(), source.event_level_epsilon(),
        source.aggregatable_debug_key_piece(),
        source.remaining_aggregatable_debug_budget(),
        source.attribution_scopes_data());
  };
  return tie(a) == tie(b);
}

// Does not compare the assembled report as it is returned by the
// aggregation service from all the other data.
bool operator==(const AttributionReport::AggregatableData& a,
                const AttributionReport::AggregatableData& b) {
  const auto tie = [](const AttributionReport::AggregatableData& data) {
    return std::make_tuple(data.aggregation_coordinator_origin(),
                           data.aggregatable_trigger_config(),
                           data.source_time(), data.contributions(),
                           data.source_origin());
  };
  return tie(a) == tie(b);
}

// Does not compare source or report IDs, as they are set by the underlying
// sqlite DB and should not be tested.
bool operator==(const AttributionReport& a, const AttributionReport& b) {
  const auto tie = [](const AttributionReport& report) {
    return std::make_tuple(
        report.attribution_info(), report.report_time(),
        report.initial_report_time(), report.external_report_id(),
        report.failed_send_attempts(), report.data(), report.reporting_origin(),
        report.source_debug_key());
  };
  return tie(a) == tie(b);
}

std::ostream& operator<<(std::ostream& out, RateLimitResult result) {
  switch (result) {
    case RateLimitResult::kAllowed:
      return out << "kAllowed";
    case RateLimitResult::kNotAllowed:
      return out << "kNotAllowed";
    case RateLimitResult::kError:
      return out << "kError";
  }
}

std::ostream& operator<<(std::ostream& out,
                         StoredSource::AttributionLogic attribution_logic) {
  switch (attribution_logic) {
    case StoredSource::AttributionLogic::kNever:
      return out << "kNever";
    case StoredSource::AttributionLogic::kTruthfully:
      return out << "kTruthfully";
    case StoredSource::AttributionLogic::kFalsely:
      return out << "kFalsely";
  }
}

std::ostream& operator<<(std::ostream& out,
                         StoredSource::ActiveState active_state) {
  switch (active_state) {
    case StoredSource::ActiveState::kActive:
      return out << "kActive";
    case StoredSource::ActiveState::kInactive:
      return out << "kInactive";
    case StoredSource::ActiveState::kReachedEventLevelAttributionLimit:
      return out << "kReachedEventLevelAttributionLimit";
  }
}

std::ostream& operator<<(std::ostream& out,
                         StoredSource::AggregatableNamedBudgets budgets) {
  out << "{";
  for (const auto& [key, value] : budgets) {
    out << key << ": { original_budget=" << value.original_budget()
        << ", remaining_budget=" << value.remaining_budget() << " }, ";
  }
  return out << "}";
}

std::ostream& operator<<(std::ostream& out,
                         const AttributionTrigger& conversion) {
  return out << "{registration=" << conversion.registration()
             << ",destination_origin=" << conversion.destination_origin()
             << ",is_within_fenced_frame="
             << conversion.is_within_fenced_frame() << "}";
}

std::ostream& operator<<(std::ostream& out, const CommonSourceInfo& source) {
  return out << "{source_origin=" << source.source_origin()
             << "reporting_origin=" << source.reporting_origin()
             << ",source_type=" << source.source_type()
             << ",cookie_based_debug_allowed="
             << source.cookie_based_debug_allowed() << "}";
}

std::ostream& operator<<(std::ostream& out,
                         const AttributionInfo& attribution_info) {
  return out << "{time=" << attribution_info.time << ",debug_key="
             << (attribution_info.debug_key
                     ? base::NumberToString(*attribution_info.debug_key)
                     : "null")
             << ",context_origin=" << attribution_info.context_origin << "}";
}

std::ostream& operator<<(std::ostream& out, const StorableSource& source) {
  return out << "{registration=" << source.registration().ToJson()
             << ",common_info=" << source.common_info()
             << ",is_within_fenced_frame=" << source.is_within_fenced_frame()
             << "}";
}

std::ostream& operator<<(std::ostream& out, const StoredSource& source) {
  out << "{common_info=" << source.common_info()
      << ",source_event_id=" << source.source_event_id()
      << ",destination_sites=" << source.destination_sites()
      << ",source_time=" << source.source_time()
      << ",expiry_time=" << source.expiry_time()
      << ",trigger_data=" << source.trigger_data()
      << ",aggregatable_report_window_time="
      << source.aggregatable_report_window_time()
      << ",priority=" << source.priority()
      << ",filter_data=" << source.filter_data() << ",debug_key="
      << (source.debug_key() ? base::NumberToString(*source.debug_key())
                             : "null")
      << ",aggregation_keys=" << source.aggregation_keys()
      << ",attribution_logic=" << source.attribution_logic()
      << ",active_state=" << source.active_state()
      << ",source_id=" << *source.source_id()
      << ",remaining_aggregatable_attribution_budget="
      << source.remaining_aggregatable_attribution_budget()
      << ",randomized_response_rate=" << source.randomized_response_rate()
      << ",event_level_epsilon=" << source.event_level_epsilon()
      << ",trigger_data_matching=" << source.trigger_data_matching()
      << ",aggregatable_debug_key_piece="
      << source.aggregatable_debug_key_piece()
      << ",remaining_aggregatable_debug_budget="
      << source.remaining_aggregatable_debug_budget()
      << ",attribution_scopes_data="
      << (source.attribution_scopes_data().has_value()
              ? SerializeAttributionJson(
                    source.attribution_scopes_data()->ToJson())
              : "null")
      << ",aggregatable_named_budgets=" << source.aggregatable_named_budgets()
      << ",dedup_keys=[";

  const char* separator = "";
  for (int64_t dedup_key : source.dedup_keys()) {
    out << separator << dedup_key;
    separator = ", ";
  }

  out << "],aggregatable_dedup_keys=[";

  separator = "";
  for (int64_t dedup_key : source.aggregatable_dedup_keys()) {
    out << separator << dedup_key;
    separator = ",";
  }

  return out << "]}";
}

std::ostream& operator<<(
    std::ostream& out,
    const blink::mojom::AggregatableReportHistogramContribution& contribution) {
  return out << "{bucket=" << contribution.bucket
             << ",value=" << contribution.value << "}";
}

std::ostream& operator<<(std::ostream& out,
                         const AttributionReport::EventLevelData& data) {
  out << "{trigger_data=" << data.trigger_data << ",priority=" << data.priority
      << ",source_origin=" << data.source_origin
      << ",destinations=" << data.destinations
      << ",source_event_id=" << data.source_event_id
      << ",source_type=" << data.source_type << ",source_debug_key=";

  return out << ",randomized_response_rate=" << data.randomized_response_rate
             << ",attributed_truthfully=" << data.attributed_truthfully << "}";
}

std::ostream& operator<<(std::ostream& out,
                         const AttributionReport::AggregatableData& data) {
  out << "{aggregation_coordinator_origin="
      << (data.aggregation_coordinator_origin().has_value()
              ? data.aggregation_coordinator_origin()->Serialize()
              : "null")
      << ",aggregatable_trigger_config=" << data.aggregatable_trigger_config()
      << ",source_time=" << data.source_time() << ",contributions=[";

  const char* separator = "";
  for (const auto& contribution : data.contributions()) {
    out << separator << contribution;
    separator = ", ";
  }

  out << "],source_origin=";

  if (data.source_origin().has_value()) {
    out << *data.source_origin();
  } else {
    out << "null";
  }

  return out << "}";
}

namespace {
std::ostream& operator<<(std::ostream& out,
                         const AttributionReport::Data& data) {
  std::visit([&out](const auto& v) { out << v; }, data);
  return out;
}
}  // namespace

std::ostream& operator<<(std::ostream& out, const AttributionReport& report) {
  out << "{attribution_info=" << report.attribution_info()
      << ",id=" << *report.id() << ",report_time=" << report.report_time()
      << ",initial_report_time=" << report.initial_report_time()
      << ",external_report_id=" << report.external_report_id()
      << ",failed_send_attempts=" << report.failed_send_attempts()
      << ",data=" << report.data()
      << ",reporting_origin=" << report.reporting_origin()
      << ",source_debug_key=";

  if (report.source_debug_key().has_value()) {
    out << *report.source_debug_key();
  } else {
    out << "null";
  }

  return out << "}";
}

std::ostream& operator<<(std::ostream& out, SendResult::Status status) {
  switch (status) {
    case SendResult::Status::kSent:
      return out << "kSent";
    case SendResult::Status::kTransientFailure:
      return out << "kTransientFailure";
    case SendResult::Status::kFailure:
      return out << "kFailure";
    case SendResult::Status::kExpired:
      return out << "kExpired";
    case SendResult::Status::kDropped:
      return out << "kDropped";
    case SendResult::Status::kAssemblyFailure:
      return out << "kAssemblyFailure";
    case SendResult::Status::kTransientAssemblyFailure:
      return out << "kTransientAssemblyFailure";
  }
}

std::ostream& operator<<(std::ostream& out, const SendResult& info) {
  std::visit(absl::Overload{
                 [&](SendResult::Sent sent) { out << sent; },
                 [&](SendResult::Dropped) { out << "{Dropped={}}"; },
                 [&](SendResult::Expired) { out << "{Expired={}}"; },
                 [&](SendResult::AssemblyFailure failure) {
                   out << "{AssemblyFailure={transient=" << failure.transient
                       << "}}";
                 },
             },
             info.result);
  return out;
}

std::ostream& operator<<(std::ostream& out, SendResult::Sent sent) {
  out << "{Sent={result=";
  switch (sent.result) {
    case SendResult::Sent::Result::kSent:
      out << "kSent";
      break;
    case SendResult::Sent::Result::kTransientFailure:
      out << "kTransientFailure";
      break;
    case SendResult::Sent::Result::kFailure:
      out << "kFailure";
      break;
  }
  out << ",status=";
  if (sent.status < 0) {
    out << net::ErrorToShortString(sent.status);
  } else {
    out << sent.status;
  }
  return out << "}}";
}

std::ostream& operator<<(std::ostream& out,
                         const AttributionDataModel::DataKey& key) {
  return out << "{reporting_origin=" << key.reporting_origin() << "}";
}

TestAggregatableSourceProvider::TestAggregatableSourceProvider(size_t size) {
  attribution_reporting::AggregationKeys::Keys::container_type keys;
  keys.reserve(size);
  for (size_t i = 0; i < size; ++i) {
    keys.emplace_back(base::NumberToString(i), i);
  }

  auto source =
      attribution_reporting::AggregationKeys::FromKeys(std::move(keys));
  DCHECK(source.has_value());
  source_ = *std::move(source);
}

TestAggregatableSourceProvider::~TestAggregatableSourceProvider() = default;

SourceBuilder TestAggregatableSourceProvider::GetBuilder(
    base::Time source_time) const {
  return SourceBuilder(source_time).SetAggregationKeys(source_);
}

TriggerBuilder DefaultAggregatableTriggerBuilder(
    const std::vector<uint32_t>& histogram_values) {
  std::vector<attribution_reporting::AggregatableTriggerData>
      aggregatable_trigger_data;

  attribution_reporting::AggregatableValues::Values aggregatable_values;

  for (size_t i = 0; i < histogram_values.size(); ++i) {
    std::string key_id = base::NumberToString(i);
    aggregatable_trigger_data.push_back(
        attribution_reporting::AggregatableTriggerData(
            absl::MakeUint128(/*high=*/i, /*low=*/0),
            /*source_keys=*/{key_id}, FilterPair()));
    aggregatable_values.emplace(
        std::move(key_id),
        *attribution_reporting::AggregatableValuesValue::Create(
            histogram_values[i], attribution_reporting::kDefaultFilteringId));
  }

  return TriggerBuilder()
      .SetAggregatableTriggerData(std::move(aggregatable_trigger_data))
      .SetAggregatableValues(
          {*attribution_reporting::AggregatableValues::Create(
              std::move(aggregatable_values), FilterPair())});
}

std::vector<blink::mojom::AggregatableReportHistogramContribution>
DefaultAggregatableHistogramContributions(
    const std::vector<int32_t>& histogram_values) {
  std::vector<blink::mojom::AggregatableReportHistogramContribution>
      contributions;
  for (size_t i = 0; i < histogram_values.size(); ++i) {
    contributions.emplace_back(absl::MakeUint128(i, i), histogram_values[i],
                               attribution_reporting::kDefaultFilteringId);
  }
  return contributions;
}

bool operator==(const OsRegistration& a, const OsRegistration& b) {
  const auto tie = [](const OsRegistration& r) {
    return std::make_tuple(r.registration_items, r.top_level_origin,
                           r.GetType());
  };
  return tie(a) == tie(b);
}

std::ostream& operator<<(std::ostream& out, const OsRegistration& r) {
  out << "{registration_items=[";
  const char* separator = "";
  for (const OsRegistrationItem& item : r.registration_items) {
    out << separator << item;
    separator = ",";
  }
  return out << "],top_level_origin=" << r.top_level_origin
             << ",type=" << r.GetType() << "}";
}

namespace {

void CheckAttributionReportingHeader(
    const std::string& header,
    const std::vector<std::string>& required_keys,
    const std::vector<std::string>& prohibited_keys) {
  auto dict = net::structured_headers::ParseDictionary(header);
  EXPECT_TRUE(dict.has_value());
  if (!dict.has_value()) {
    return;
  }

  for (const auto& key : required_keys) {
    EXPECT_TRUE(dict->contains(key)) << key;
  }

  for (const auto& key : prohibited_keys) {
    EXPECT_FALSE(dict->contains(key)) << key;
  }
}

}  // namespace

void ExpectValidAttributionReportingEligibleHeaderForEventBeacon(
    const std::string& header) {
  CheckAttributionReportingHeader(
      header,
      /*required_keys=*/{"event-source"},
      /*prohibited_keys=*/{"navigation-source", "trigger"});
}

void ExpectValidAttributionReportingEligibleHeaderForImg(
    const std::string& header) {
  CheckAttributionReportingHeader(header,
                                  /*required_keys=*/{"event-source", "trigger"},
                                  /*prohibited_keys=*/{"navigation-source"});
}

void ExpectValidAttributionReportingEligibleHeaderForNavigation(
    const std::string& header) {
  CheckAttributionReportingHeader(
      header,
      /*required_keys=*/{"navigation-source"},
      /*prohibited_keys=*/{"event-source", "trigger"});
}

void ExpectEmptyAttributionReportingEligibleHeader(const std::string& header) {
  CheckAttributionReportingHeader(
      header,
      /*required_keys=*/{},
      /*prohibited_keys=*/{"navigation-source", "event-source", "trigger"});
}

void ExpectValidAttributionReportingSupportHeader(const std::string& header,
                                                  bool web_expected,
                                                  bool os_expected) {
  std::vector<std::string> required_keys;
  std::vector<std::string> prohibited_keys;

  if (web_expected) {
    required_keys.emplace_back("web");
  } else {
    prohibited_keys.emplace_back("web");
  }

  if (os_expected) {
    required_keys.emplace_back("os");
  } else {
    prohibited_keys.emplace_back("os");
  }

  CheckAttributionReportingHeader(header, required_keys, prohibited_keys);
}

}  // namespace content