blob: f9ed13a39aaa7f80aabb3cbbeed25a750004d8a9 [file] [log] [blame]
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/test/attribution_simulator_input_parser.h"
#include <ostream>
#include <sstream>
#include <vector>
#include "base/test/values_test_util.h"
#include "base/time/time.h"
#include "base/time/time_override.h"
#include "base/values.h"
#include "content/browser/attribution_reporting/attribution_aggregatable_trigger_data.h"
#include "content/browser/attribution_reporting/attribution_aggregatable_values.h"
#include "content/browser/attribution_reporting/attribution_aggregation_keys.h"
#include "content/browser/attribution_reporting/attribution_filter_data.h"
#include "content/browser/attribution_reporting/attribution_source_type.h"
#include "content/browser/attribution_reporting/attribution_test_utils.h"
#include "content/browser/attribution_reporting/common_source_info.h"
#include "content/browser/attribution_reporting/storable_source.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_constants.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/numeric/int128.h"
#include "third_party/blink/public/common/attribution_reporting/constants.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace content {
bool operator==(const AttributionTriggerAndTime& a,
const AttributionTriggerAndTime& b) {
return a.trigger == b.trigger && a.time == b.time;
}
std::ostream& operator<<(std::ostream& out,
const AttributionTriggerAndTime& t) {
return out << "{time=" << t.time << ",trigger=" << t.trigger << "}";
}
bool operator==(const AttributionSimulatorCookie& a,
const AttributionSimulatorCookie& b) {
return a.cookie.HasEquivalentDataMembers(b.cookie) &&
a.source_url == b.source_url;
}
std::ostream& operator<<(std::ostream& out,
const AttributionSimulatorCookie& c) {
return out << "{source_url=" << c.source_url
<< ",cookie=" << c.cookie.DebugString() << "}";
}
bool operator==(const AttributionDataClear& a, const AttributionDataClear& b) {
return a.time == b.time && a.delete_begin == b.delete_begin &&
a.delete_end == b.delete_end && a.origins == b.origins;
}
std::ostream& operator<<(std::ostream& out, const AttributionDataClear& c) {
out << "{time=" << c.time << ",delete_begin=" << c.delete_begin
<< ",delete_end=" << c.delete_end << ",origins=";
if (c.origins.has_value()) {
out << "[";
const char* separator = "";
for (const url::Origin& origin : *c.origins) {
out << separator << origin;
separator = ", ";
}
out << "]";
} else {
out << "null";
}
return out;
}
namespace {
using ::testing::_;
using ::testing::ElementsAre;
using ::testing::HasSubstr;
using ::testing::IsEmpty;
using ::testing::Optional;
using ::testing::Pair;
using ::testing::SizeIs;
// Pick an arbitrary offset time to test correct handling.
constexpr base::Time kOffsetTime = base::Time::UnixEpoch() + base::Days(5);
TEST(AttributionSimulatorInputParserTest, EmptyInputParses) {
const char* const kTestCases[] = {
R"json({})json",
R"json({"sources":[]})json",
R"json({"triggers":[]})json",
};
for (const char* json : kTestCases) {
base::Value value = base::test::ParseJson(json);
std::ostringstream error_stream;
EXPECT_THAT(ParseAttributionSimulationInput(std::move(value), kOffsetTime,
error_stream),
Optional(IsEmpty()))
<< json;
EXPECT_THAT(error_stream.str(), IsEmpty()) << json;
}
}
TEST(AttributionSimulatorInputParserTest, ValidSourceParses) {
constexpr char kJson[] = R"json({"sources": [
{
"timestamp": "1643235574123",
"source_type": "navigation",
"reporting_origin": "https://a.r.test",
"source_origin": "https://a.s.test",
"Attribution-Reporting-Register-Source": {
"source_event_id": "123",
"destination": "https://a.d.test",
"expiry": "864000",
"priority": "-5",
"debug_key": "14"
}
},
{
"timestamp": "1643235573123",
"source_type": "event",
"reporting_origin": "https://b.r.test",
"source_origin": "https://b.s.test",
"Attribution-Reporting-Register-Source": {
"source_event_id": "456",
"destination": "https://b.d.test"
}
},
{
"timestamp": "1643235575123",
"source_type": "event",
"reporting_origin": "https://c.r.test",
"source_origin": "https://c.s.test",
"Attribution-Reporting-Register-Source": {
"source_event_id": "789",
"destination": "https://c.d.test",
"expiry": "864001",
"filter_data": {
"a": [],
"b": ["c", "d"]
}
}
},
{
"timestamp": "1643235576123",
"source_type": "event",
"reporting_origin": "https://c.r.test",
"source_origin": "https://c.s.test",
"Attribution-Reporting-Register-Source": {
"source_event_id": "789",
"destination": "https://c.d.test",
"expiry": "864001",
"aggregation_keys": {
"a": "0x1"
}
}
}
]})json";
base::Value value = base::test::ParseJson(kJson);
std::ostringstream error_stream;
EXPECT_THAT(
ParseAttributionSimulationInput(std::move(value), kOffsetTime,
error_stream),
Optional(ElementsAre(
Pair(SourceBuilder(kOffsetTime + base::Milliseconds(1643235574123))
.SetSourceType(AttributionSourceType::kNavigation)
.SetReportingOrigin(
url::Origin::Create(GURL("https://a.r.test")))
.SetImpressionOrigin(
url::Origin::Create(GURL("https://a.s.test")))
.SetSourceEventId(123)
.SetConversionOrigin(
url::Origin::Create(GURL("https://a.d.test")))
.SetExpiry(base::Days(10))
.SetPriority(-5)
.SetDebugKey(14)
.Build(),
_),
Pair(SourceBuilder(kOffsetTime + base::Milliseconds(1643235573123))
.SetSourceType(AttributionSourceType::kEvent)
.SetReportingOrigin(
url::Origin::Create(GURL("https://b.r.test")))
.SetImpressionOrigin(
url::Origin::Create(GURL("https://b.s.test")))
.SetSourceEventId(456)
.SetConversionOrigin(
url::Origin::Create(GURL("https://b.d.test")))
.SetExpiry(base::Days(30)) // default
.SetPriority(0) // default
.SetDebugKey(absl::nullopt) // default
.Build(),
_),
Pair(
SourceBuilder(kOffsetTime + base::Milliseconds(1643235575123))
.SetSourceType(AttributionSourceType::kEvent)
.SetReportingOrigin(
url::Origin::Create(GURL("https://c.r.test")))
.SetImpressionOrigin(
url::Origin::Create(GURL("https://c.s.test")))
.SetSourceEventId(789)
.SetConversionOrigin(
url::Origin::Create(GURL("https://c.d.test")))
.SetExpiry(base::Days(10)) // rounded to whole number of days
.SetPriority(0) // default
.SetDebugKey(absl::nullopt) // default
.SetFilterData(
*AttributionFilterData::FromSourceFilterValues({
{"a", {}},
{"b", {"c", "d"}},
}))
.Build(),
_),
Pair(
SourceBuilder(kOffsetTime + base::Milliseconds(1643235576123))
.SetSourceType(AttributionSourceType::kEvent)
.SetReportingOrigin(
url::Origin::Create(GURL("https://c.r.test")))
.SetImpressionOrigin(
url::Origin::Create(GURL("https://c.s.test")))
.SetSourceEventId(789)
.SetConversionOrigin(
url::Origin::Create(GURL("https://c.d.test")))
.SetExpiry(base::Days(10)) // rounded to whole number of days
.SetPriority(0) // default
.SetDebugKey(absl::nullopt) // default
.SetAggregationKeys(
*AttributionAggregationKeys::FromKeys({{"a", 1}}))
.Build(),
_))));
EXPECT_THAT(error_stream.str(), IsEmpty());
}
TEST(AttributionSimulatorInputParserTest, OutputRetainsInputJSON) {
constexpr char kJson[] = R"json({
"sources": [
{
"timestamp": "1643235574123",
"source_type": "navigation",
"reporting_origin": "https://r.test",
"source_origin": "https://s.test",
"Attribution-Reporting-Register-Source": {
"source_event_id": "123",
"destination": "https://d.test",
"filter_data": {"a": ["b", "c"]},
"expiry": "864000",
"priority": "-5",
"debug_key": "14"
}
}
],
"triggers": [
{
"timestamp": "1643235576123",
"reporting_origin": "https://a.r.test",
"destination_origin": " https://a.d1.test",
"Attribution-Reporting-Register-Trigger": {
"trigger_data": "10",
"event_source_trigger_data": "3",
"priority": "-5",
"deduplication_key": "123",
"debug_key": "14"
}
}
]})json";
const base::Value value = base::test::ParseJson(kJson);
std::ostringstream error_stream;
EXPECT_THAT(
ParseAttributionSimulationInput(value.Clone(), kOffsetTime, error_stream),
Optional(ElementsAre(
Pair(_, base::test::IsJson(
value.FindKey("sources")->GetIfList()->front())),
Pair(_, base::test::IsJson(
value.FindKey("triggers")->GetIfList()->front())))));
}
TEST(AttributionSimulatorInputParserTest, ValidTriggerParses) {
constexpr char kJson[] = R"json({"triggers": [
{
"timestamp": "1643235576123",
"reporting_origin": "https://a.r.test",
"destination_origin": " https://a.d1.test",
"Attribution-Reporting-Register-Trigger": {
"event_trigger_data": [
{
"trigger_data": "10",
"priority": "-5",
"deduplication_key": "123",
"filters": {
"x": ["y"]
},
"not_filters": {
"z": []
}
},
{}
],
"debug_key": "14",
"filters": {
"a": ["b", "c"],
"d": []
},
"not_filters": {
"e": ["f"]
}
}
},
{
"timestamp": "1643235575123",
"reporting_origin": "https://b.r.test",
"destination_origin": " https://a.d2.test",
"Attribution-Reporting-Register-Trigger": {}
},
{
"timestamp": "1643235574123",
"reporting_origin": "https://b.r.test",
"destination_origin": " https://a.d2.test",
"Attribution-Reporting-Register-Trigger": {
"aggregatable_trigger_data": [{
"source_keys": ["a"],
"key_piece": "0x1"
}],
"aggregatable_values": {"a": 1}
}
}
]})json";
base::Value value = base::test::ParseJson(kJson);
std::ostringstream error_stream;
EXPECT_THAT(
ParseAttributionSimulationInput(std::move(value), kOffsetTime,
error_stream),
Optional(ElementsAre(
Pair(
AttributionTriggerAndTime{
.trigger = AttributionTrigger(
/*destination_origin=*/
url::Origin::Create(GURL("https://a.d1.test")),
/*reporting_origin=*/
url::Origin::Create(GURL("https://a.r.test")),
/*filters=*/
*AttributionFilterData::FromTriggerFilterValues({
{"a", {"b", "c"}},
{"d", {}},
}),
/*not_filters=*/
*AttributionFilterData::FromTriggerFilterValues({
{"e", {"f"}},
}),
/*debug_key=*/14,
{
AttributionTrigger::EventTriggerData(
/*data=*/10,
/*priority=*/-5,
/*dedup_key=*/123,
/*filters=*/
*AttributionFilterData::FromTriggerFilterValues({
{"x", {"y"}},
}),
/*not_filters=*/
*AttributionFilterData::FromTriggerFilterValues({
{"z", {}},
})),
AttributionTrigger::EventTriggerData(
/*data=*/0,
/*priority=*/0,
/*dedup_key=*/absl::nullopt,
/*filters=*/AttributionFilterData(),
/*not_filters=*/AttributionFilterData()),
},
/*aggregatable_trigger_data=*/{},
/*aggregatable_values=*/AttributionAggregatableValues()),
.time = kOffsetTime + base::Milliseconds(1643235576123),
},
_),
Pair(
AttributionTriggerAndTime{
.trigger = AttributionTrigger(
/*destination_origin=*/
url::Origin::Create(GURL("https://a.d2.test")),
/*reporting_origin=*/
url::Origin::Create(GURL("https://b.r.test")),
/*filters=*/AttributionFilterData(),
/*not_filters=*/AttributionFilterData(),
/*debug_key=*/absl::nullopt,
/*event_triggers=*/{},
/*aggregatable_trigger_data=*/{},
/*aggregatable_values=*/AttributionAggregatableValues()),
.time = kOffsetTime + base::Milliseconds(1643235575123),
},
_),
Pair(
AttributionTriggerAndTime{
.trigger = AttributionTrigger(
/*destination_origin=*/
url::Origin::Create(GURL("https://a.d2.test")),
/*reporting_origin=*/
url::Origin::Create(GURL("https://b.r.test")),
/*filters=*/AttributionFilterData(),
/*not_filters=*/AttributionFilterData(),
/*debug_key=*/absl::nullopt,
/*event_triggers=*/{},
{AttributionAggregatableTriggerData::CreateForTesting(
absl::MakeUint128(/*high=*/0, /*low=*/1),
/*source_keys=*/{"a"},
/*filters=*/AttributionFilterData(),
/*not_filters=*/AttributionFilterData())},
/*aggregatable_values=*/
AttributionAggregatableValues::CreateForTesting(
{{"a", 1}})),
.time = kOffsetTime + base::Milliseconds(1643235574123),
},
_))));
EXPECT_THAT(error_stream.str(), IsEmpty());
}
TEST(AttributionSimulatorInputParserTest, ValidSourceAndTriggerParses) {
constexpr char kJson[] = R"json({
"sources": [{
"timestamp": "1643235573123",
"source_type": "event",
"reporting_origin": "https://b.r.test",
"source_origin": "https://b.s.test",
"Attribution-Reporting-Register-Source": {
"source_event_id": "456",
"destination": "https://b.d.test"
}
}],
"triggers": [{
"timestamp": "1643235575123",
"reporting_origin": "https://b.r.test",
"destination_origin": " https://a.d2.test",
"Attribution-Reporting-Register-Trigger": {}
}]
})json";
base::Value value = base::test::ParseJson(kJson);
std::ostringstream error_stream;
EXPECT_THAT(ParseAttributionSimulationInput(std::move(value), kOffsetTime,
error_stream),
Optional(SizeIs(2)));
EXPECT_THAT(error_stream.str(), IsEmpty());
}
TEST(AttributionSimulatorInputParserTest, ValidCookieParses) {
// `net::CanonicalCookie::Create()` sets
// `net::CanonicalCookie::LastUpdateDate()` to `base::Time::Now()`, so
// override it here to make the test deterministic.
base::subtle::ScopedTimeClockOverrides time_override(
/*time_override=*/[]() { return kOffsetTime + base::Seconds(1); },
/*time_ticks_override=*/nullptr,
/*thread_ticks_override=*/nullptr);
constexpr char kJson[] = R"json({"cookies": [
{
"timestamp": "1643235574123",
"url": "https://r.test/x",
"Set-Cookie": "a=b; Secure; Max-Age=5"
}
]})json";
const base::Time expected_creation_time =
kOffsetTime + base::Milliseconds(1643235574123);
base::Value value = base::test::ParseJson(kJson);
std::ostringstream error_stream;
EXPECT_THAT(
ParseAttributionSimulationInput(std::move(value), kOffsetTime,
error_stream),
Optional(ElementsAre(Pair(
AttributionSimulatorCookie{
.cookie = *net::CanonicalCookie::CreateUnsafeCookieForTesting(
/*name=*/"a",
/*value=*/"b",
/*domain=*/"r.test",
/*path=*/"/",
/*creation=*/expected_creation_time,
/*expiration=*/expected_creation_time + base::Seconds(5),
/*last_access=*/expected_creation_time,
/*last_updated=*/kOffsetTime + base::Seconds(1),
/*secure=*/true,
/*httponly=*/false,
/*same_site=*/net::CookieSameSite::UNSPECIFIED,
/*priority=*/net::CookiePriority::COOKIE_PRIORITY_DEFAULT,
/*same_party=*/false),
.source_url = GURL("https://r.test/x"),
},
_))));
EXPECT_THAT(error_stream.str(), IsEmpty());
}
TEST(AttributionSimulatorInputParserTest, ValidDataClearParses) {
constexpr char kJson[] = R"json({"data_clears": [
{
"timestamp": "1643235574123",
"delete_begin": "1643235573123",
},
{
"timestamp": "1643235574123",
"delete_end": "1643235575123",
"origins": [
"https://r.test",
"https://s.test"
]
}
]})json";
base::Value value = base::test::ParseJson(kJson);
std::ostringstream error_stream;
EXPECT_THAT(
ParseAttributionSimulationInput(std::move(value), kOffsetTime,
error_stream),
Optional(ElementsAre(
Pair(AttributionDataClear(
/*time=*/kOffsetTime + base::Milliseconds(1643235574123),
/*delete_begin=*/kOffsetTime +
base::Milliseconds(1643235573123),
/*delete_end=*/base::Time::Max(),
/*origins=*/absl::nullopt),
_),
Pair(AttributionDataClear(
/*time=*/kOffsetTime + base::Milliseconds(1643235574123),
/*delete_begin=*/base::Time::Min(),
/*delete_end=*/kOffsetTime +
base::Milliseconds(1643235575123),
/*origins=*/
base::flat_set<url::Origin>{
url::Origin::Create(GURL("https://r.test")),
url::Origin::Create(GURL("https://s.test")),
}),
_))));
EXPECT_THAT(error_stream.str(), IsEmpty());
}
TEST(AttributionSimulatorInputParserTest, InvalidAggregatableTriggerDataSize) {
const struct {
size_t size;
bool valid;
} kTestCases[]{
{blink::kMaxAttributionAggregatableTriggerDataPerTrigger, true},
{blink::kMaxAttributionAggregatableTriggerDataPerTrigger + 1, false},
};
static constexpr char kError[] =
R"(["triggers"][0]["Attribution-Reporting-Register-Trigger"]["aggregatable_trigger_data"]: too many elements)";
for (const auto test_case : kTestCases) {
base::Value::List list;
for (size_t i = 0; i < test_case.size; ++i) {
list.Append("");
}
base::Value::Dict trigger;
trigger.Set("aggregatable_trigger_data", std::move(list));
base::Value::Dict dict;
dict.Set("Attribution-Reporting-Register-Trigger", std::move(trigger));
base::Value::List triggers;
triggers.Append(std::move(dict));
base::Value::Dict input;
input.Set("triggers", std::move(triggers));
std::ostringstream error_stream;
EXPECT_EQ(ParseAttributionSimulationInput(base::Value(std::move(input)),
kOffsetTime, error_stream),
absl::nullopt);
if (test_case.valid) {
EXPECT_THAT(error_stream.str(), Not(HasSubstr(kError)));
} else {
EXPECT_THAT(error_stream.str(), HasSubstr(kError));
}
}
}
TEST(AttributionSimulatorInputParserTest, InvalidEventTriggerDataSize) {
const struct {
size_t size;
bool valid;
} kTestCases[]{
{blink::kMaxAttributionEventTriggerData, true},
{blink::kMaxAttributionEventTriggerData + 1, false},
};
static constexpr char kError[] =
R"(["triggers"][0]["Attribution-Reporting-Register-Trigger"]["event_trigger_data"]: too many elements)";
for (const auto test_case : kTestCases) {
base::Value::List list;
for (size_t i = 0; i < test_case.size; ++i) {
list.Append("");
}
base::Value::Dict trigger;
trigger.Set("event_trigger_data", std::move(list));
base::Value::Dict dict;
dict.Set("Attribution-Reporting-Register-Trigger", std::move(trigger));
base::Value::List triggers;
triggers.Append(std::move(dict));
base::Value::Dict input;
input.Set("triggers", std::move(triggers));
std::ostringstream error_stream;
EXPECT_EQ(ParseAttributionSimulationInput(base::Value(std::move(input)),
kOffsetTime, error_stream),
absl::nullopt);
if (test_case.valid) {
EXPECT_THAT(error_stream.str(), Not(HasSubstr(kError)));
} else {
EXPECT_THAT(error_stream.str(), HasSubstr(kError));
}
}
}
struct ParseErrorTestCase {
const char* expected_failure_substr;
const char* json;
};
class AttributionSimulatorInputParseErrorTest
: public testing::TestWithParam<ParseErrorTestCase> {};
TEST_P(AttributionSimulatorInputParseErrorTest, InvalidInputFails) {
const ParseErrorTestCase& test_case = GetParam();
base::Value value = base::test::ParseJson(test_case.json);
std::ostringstream error_stream;
EXPECT_EQ(ParseAttributionSimulationInput(std::move(value), kOffsetTime,
error_stream),
absl::nullopt);
EXPECT_THAT(error_stream.str(), HasSubstr(test_case.expected_failure_substr));
}
const ParseErrorTestCase kParseErrorTestCases[] = {
{
"input root: must be a dictionary",
R"json(1)json",
},
{
R"(["sources"][0]["source_type"]: must be either)",
R"json({"sources": [{
"timestamp": "1643235574000",
"reporting_origin": "https://a.r.test",
"source_origin": "https://a.s.test"
}]})json",
},
{
R"(["sources"][0]["timestamp"]: must be an integer number of)",
R"json({"sources": [{
"source_type": "navigation",
"reporting_origin": "https://a.r.test",
"source_origin": "https://a.s.test"
}]})json",
},
{
R"(["sources"][0]["reporting_origin"]: must be a valid, secure origin)",
R"json({"sources": [{
"timestamp": "1643235574000",
"source_type": "navigation",
"source_origin": "https://a.s.test"
}]})json",
},
{
R"(["sources"][0]["reporting_origin"]: must be a valid, secure origin)",
R"json({"sources": [{
"timestamp": "1643235574000",
"source_type": "navigation",
"source_origin": "https://a.s.test",
"reporting_origin": "http://r.test"
}]})json",
},
{
R"(["sources"][0]["source_origin"]: must be a valid, secure origin)",
R"json({"sources": [{
"timestamp": "1643235574000",
"source_type": "navigation",
"reporting_origin": "https://a.s.test"
}]})json",
},
{
R"(["sources"][0]["Attribution-Reporting-Register-Source"]: must be present)",
R"json({"sources": [{
"timestamp": "1643235574000",
"source_type": "navigation",
"reporting_origin": "https://a.r.test",
"source_origin": "https://a.s.test"
}]})json",
},
{
R"(["sources"][0]["Attribution-Reporting-Register-Source"]: must be a dictionary)",
R"json({"sources": [{
"timestamp": "1643235574000",
"source_type": "navigation",
"reporting_origin": "https://a.r.test",
"source_origin": "https://a.s.test",
"Attribution-Reporting-Register-Source": ""
}]})json",
},
{
R"(["sources"][0]["Attribution-Reporting-Register-Source"]["source_event_id"]: must be a uint64 formatted)",
R"json({"sources": [{
"timestamp": "1643235574000",
"source_type": "navigation",
"reporting_origin": "https://a.r.test",
"source_origin": "https://a.s.test",
"Attribution-Reporting-Register-Source": {
"destination": "https://a.d.test"
}
}]})json",
},
{
R"(["sources"][0]["Attribution-Reporting-Register-Source"]["destination"]: must be a valid, secure origin)",
R"json({"sources": [{
"timestamp": "1643235574000",
"source_type": "navigation",
"reporting_origin": "https://a.r.test",
"source_origin": "https://a.s.test",
"Attribution-Reporting-Register-Source": {
"source_event_id": "123"
}
}]})json",
},
{
R"(["sources"][0]["source_type"]: must be either)",
R"json({"sources": [{
"timestamp": "1643235574000",
"source_type": "NAVIGATION",
"reporting_origin": "https://a.r.test",
"source_origin": "https://a.s.test"
}]})json",
},
{
R"(["sources"][0]["Attribution-Reporting-Register-Source"]["expiry"]: must be a positive number of)",
R"json({"sources": [{
"timestamp": "1643235574000",
"source_type": "navigation",
"reporting_origin": "https://a.r.test",
"source_origin": "https://a.s.test",
"Attribution-Reporting-Register-Source": {
"source_event_id": "123",
"destination": "https://a.d.test",
"expiry": "-5"
}
}]})json",
},
{
R"(["sources"][0]["Attribution-Reporting-Register-Source"]["priority"]: must be an int64)",
R"json({"sources": [{
"timestamp": "1643235574000",
"source_type": "navigation",
"reporting_origin": "https://a.r.test",
"source_origin": "https://a.s.test",
"Attribution-Reporting-Register-Source": {
"source_event_id": "123",
"destination": "https://a.d.test",
"priority": "x"
}
}]})json",
},
{
R"(["sources"][0]["Attribution-Reporting-Register-Source"]["source_event_id"]: must be a uint64 formatted)",
R"json({"sources": [{
"timestamp": "1643235574000",
"source_type": "navigation",
"reporting_origin": "https://a.r.test",
"source_origin": "https://a.s.test",
"Attribution-Reporting-Register-Source": {
"source_event_id": "x",
"destination": "https://a.d.test"
}
}]})json",
},
{
R"(["sources"][0]["Attribution-Reporting-Register-Source"]["filter_data"]: must be a dictionary)",
R"json({"sources": [{
"timestamp": "1643235574000",
"source_type": "navigation",
"reporting_origin": "https://a.r.test",
"source_origin": "https://a.s.test",
"Attribution-Reporting-Register-Source": {
"source_event_id": "123",
"destination": "https://a.d.test",
"filter_data": ""
}
}]})json",
},
{
R"(["sources"][0]["Attribution-Reporting-Register-Source"]["filter_data"]["a"]: must be a list)",
R"json({"sources": [{
"timestamp": "1643235574000",
"source_type": "navigation",
"reporting_origin": "https://a.r.test",
"source_origin": "https://a.s.test",
"Attribution-Reporting-Register-Source": {
"source_event_id": "123",
"destination": "https://a.d.test",
"filter_data": {
"a": "x"
}
}
}]})json",
},
{
R"(["sources"][0]["Attribution-Reporting-Register-Source"]["filter_data"]["a"][0]: must be a string)",
R"json({"sources": [{
"timestamp": "1643235574000",
"source_type": "navigation",
"reporting_origin": "https://a.r.test",
"source_origin": "https://a.s.test",
"Attribution-Reporting-Register-Source": {
"source_event_id": "123",
"destination": "https://a.d.test",
"filter_data": {
"a": [5]
}
}
}]})json",
},
{
R"(["sources"][0]["Attribution-Reporting-Register-Source"]["aggregation_keys"]: must be a dictionary)",
R"json({"sources": [{
"timestamp": "1643235574000",
"source_type": "event",
"reporting_origin": "https://a.r.test",
"source_origin": "https://a.s.test",
"Attribution-Reporting-Register-Source": {
"source_event_id": "123",
"destination": "https://a.d.test",
"aggregation_keys": ""
}
}]})json",
},
{
R"(["sources"][0]["Attribution-Reporting-Register-Source"]["aggregation_keys"]["a"]: must be a uint128 formatted as a base-16 string)",
R"json({"sources": [{
"timestamp": "1643235574000",
"source_type": "event",
"reporting_origin": "https://a.r.test",
"source_origin": "https://a.s.test",
"Attribution-Reporting-Register-Source": {
"source_event_id": "123",
"destination": "https://a.d.test",
"aggregation_keys": {
"a": "0xG"
}
}
}]})json",
},
{
R"(["sources"][0]["Attribution-Reporting-Register-Source"]["aggregation_keys"]["a"]: must be a uint128 formatted as a base-16 string)",
R"json({"sources": [{
"timestamp": "1643235574000",
"source_type": "event",
"reporting_origin": "https://a.r.test",
"source_origin": "https://a.s.test",
"Attribution-Reporting-Register-Source": {
"source_event_id": "123",
"destination": "https://a.d.test",
"aggregation_keys": {
"a": "123"
}
}
}]})json",
},
{
R"(["sources"]: must be a list)",
R"json({"sources": ""})json",
},
{
R"(["triggers"][0]["timestamp"]: must be an integer number of)",
R"json({"triggers": [{
"reporting_origin": "https://a.r.test",
"destination_origin": " https://a.d1.test",
"Attribution-Reporting-Register-Trigger": {}
}]})json",
},
{
R"(["triggers"][0]["destination_origin"]: must be a valid, secure origin)",
R"json({"triggers": [{
"timestamp": "1643235576000",
"reporting_origin": "https://a.r.test",
"Attribution-Reporting-Register-Trigger": {}
}]})json",
},
{
R"(["triggers"][0]["reporting_origin"]: must be a valid, secure origin)",
R"json({"triggers": [{
"timestamp": "1643235576000",
"destination_origin": " https://a.d1.test",
"Attribution-Reporting-Register-Trigger": {}
}]})json",
},
{
R"(["triggers"]: must be a list)",
R"json({"triggers": ""})json",
},
{
R"(["triggers"][0]["Attribution-Reporting-Register-Trigger"]: must be present)",
R"json({"triggers": [{}]})json",
},
{
R"(["triggers"][0]["Attribution-Reporting-Register-Trigger"]: must be a dictionary)",
R"json({"triggers": [{
"Attribution-Reporting-Register-Trigger": ""
}]})json",
},
{
R"(["triggers"][0]["Attribution-Reporting-Register-Trigger"]["event_trigger_data"]: must be a list)",
R"json({"triggers": [{
"Attribution-Reporting-Register-Trigger": {
"timestamp": "1643235576000",
"reporting_origin": "https://a.r.test",
"destination_origin": " https://a.d1.test",
"event_trigger_data": 1
}
}]})json",
},
{
R"(["triggers"][0]["Attribution-Reporting-Register-Trigger"]["aggregatable_trigger_data"]: must be a list)",
R"json({"triggers": [{
"Attribution-Reporting-Register-Trigger": {
"timestamp": "1643235576000",
"reporting_origin": "https://a.r.test",
"destination_origin": " https://a.d1.test",
"aggregatable_trigger_data": 5
}
}]})json",
},
{
R"(["triggers"][0]["Attribution-Reporting-Register-Trigger"]["aggregatable_trigger_data"][0]: must be a dictionary)",
R"json({"triggers": [{
"Attribution-Reporting-Register-Trigger": {
"timestamp": "1643235576000",
"reporting_origin": "https://a.r.test",
"destination_origin": " https://a.d1.test",
"aggregatable_trigger_data": [ 5 ]
}
}]})json",
},
{
R"(["triggers"][0]["Attribution-Reporting-Register-Trigger"]["aggregatable_trigger_data"][0]["source_keys"]: must be present)",
R"json({"triggers": [{
"Attribution-Reporting-Register-Trigger": {
"timestamp": "1643235576000",
"reporting_origin": "https://a.r.test",
"destination_origin": " https://a.d1.test",
"aggregatable_trigger_data": [{}]
}
}]})json",
},
{
R"(["triggers"][0]["Attribution-Reporting-Register-Trigger"]["aggregatable_trigger_data"][0]["source_keys"]: must be a list)",
R"json({"triggers": [{
"Attribution-Reporting-Register-Trigger": {
"timestamp": "1643235576000",
"reporting_origin": "https://a.r.test",
"destination_origin": " https://a.d1.test",
"aggregatable_trigger_data": [{
"source_keys": "a"
}]
}
}]})json",
},
{
R"(["triggers"][0]["Attribution-Reporting-Register-Trigger"]["aggregatable_trigger_data"][0]["source_keys"][0]: must be a string)",
R"json({"triggers": [{
"Attribution-Reporting-Register-Trigger": {
"timestamp": "1643235576000",
"reporting_origin": "https://a.r.test",
"destination_origin": " https://a.d1.test",
"aggregatable_trigger_data": [{
"source_keys": [ 5 ]
}]
}
}]})json",
},
{
R"(["triggers"][0]["Attribution-Reporting-Register-Trigger"]["aggregatable_trigger_data"][0]["key_piece"]: must be a uint128 formatted as a base-16 string)",
R"json({"triggers": [{
"Attribution-Reporting-Register-Trigger": {
"timestamp": "1643235576000",
"reporting_origin": "https://a.r.test",
"destination_origin": " https://a.d1.test",
"aggregatable_trigger_data": [{
"source_keys": [ "a" ],
"key_piece": "0xG"
}]
}
}]})json",
},
{
R"(["triggers"][0]["Attribution-Reporting-Register-Trigger"]["aggregatable_values"]: must be a dictionary)",
R"json({"triggers": [{
"Attribution-Reporting-Register-Trigger": {
"timestamp": "1643235576000",
"reporting_origin": "https://a.r.test",
"destination_origin": " https://a.d1.test",
"aggregatable_values": 5
}
}]})json",
},
{
R"(["triggers"][0]["Attribution-Reporting-Register-Trigger"]["aggregatable_values"]["a"]: must be a positive integer)",
R"json({"triggers": [{
"Attribution-Reporting-Register-Trigger": {
"timestamp": "1643235576000",
"reporting_origin": "https://a.r.test",
"destination_origin": " https://a.d1.test",
"aggregatable_values": {
"a": -5
}
}
}]})json",
},
{
R"(["triggers"][0]["Attribution-Reporting-Register-Trigger"]["event_trigger_data"][0]: must be a dictionary)",
R"json({"triggers":[{
"Attribution-Reporting-Register-Trigger": {
"timestamp": "1643235576000",
"reporting_origin": "https://a.r.test",
"destination_origin": " https://a.d1.test",
"event_trigger_data":[true]
}
}]})json",
},
{
R"(["cookies"][0]["timestamp"]: must be an integer number of milliseconds)",
R"json({"cookies": [{}]})json",
},
{
R"(["cookies"][0]["timestamp"]: must be an integer number of milliseconds)",
R"json({"cookies": [{
"timestamp": "9223372036854775"
}]})json",
},
{
R"(["cookies"][0]["url"]: must be a valid URL)",
R"json({"cookies": [{
"timestamp": "1643235576000"
}]})json",
},
{
R"(["cookies"][0]["url"]: must be a valid URL)",
R"json({"cookies": [{
"timestamp": "1643235576000",
"url": "!!!"
}]})json",
},
{
R"(["cookies"][0]["Set-Cookie"]: must be present)",
R"json({"cookies": [{
"timestamp": "1643235576000",
"url": "https://r.test"
}]})json",
},
{
R"(["cookies"][0]: invalid cookie)",
R"json({"cookies": [{
"timestamp": "1643235576000",
"url": "https://r.test",
"Set-Cookie": ""
}]})json",
},
{R"(["data_clears"][0]["timestamp"]: must be an integer number of milliseconds)",
R"json({"data_clears": [{}]})json"},
{R"(["data_clears"][0]["delete_begin"]: must be an integer number of milliseconds)",
R"json({"data_clears": [{
"timestamp": "1643235576000",
"delete_begin": ""
}]})json"},
{R"(["data_clears"][0]["delete_end"]: must be an integer number of milliseconds)",
R"json({"data_clears": [{
"timestamp": "1643235576000",
"delete_end": ""
}]})json"},
{R"(["data_clears"][0]["origins"]: must be a list)",
R"json({"data_clears": [{
"timestamp": "1643235576000",
"origins": ""
}]})json"},
{R"(["data_clears"][0]["origins"][0]: must be a string)",
R"json({"data_clears": [{
"timestamp": "1643235576000",
"origins": [1]
}]})json"}};
INSTANTIATE_TEST_SUITE_P(AttributionSimulatorInputParserInvalidInputs,
AttributionSimulatorInputParseErrorTest,
::testing::ValuesIn(kParseErrorTestCases));
} // namespace
} // namespace content