Flex API debug key list support and bug fixes
Bugs in assessing summary buckets and updating bucket amounts during
attribution were also addressed.
Bug: 307715563
Bug: 305247214
Test: atest com.android.adservices.service.measurement
Change-Id: Ic2282b5d4e398370689ae9b767510de7b8b796e1
diff --git a/adservices/service-core/java/com/android/adservices/service/measurement/AttributedTrigger.java b/adservices/service-core/java/com/android/adservices/service/measurement/AttributedTrigger.java
index 4866316..280a92d 100644
--- a/adservices/service-core/java/com/android/adservices/service/measurement/AttributedTrigger.java
+++ b/adservices/service-core/java/com/android/adservices/service/measurement/AttributedTrigger.java
@@ -32,6 +32,8 @@
private final long mValue;
private final long mTriggerTime;
private final UnsignedLong mDedupKey;
+ private final UnsignedLong mDebugKey;
+ private final Boolean mHasSourceDebugKey;
private long mContribution;
@Override
@@ -46,12 +48,22 @@
&& Objects.equals(mTriggerData, t.mTriggerData)
&& mValue == t.mValue
&& mTriggerTime == t.mTriggerTime
- && Objects.equals(mDedupKey, t.mDedupKey);
+ && Objects.equals(mDedupKey, t.mDedupKey)
+ && Objects.equals(mDebugKey, t.mDebugKey)
+ && Objects.equals(mHasSourceDebugKey, t.mHasSourceDebugKey);
}
@Override
public int hashCode() {
- return Objects.hash(mTriggerId, mPriority, mTriggerData, mValue, mTriggerTime, mDedupKey);
+ return Objects.hash(
+ mTriggerId,
+ mPriority,
+ mTriggerData,
+ mValue,
+ mTriggerTime,
+ mDedupKey,
+ mDebugKey,
+ mHasSourceDebugKey);
}
public AttributedTrigger(JSONObject json) throws JSONException {
@@ -83,6 +95,17 @@
} else {
mDedupKey = null;
}
+ if (!json.isNull(JsonKeys.DEBUG_KEY)) {
+ mDebugKey = new UnsignedLong(
+ json.getString(JsonKeys.DEBUG_KEY));
+ } else {
+ mDebugKey = null;
+ }
+ if (!json.isNull(JsonKeys.HAS_SOURCE_DEBUG_KEY)) {
+ mHasSourceDebugKey = json.getBoolean(JsonKeys.HAS_SOURCE_DEBUG_KEY);
+ } else {
+ mHasSourceDebugKey = null;
+ }
}
public AttributedTrigger(
@@ -91,6 +114,8 @@
UnsignedLong dedupKey) {
mTriggerId = triggerId;
mDedupKey = dedupKey;
+ mDebugKey = null;
+ mHasSourceDebugKey = null;
mPriority = 0L;
mTriggerData = triggerData;
mValue = 0L;
@@ -103,13 +128,17 @@
UnsignedLong triggerData,
long value,
long triggerTime,
- UnsignedLong dedupKey) {
+ UnsignedLong dedupKey,
+ UnsignedLong debugKey,
+ boolean hasSourceDebugKey) {
mTriggerId = triggerId;
mPriority = priority;
mTriggerData = triggerData;
mValue = value;
mTriggerTime = triggerTime;
mDedupKey = dedupKey;
+ mDebugKey = debugKey;
+ mHasSourceDebugKey = hasSourceDebugKey;
}
public String getTriggerId() {
@@ -136,6 +165,18 @@
return mDedupKey;
}
+ public UnsignedLong getDebugKey() {
+ return mDebugKey;
+ }
+
+ /**
+ * Returns whether the source debug key was permitted and populated when this trigger was
+ * attributed.
+ */
+ public boolean hasSourceDebugKey() {
+ return mHasSourceDebugKey;
+ }
+
public long getContribution() {
return mContribution;
}
@@ -180,6 +221,10 @@
if (mDedupKey != null) {
json.put(JsonKeys.DEDUP_KEY, mDedupKey.toString());
}
+ if (mDebugKey != null) {
+ json.put(JsonKeys.DEBUG_KEY, mDebugKey.toString());
+ }
+ json.put(JsonKeys.HAS_SOURCE_DEBUG_KEY, mHasSourceDebugKey);
json.put(TriggerSpecs.FlexEventReportJsonKeys.PRIORITY, mPriority);
} catch (JSONException e) {
LoggerFactory.getMeasurementLogger()
@@ -194,5 +239,7 @@
private interface JsonKeys {
String TRIGGER_ID = "trigger_id";
String DEDUP_KEY = "dedup_key";
+ String DEBUG_KEY = "debug_key";
+ String HAS_SOURCE_DEBUG_KEY = "has_source_debug_key";
}
}
diff --git a/adservices/service-core/java/com/android/adservices/service/measurement/EventReport.java b/adservices/service-core/java/com/android/adservices/service/measurement/EventReport.java
index 3ac460e..66eba53 100644
--- a/adservices/service-core/java/com/android/adservices/service/measurement/EventReport.java
+++ b/adservices/service-core/java/com/android/adservices/service/measurement/EventReport.java
@@ -494,7 +494,8 @@
@NonNull AttributedTrigger attributedTrigger,
long reportTime,
@NonNull Pair<Long, Long> triggerSummaryBucket,
- @NonNull Pair<UnsignedLong, UnsignedLong> debugKeyPair,
+ @Nullable UnsignedLong sourceDebugKey,
+ @NonNull List<UnsignedLong> debugKeys,
@NonNull EventReportWindowCalcDelegate eventReportWindowCalcDelegate,
@NonNull SourceNoiseHandler sourceNoiseHandler,
List<Uri> eventReportDestinations) {
@@ -504,10 +505,10 @@
mBuilding.mStatus = Status.PENDING;
mBuilding.mAttributionDestinations = eventReportDestinations;
mBuilding.mSourceType = source.getSourceType();
- mBuilding.mSourceDebugKey = debugKeyPair.first;
- mBuilding.mTriggerDebugKey = debugKeyPair.second;
+ mBuilding.mSourceDebugKey = sourceDebugKey;
+ mBuilding.mTriggerDebugKeys = debugKeys;
mBuilding.mDebugReportStatus = DebugReportStatus.NONE;
- if (mBuilding.mSourceDebugKey != null && mBuilding.mTriggerDebugKey != null) {
+ if (mBuilding.mSourceDebugKey != null && debugKeys.size() > 0) {
mBuilding.mDebugReportStatus = DebugReportStatus.PENDING;
}
mBuilding.mSourceId = source.getId();
diff --git a/adservices/service-core/java/com/android/adservices/service/measurement/TriggerSpecs.java b/adservices/service-core/java/com/android/adservices/service/measurement/TriggerSpecs.java
index a4b01d2..1411c2e 100644
--- a/adservices/service-core/java/com/android/adservices/service/measurement/TriggerSpecs.java
+++ b/adservices/service-core/java/com/android/adservices/service/measurement/TriggerSpecs.java
@@ -276,13 +276,17 @@
continue;
}
- // Event reports are sorted by summary bucket so this event report must be either for
- // the first or the next bucket.
- triggerDataToBucketIndexMap.merge(
- eventReport.getTriggerData(), 1, (oldValue, value) -> oldValue + 1);
+ UnsignedLong triggerData = eventReport.getTriggerData();
- Pair<Long, Long> summaryBucket = eventReport.getTriggerSummaryBucket();
- long bucketSize = summaryBucket.second - summaryBucket.first + 1;
+ // Event reports are sorted by summary bucket so this event report must be either for
+ // the first or the next bucket. The index for the map is one higher, corresponding to
+ // the current bucket we'll start with for attribution.
+ triggerDataToBucketIndexMap.merge(triggerData, 1, (oldValue, value) -> oldValue + 1);
+
+ List<Long> buckets = getSummaryBucketsForTriggerData(triggerData);
+ int bucketIndex = triggerDataToBucketIndexMap.get(triggerData) - 1;
+ long prevBucket = bucketIndex == 0 ? 0L : buckets.get(bucketIndex - 1);
+ long bucketSize = buckets.get(bucketIndex) - prevBucket;
for (AttributedTrigger attributedTrigger : mAttributedTriggersRef) {
bucketSize -= restoreTriggerContributionAndGetBucketDelta(
@@ -315,8 +319,7 @@
return bucketSize;
// The trigger only covers some of the report's bucket.
} else {
- long diff = attributedTrigger.getValue()
- - attributedTrigger.getContribution();
+ long diff = attributedTrigger.remainingValue();
attributedTrigger.addContribution(diff);
return diff;
}
diff --git a/adservices/service-core/java/com/android/adservices/service/measurement/attribution/AttributionJobHandler.java b/adservices/service-core/java/com/android/adservices/service/measurement/attribution/AttributionJobHandler.java
index 2379456..1544aa6 100644
--- a/adservices/service-core/java/com/android/adservices/service/measurement/attribution/AttributionJobHandler.java
+++ b/adservices/service-core/java/com/android/adservices/service/measurement/attribution/AttributionJobHandler.java
@@ -760,20 +760,21 @@
Pair<UnsignedLong, UnsignedLong> debugKeyPair =
new DebugKeyAccessor(measurementDao).getDebugKeys(source, trigger);
- EventReport newEventReport =
- new EventReport.Builder()
- .populateFromSourceAndTrigger(
- source,
- trigger,
- eventTrigger,
- debugKeyPair,
- mEventReportWindowCalcDelegate,
- mSourceNoiseHandler,
- getEventReportDestinations(source, trigger.getDestinationType()))
- .build();
if (!mFlags.getMeasurementFlexibleEventReportingApiEnabled()
|| source.getTriggerSpecsString() == null
|| source.getTriggerSpecsString().isEmpty()) {
+ EventReport newEventReport =
+ new EventReport.Builder()
+ .populateFromSourceAndTrigger(
+ source,
+ trigger,
+ eventTrigger,
+ debugKeyPair,
+ mEventReportWindowCalcDelegate,
+ mSourceNoiseHandler,
+ getEventReportDestinations(
+ source, trigger.getDestinationType()))
+ .build();
if (!provisionEventReportQuota(source, trigger, newEventReport, measurementDao)) {
return TriggeringStatus.DROPPED;
}
@@ -792,7 +793,7 @@
&& !source.getTriggerSpecsString().isEmpty()) {
try {
source.buildTriggerSpecs();
- if (!provisionEventReportFlexEventApiQuota(
+ if (!generateFlexEventReports(
source, trigger, eventTrigger, debugKeyPair, measurementDao)) {
return TriggeringStatus.DROPPED;
}
@@ -806,37 +807,28 @@
return TriggeringStatus.ATTRIBUTED;
}
- private boolean provisionEventReportFlexEventApiQuota(
+ private static int restoreTriggerContributionsAndProvisionFlexEventReportQuota(
Source source,
Trigger trigger,
- EventTrigger eventTrigger,
- Pair<UnsignedLong, UnsignedLong> debugKeyPair,
- IMeasurementDao measurementDao)
- throws DatastoreException {
- TriggerSpecs triggerSpecs = source.getTriggerSpecs();
-
- if (!triggerSpecs.containsTriggerData(eventTrigger.getTriggerData())) {
- return false;
- }
+ Map<UnsignedLong, Integer> triggerDataToBucketIndexMap,
+ IMeasurementDao measurementDao) throws DatastoreException {
List<EventReport> sourceEventReports = measurementDao.getSourceEventReports(source);
List<EventReport> reportsToDelete = new ArrayList<>();
- // Store the current bucket index for each trigger data
- Map<UnsignedLong, Integer> triggerDataToBucketIndexMap = new HashMap<>();
- triggerSpecs.prepareFlexAttribution(
+ source.getTriggerSpecs().prepareFlexAttribution(
sourceEventReports,
trigger.getTriggerTime(),
reportsToDelete,
triggerDataToBucketIndexMap);
- int numEventReports = sourceEventReports.size() - reportsToDelete.size();
- int maxEventReports = triggerSpecs.getMaxReports();
+ int numEarlierScheduledReports = sourceEventReports.size() - reportsToDelete.size();
+ int maxEventReports = source.getTriggerSpecs().getMaxReports();
// Completed reports already covered the allotted quota.
- if (numEventReports == maxEventReports) {
- return false;
+ if (numEarlierScheduledReports == maxEventReports) {
+ return 0;
}
// Delete pending reports. We will recreate an updated sequence below.
@@ -844,15 +836,49 @@
measurementDao.deleteEventReport(eventReport);
}
+ return maxEventReports - numEarlierScheduledReports;
+ }
+
+ private boolean generateFlexEventReports(
+ Source source,
+ Trigger trigger,
+ EventTrigger eventTrigger,
+ Pair<UnsignedLong, UnsignedLong> debugKeyPair,
+ IMeasurementDao measurementDao) throws DatastoreException {
+ TriggerSpecs triggerSpecs = source.getTriggerSpecs();
+
+ if (!triggerSpecs.containsTriggerData(eventTrigger.getTriggerData())) {
+ return false;
+ }
+
+ // Store the current bucket index for each trigger data
+ Map<UnsignedLong, Integer> triggerDataToBucketIndexMap = new HashMap<>();
+
+ int remainingReportQuota =
+ restoreTriggerContributionsAndProvisionFlexEventReportQuota(
+ source, trigger, triggerDataToBucketIndexMap, measurementDao);
+
+ if (remainingReportQuota == 0) {
+ return false;
+ }
+
List<AttributedTrigger> attributedTriggers = source.getAttributedTriggers();
+ long triggerValue =
+ triggerSpecs.getSummaryOperatorType(eventTrigger.getTriggerData())
+ == TriggerSpec.SummaryOperatorType.COUNT
+ ? 1L
+ : eventTrigger.getTriggerValue();
+
attributedTriggers.add(new AttributedTrigger(
trigger.getId(),
eventTrigger.getTriggerPriority(),
eventTrigger.getTriggerData(),
- eventTrigger.getTriggerValue(),
+ triggerValue,
trigger.getTriggerTime(),
- eventTrigger.getDedupKey()));
+ eventTrigger.getDedupKey(),
+ debugKeyPair.second,
+ debugKeyPair.first != null));
attributedTriggers.sort(
Comparator.comparingLong(AttributedTrigger::getPriority).reversed()
@@ -860,6 +886,8 @@
// Store for each trigger data any amount already covered for the current bucket.
Map<UnsignedLong, Long> triggerDataToBucketAmountMap = new HashMap<>();
+ Map<UnsignedLong, List<AttributedTrigger>> triggerDataToContributingTriggersMap =
+ new HashMap<>();
for (AttributedTrigger attributedTrigger : attributedTriggers) {
// Flex API already inserts the attributed trigger and does not need an explicit action
@@ -870,19 +898,17 @@
measurementDao.updateSourceEventReportDedupKeys(source);
}
- numEventReports += updateFlexAttributionStateAndGetNumReports(
+ remainingReportQuota -= updateFlexAttributionStateAndGetNumReports(
source,
trigger,
attributedTrigger,
- debugKeyPair,
- numEventReports,
- maxEventReports,
- triggerSpecs,
+ remainingReportQuota,
triggerDataToBucketIndexMap,
triggerDataToBucketAmountMap,
+ triggerDataToContributingTriggersMap,
measurementDao);
- if (numEventReports == maxEventReports) {
+ if (remainingReportQuota == 0) {
break;
}
}
@@ -891,6 +917,7 @@
source.getId(),
source.attributedTriggersToJsonFlexApi());
+ // TODO (b/307786346): represent actual report count.
return true;
}
@@ -898,17 +925,15 @@
Source source,
Trigger trigger,
AttributedTrigger attributedTrigger,
- Pair<UnsignedLong, UnsignedLong> debugKeyPair,
- int numEventReports,
- int maxEventReports,
- TriggerSpecs triggerSpecs,
+ int remainingReportQuota,
Map<UnsignedLong, Integer> triggerDataToBucketIndexMap,
Map<UnsignedLong, Long> triggerDataToBucketAmountMap,
+ Map<UnsignedLong, List<AttributedTrigger>> triggerDataToContributingTriggersMap,
IMeasurementDao measurementDao) throws DatastoreException {
+ TriggerSpecs triggerSpecs = source.getTriggerSpecs();
UnsignedLong triggerData = attributedTrigger.getTriggerData();
triggerDataToBucketIndexMap.putIfAbsent(triggerData, 0);
- triggerDataToBucketAmountMap.putIfAbsent(triggerData, 0L);
int bucketIndex = triggerDataToBucketIndexMap.get(triggerData);
List<Long> buckets = triggerSpecs.getSummaryBucketsForTriggerData(triggerData);
@@ -919,62 +944,53 @@
return 0;
}
+ triggerDataToBucketAmountMap.putIfAbsent(triggerData, 0L);
+ triggerDataToContributingTriggersMap.putIfAbsent(triggerData, new ArrayList<>());
+
+ List<AttributedTrigger> contributingTriggers =
+ triggerDataToContributingTriggersMap.get(triggerData);
+ if (attributedTrigger.remainingValue() > 0L) {
+ contributingTriggers.add(attributedTrigger);
+ }
+
long prevBucket = bucketIndex == 0 ? 0L : buckets.get(bucketIndex - 1);
- long bucketSize = buckets.get(bucketIndex) - prevBucket;
int numReportsCreated = 0;
- // value_sum operator
- if (triggerSpecs.getSummaryOperatorType(triggerData)
- == TriggerSpec.SummaryOperatorType.VALUE_SUM) {
- for (int i = bucketIndex; i < buckets.size(); i++) {
- long bucket = buckets.get(i);
- bucketSize = bucket - prevBucket;
- long bucketAmount = triggerDataToBucketAmountMap.get(triggerData);
+ for (int i = bucketIndex; i < buckets.size(); i++) {
+ long bucket = buckets.get(i);
+ long bucketSize = bucket - prevBucket;
+ long bucketAmount = triggerDataToBucketAmountMap.get(triggerData);
- if (attributedTrigger.remainingValue() >= bucketSize - bucketAmount) {
- finalizeEventReportCreationForFlex(
- source,
- trigger,
- attributedTrigger,
- debugKeyPair,
- TriggerSpecs.getSummaryBucketFromIndex(i, buckets),
- measurementDao);
- numReportsCreated += 1;
- attributedTrigger.addContribution(bucketSize - bucketAmount);
- triggerDataToBucketIndexMap.put(triggerData, i + 1);
- triggerDataToBucketAmountMap.put(triggerData, 0L);
-
- if (numEventReports + numReportsCreated == maxEventReports) {
- return numReportsCreated;
- }
- } else {
- triggerDataToBucketIndexMap.put(triggerData, i);
- long diff = attributedTrigger.getValue()
- - attributedTrigger.getContribution();
- triggerDataToBucketAmountMap.put(triggerData, diff);
- attributedTrigger.addContribution(diff);
- break;
- }
- prevBucket = bucket;
- }
- // count operator for a trigger that we haven't yet counted.
- } else if (attributedTrigger.getContribution() == 0) {
- if (bucketSize - triggerDataToBucketAmountMap.get(triggerData) == 1) {
+ if (attributedTrigger.remainingValue() >= bucketSize - bucketAmount) {
finalizeEventReportCreationForFlex(
source,
trigger,
attributedTrigger,
- debugKeyPair,
- TriggerSpecs.getSummaryBucketFromIndex(bucketIndex, buckets),
+ contributingTriggers,
+ TriggerSpecs.getSummaryBucketFromIndex(i, buckets),
measurementDao);
numReportsCreated += 1;
- triggerDataToBucketIndexMap.put(triggerData, bucketIndex + 1);
+
+ if (remainingReportQuota - numReportsCreated == 0) {
+ return numReportsCreated;
+ }
+
+ attributedTrigger.addContribution(bucketSize - bucketAmount);
+ triggerDataToBucketIndexMap.put(triggerData, i + 1);
triggerDataToBucketAmountMap.put(triggerData, 0L);
- attributedTrigger.addContribution(1L);
+ contributingTriggers.clear();
+ if (attributedTrigger.remainingValue() > 0L) {
+ contributingTriggers.add(attributedTrigger);
+ }
} else {
+ triggerDataToBucketIndexMap.put(triggerData, i);
+ long diff = attributedTrigger.remainingValue();
triggerDataToBucketAmountMap.merge(
- triggerData, 0L, (oldValue, value) -> oldValue + 1L);
+ triggerData, diff, (oldValue, value) -> oldValue + diff);
+ attributedTrigger.addContribution(diff);
+ break;
}
+ prevBucket = bucket;
}
return numReportsCreated;
@@ -1085,7 +1101,7 @@
Source source,
Trigger trigger,
AttributedTrigger attributedTrigger,
- Pair<UnsignedLong, UnsignedLong> debugKeyPair,
+ List<AttributedTrigger> contributingTriggers,
Pair<Long, Long> triggerSummaryBucket,
IMeasurementDao measurementDao)
throws DatastoreException {
@@ -1102,6 +1118,8 @@
// much earlier were the actual attributed triggers counted towards the bucket.
trigger.getTriggerTime(),
attributedTrigger.getTriggerData());
+ Pair<UnsignedLong, List<UnsignedLong>> debugKeys =
+ getDebugKeysForFlex(contributingTriggers, source);
EventReport eventReport =
new EventReport.Builder()
.getForFlex(
@@ -1110,7 +1128,8 @@
attributedTrigger,
reportTime,
triggerSummaryBucket,
- debugKeyPair,
+ debugKeys.first,
+ debugKeys.second,
mEventReportWindowCalcDelegate,
mSourceNoiseHandler,
getEventReportDestinations(
@@ -1474,6 +1493,36 @@
: WebAddresses.topPrivateDomainAndScheme(uri);
}
+ private static Pair<UnsignedLong, List<UnsignedLong>> getDebugKeysForFlex(
+ List<AttributedTrigger> contributingTriggers, Source source) {
+ List<UnsignedLong> triggerDebugKeys = new ArrayList<>();
+ // To provide a source debug key in the event report, the source debug key must have been
+ // populated for each evaluation for source and trigger for all triggers contributing to the
+ // bucket.
+ boolean allBucketContributorsHadNonNullSourceDebugKeys = true;
+ for (AttributedTrigger trigger : contributingTriggers) {
+ // Only add a debug key to the result if the invariant is maintained. Otherwise, the
+ // invariant has been broken, but conclude the iteration to process source debug-key.
+ if (trigger.getDebugKey() != null) {
+ triggerDebugKeys.add(trigger.getDebugKey());
+ }
+ // Update the value of the boolean for source debug key as a series of AND
+ // operations that must all be true.
+ allBucketContributorsHadNonNullSourceDebugKeys &= trigger.hasSourceDebugKey();
+ }
+ // We are allowed to access the actual source debug key value if the invariant has been
+ // maintained.
+ UnsignedLong sourceDebugKey = allBucketContributorsHadNonNullSourceDebugKeys
+ ? source.getDebugKey()
+ : null;
+ // All triggers must have debug keys for the report to include any.
+ if (contributingTriggers.size() == triggerDebugKeys.size()) {
+ return Pair.create(sourceDebugKey, triggerDebugKeys);
+ } else {
+ return Pair.create(sourceDebugKey, Collections.emptyList());
+ }
+ }
+
private static boolean hasDeduplicationKey(@NonNull Source source,
@NonNull UnsignedLong dedupKey) {
for (AttributedTrigger attributedTrigger : source.getAttributedTriggers()) {
diff --git a/adservices/service-core/java/com/android/adservices/service/measurement/reporting/ReportUtil.java b/adservices/service-core/java/com/android/adservices/service/measurement/reporting/ReportUtil.java
index 82cd379..8c74428 100644
--- a/adservices/service-core/java/com/android/adservices/service/measurement/reporting/ReportUtil.java
+++ b/adservices/service-core/java/com/android/adservices/service/measurement/reporting/ReportUtil.java
@@ -71,13 +71,13 @@
* Prepare summary bucket for report JSON
*
* @param summaryBucket the summary bucket
- * @return the string encoded summary bucket in format [start, end]
+ * @return the encoded summary bucket in format [start, end]
*/
@Nullable
- public static String serializeSummaryBucket(@NonNull Pair<Long, Long> summaryBucket) {
+ public static JSONArray serializeSummaryBucket(@NonNull Pair<Long, Long> summaryBucket) {
JSONArray result = new JSONArray();
result.put(summaryBucket.first);
result.put(summaryBucket.second);
- return result.toString();
+ return result;
}
}
diff --git a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_incremental_bucket_larger_than_one_for_count_generate_report.json b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_incremental_bucket_larger_than_one_for_count_generate_report.json
index 55f8320..6c5e51c 100644
--- a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_incremental_bucket_larger_than_one_for_count_generate_report.json
+++ b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_incremental_bucket_larger_than_one_for_count_generate_report.json
@@ -137,7 +137,7 @@
"source_event_id": "2",
"trigger_data": "0",
"source_type": "event",
- "trigger_summary_bucket": "[2,2147483646]",
+ "trigger_summary_bucket": [2, 2147483646],
"randomized_trigger_rate": 0.000002494582008677539
}
}
diff --git a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_mixed_priority_for_multiple_reports.json b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_mixed_priority_for_multiple_reports.json
index a77d8f1..8072324 100644
--- a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_mixed_priority_for_multiple_reports.json
+++ b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_mixed_priority_for_multiple_reports.json
@@ -137,7 +137,7 @@
"source_event_id": "123",
"trigger_data": "1",
"source_type": "event",
- "trigger_summary_bucket": "[10,19]",
+ "trigger_summary_bucket": [10, 19],
"randomized_trigger_rate": 0.00001663031163901838
}
},
@@ -150,7 +150,7 @@
"source_event_id": "123",
"trigger_data": "0",
"source_type": "event",
- "trigger_summary_bucket": "[10,19]",
+ "trigger_summary_bucket": [10, 19],
"randomized_trigger_rate": 0.00001663031163901838
}
},
diff --git a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_mixed_priority_for_one_report.json b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_mixed_priority_for_one_report.json
index 1bda7c6..67bde2d 100644
--- a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_mixed_priority_for_one_report.json
+++ b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_mixed_priority_for_one_report.json
@@ -1,5 +1,5 @@
{
- "description": "One event source with two trigger specs, followed by three triggers. The last two triggers that have the highest priority win attribution.",
+ "description": "One event source followed by three triggers. The last two triggers that have the highest priority win attribution.",
"phflags_override": {
"measurement_flexible_event_reporting_api_enabled": "true"
},
@@ -136,7 +136,7 @@
"source_event_id": "123",
"trigger_data": "1",
"source_type": "event",
- "trigger_summary_bucket": "[10,99]",
+ "trigger_summary_bucket": [10, 99],
"randomized_trigger_rate": 0.0000033261065791548415
}
}
diff --git a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_one_sources_default_event_three_triggers.json b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_one_sources_default_event_three_triggers.json
index af6423e..7477e2a 100644
--- a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_one_sources_default_event_three_triggers.json
+++ b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_one_sources_default_event_three_triggers.json
@@ -137,7 +137,7 @@
"source_event_id": "2",
"trigger_data": "1",
"source_type": "event",
- "trigger_summary_bucket": "[1,2147483646]",
+ "trigger_summary_bucket": [1, 2147483646],
"randomized_trigger_rate": 0.000002494582008677539
}
}
diff --git a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_one_sources_default_nav_three_triggers.json b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_one_sources_default_nav_three_triggers.json
index 78301d4..fc7e05e 100644
--- a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_one_sources_default_nav_three_triggers.json
+++ b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_one_sources_default_nav_three_triggers.json
@@ -145,7 +145,7 @@
"source_event_id": "2",
"trigger_data": "2",
"source_type": "navigation",
- "trigger_summary_bucket": "[1,1]",
+ "trigger_summary_bucket": [1, 1],
"randomized_trigger_rate": 0.0001371835308365974
}
},
@@ -158,7 +158,7 @@
"source_event_id": "2",
"trigger_data": "1",
"source_type": "navigation",
- "trigger_summary_bucket": "[1,1]",
+ "trigger_summary_bucket": [1, 1],
"randomized_trigger_rate": 0.0001371835308365974
}
},
diff --git a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_trigger_data_partial_mismatch.json b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_trigger_data_partial_mismatch.json
index 54d9c49..6018b0f 100644
--- a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_trigger_data_partial_mismatch.json
+++ b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_trigger_data_partial_mismatch.json
@@ -145,7 +145,7 @@
"source_event_id": "2",
"trigger_data": "2",
"source_type": "navigation",
- "trigger_summary_bucket": "[1,1]",
+ "trigger_summary_bucket": [1, 1],
"randomized_trigger_rate": 0.0001371835308365974
}
},
@@ -158,7 +158,7 @@
"source_event_id": "2",
"trigger_data": "1",
"source_type": "navigation",
- "trigger_summary_bucket": "[1,1]",
+ "trigger_summary_bucket": [1, 1],
"randomized_trigger_rate": 0.0001371835308365974
}
}
diff --git a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_two_specs_trigger_priority_wins.json b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_two_specs_trigger_priority_wins.json
index a09b035..20248b3 100644
--- a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_two_specs_trigger_priority_wins.json
+++ b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_two_specs_trigger_priority_wins.json
@@ -146,7 +146,7 @@
"source_event_id": "123",
"trigger_data": "0",
"source_type": "event",
- "trigger_summary_bucket": "[1,1]",
+ "trigger_summary_bucket": [1, 1],
"randomized_trigger_rate": 0.00001746181270119995
}
},
@@ -159,7 +159,7 @@
"source_event_id": "123",
"trigger_data": "2",
"source_type": "event",
- "trigger_summary_bucket": "[1,1]",
+ "trigger_summary_bucket": [1, 1],
"randomized_trigger_rate": 0.00001746181270119995
}
}
diff --git a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_dedup_key_remove_trigger.json b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_dedup_key_remove_trigger.json
index c28b506..7fd2690 100644
--- a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_dedup_key_remove_trigger.json
+++ b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_dedup_key_remove_trigger.json
@@ -116,7 +116,7 @@
"source_event_id": "2",
"trigger_data": "0",
"source_type": "navigation",
- "trigger_summary_bucket": "[10,99]",
+ "trigger_summary_bucket": [10, 99],
"randomized_trigger_rate": 0.000012472785585841613
}
}
diff --git a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_no_trigger_dedup_key.json b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_no_trigger_dedup_key.json
index 2e03c47..36fedaf 100644
--- a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_no_trigger_dedup_key.json
+++ b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_no_trigger_dedup_key.json
@@ -138,7 +138,7 @@
"source_event_id": "2",
"trigger_data": "1",
"source_type": "event",
- "trigger_summary_bucket": "[10,2147483646]",
+ "trigger_summary_bucket": [10, 2147483646],
"randomized_trigger_rate": 0.000002494582008677539
}
}
diff --git a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_no_trigger_event_data.json b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_no_trigger_event_data.json
index df8eb9e..894a649 100644
--- a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_no_trigger_event_data.json
+++ b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_no_trigger_event_data.json
@@ -145,7 +145,7 @@
"source_event_id": "2",
"trigger_data": "0",
"source_type": "navigation",
- "trigger_summary_bucket": "[10,99]",
+ "trigger_summary_bucket": [10, 99],
"randomized_trigger_rate": 0.000012472785585841613
}
}
diff --git a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_source_across_report_window.json b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_source_across_report_window_debug_report.json
similarity index 72%
rename from adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_source_across_report_window.json
rename to adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_source_across_report_window_debug_report.json
index d82870a..e585eec 100644
--- a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_source_across_report_window.json
+++ b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_source_across_report_window_debug_report.json
@@ -1,5 +1,5 @@
{
- "description": "value sum on navigation source, triggers are across multiple window",
+ "description": "value sum on navigation source, triggers are across multiple window, includes debug report.",
"phflags_override": {
"measurement_flexible_event_reporting_api_enabled": "true"
},
@@ -14,6 +14,7 @@
"responses": [
{
"url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
"response": {
"Attribution-Reporting-Register-Source": {
"source_event_id": "2",
@@ -39,7 +40,8 @@
]
}
],
- "max_event_level_reports": 1
+ "max_event_level_reports": 1,
+ "debug_key": "333"
},
"Location": null,
"Attribution-Reporting-Redirect": null
@@ -58,6 +60,7 @@
"responses": [
{
"url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
"response": {
"Attribution-Reporting-Register-Trigger": {
"event_trigger_data": [
@@ -67,7 +70,9 @@
"deduplication_key": "10",
"value": "2"
}
- ]
+ ],
+ "debug_key": "444",
+ "debug_reporting": true
},
"Location": null,
"Attribution-Reporting-Redirect": null
@@ -84,6 +89,7 @@
"responses": [
{
"url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
"response": {
"Attribution-Reporting-Register-Trigger": {
"event_trigger_data": [
@@ -93,7 +99,9 @@
"deduplication_key": "11",
"value": "9"
}
- ]
+ ],
+ "debug_key": "555",
+ "debug_reporting": true
},
"Location": null,
"Attribution-Reporting-Redirect": null
@@ -115,8 +123,27 @@
"source_event_id": "2",
"trigger_data": "0",
"source_type": "navigation",
- "trigger_summary_bucket": "[10,2147483646]",
- "randomized_trigger_rate": 0.000004157629766763622
+ "source_debug_key": "333",
+ "trigger_summary_bucket": [10, 2147483646],
+ "randomized_trigger_rate": 0.000004157629766763622,
+ "trigger_debug_keys": ["555", "444"]
+ }
+ }
+ ],
+ "debug_event_level_results": [
+ {
+ "report_time": "1800203600001",
+ "report_url": "https://www.ad-tech1.test/.well-known/attribution-reporting/debug/report-event-attribution",
+ "payload": {
+ "attribution_destination": "android-app://example.2d1.test",
+ "scheduled_report_time": "1800599000",
+ "source_event_id": "2",
+ "trigger_data": "0",
+ "source_type": "navigation",
+ "source_debug_key": "333",
+ "trigger_summary_bucket": [10, 2147483646],
+ "randomized_trigger_rate": 0.000004157629766763622,
+ "trigger_debug_keys": ["555", "444"]
}
}
],
diff --git a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_source_base_case_generate_report_one_trigger.json b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_source_base_case_generate_report_one_trigger.json
index 98ecc80..10ac7d1 100644
--- a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_source_base_case_generate_report_one_trigger.json
+++ b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_source_base_case_generate_report_one_trigger.json
@@ -140,7 +140,7 @@
"source_event_id": "2",
"trigger_data": "0",
"source_type": "event",
- "trigger_summary_bucket": "[10,2147483646]",
+ "trigger_summary_bucket": [10, 2147483646],
"randomized_trigger_rate": 0.000002494582008677539
}
}
diff --git a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_source_multiple_buckets.json b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_source_multiple_buckets.json
index 29179a3..d0b94e9 100644
--- a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_source_multiple_buckets.json
+++ b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_event_source_multiple_buckets.json
@@ -116,7 +116,7 @@
"source_event_id": "2",
"trigger_data": "0",
"source_type": "navigation",
- "trigger_summary_bucket": "[10,99]",
+ "trigger_summary_bucket": [10, 99],
"randomized_trigger_rate": 0.000012472785585841613
}
},
@@ -129,7 +129,7 @@
"source_event_id": "2",
"trigger_data": "0",
"source_type": "navigation",
- "trigger_summary_bucket": "[100,2147483646]",
+ "trigger_summary_bucket": [100, 2147483646],
"randomized_trigger_rate": 0.000012472785585841613
}
}
diff --git a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_two_specs_two_report_windows_debug_report.json b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_two_specs_two_report_windows_debug_report.json
new file mode 100644
index 0000000..a851971
--- /dev/null
+++ b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_two_specs_two_report_windows_debug_report.json
@@ -0,0 +1,469 @@
+{
+ // Source's trigger specs:
+ //
+ // trigger_data: [0, 1]
+ // end_times: [3600, 7200]
+ // summary_buckets: [10, 50]
+ //
+ // trigger_data: [2, 3]
+ // end_times: [5400, 9000]
+ // summary_buckets: [20, 70]
+ //
+ // max_event_level_reports: 4
+ //
+ // Triggers:
+ //
+ // T1 time 1200, data 0, value 9, priority 200, debug key 1
+ // T2 time 2000, data 1, value 10, priority 150
+ // T3 time 2400, data 0, value 30, priority 100, debug key 3
+ // T4 time 3000, data 2, value 18, priority 150, debug key 4
+ //
+ // Report window 1 at 3600:
+ // Trigger ordering: T1 -> T3 -> T2 -> T4
+ // * T1 + T3 (data 0) generate report and debug report, bucket at 10 (+29 at priority 100)
+ // * T2 (data 1) generates report, bucket at 10
+ // T4 (data 2) does not generate a report, bucket at 18
+ // Fully contributed: T1, T2
+ //
+ // T5 time 4000, data 2, value 1, priority 150, debug key 5
+ // T6 time 5000, data 3, value 19, priority 130
+ // T7 time 5300, data 2, value 40, priority 400
+ //
+ // Report window 1 at 5400:
+ // Trigger ordering: T7 -> T4 -> T5 -> T6 -> T3
+ // * T7 (data 2) generates a report, bucket at 20 (+20 at priority 400)
+ // T4 (data 2) adds to bucket, bucket at 58
+ // T5 (data 2) adds to bucket, bucket at 59
+ // T6 (data 3) does not generate a report, bucket at 19
+ // T3 (data 0) does not generate a report, bucket at 39
+ //
+ // T8 time 6000, data 0, value 5, priority 90
+ // T9 time 6500, data 2, value 20, priority 50, debug key 9
+ // T10 time 7000, data 0, value 20, priority 50, debug key 10
+ //
+ // Report window 2 at 7200:
+ // Trigger ordering: T7 -> T4 -> T5 -> T6 -> T3 -> T8 -> T9 -> T10
+ // T7 + T4 + T5 (data 2) get bucket to 59
+ // T6 (data 3) does not generate a report, bucket at 19
+ // T3 + T8 (data 0) get bucket to 44
+ // * T9 (data 2) crosses bucket to generate a speculative report but no debug report
+ // because T7 is missing a debug key, bucket at 70 (+9 at priority 50)
+ // T10 (data 0) would cross bucket to generate a report, but quota was reached
+ //
+ // Report window 2 at 9000:
+ // Report is sent for T7 + T4 + T5 + T9
+ // Fully contributed: T4, T5, T7
+ "description": "One event source with two trigger specs, see comment above for full description.",
+ "phflags_override": {
+ "measurement_flex_api_max_information_gain_navigation": 15,
+ "measurement_flexible_event_reporting_api_enabled": "true",
+ "measurement_min_event_report_delay_millis": 0
+ },
+ "input": {
+ "sources": [
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "source_type": "navigation",
+ "registrant": "example.1s1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
+ "response": {
+ "Attribution-Reporting-Register-Source": {
+ "source_event_id": "123",
+ "destination": "android-app://example.2d1.test",
+ "trigger_specs": [
+ {
+ "trigger_data": [0, 1],
+ "event_report_windows": {
+ "end_times": [3600, 7200]
+ },
+ "summary_window_operator": "value_sum",
+ "summary_buckets": [10, 50]
+ },
+ {
+ "trigger_data": [2, 3],
+ "event_report_windows": {
+ "end_times": [5400, 9000]
+ },
+ "summary_window_operator": "value_sum",
+ "summary_buckets": [20, 70]
+ }
+ ],
+ "max_event_level_reports": 4,
+ "debug_key": "111"
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "0"
+ }
+ ],
+ "triggers": [
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "0",
+ "value": "9",
+ "priority": "200"
+ }
+ ],
+ "debug_key": "1"
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "1200000"
+ },
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ // Ad ID permission results in a report with the source debug key
+ "has_ad_id_permission": true,
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "1",
+ "value": "10",
+ "priority": "150"
+ }
+ ]
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "2000000"
+ },
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "0",
+ "value": "30",
+ "priority": "100"
+ }
+ ],
+ "debug_key": "3"
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "2400000"
+ },
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "2",
+ "value": "18",
+ "priority": "150"
+ }
+ ],
+ "debug_key": "4"
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "3000000"
+ },
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "2",
+ "value": "1",
+ "priority": "150"
+ }
+ ],
+ "debug_key": "5"
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "4000000"
+ },
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "3",
+ "value": "19",
+ "priority": "130"
+ }
+ ]
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "5000000"
+ },
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "2",
+ "value": "40",
+ "priority": "400"
+ }
+ ]
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "5300000"
+ },
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "0",
+ "value": "5",
+ "priority": "90"
+ }
+ ]
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "6000000"
+ },
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "2",
+ "value": "20",
+ "priority": "50"
+ }
+ ],
+ "debug_key": "9"
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "6500000"
+ },
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "0",
+ "value": "20",
+ "priority": "50"
+ }
+ ],
+ "debug_key": "10"
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "7000000"
+ }
+ ]
+ },
+ "output": {
+ "event_level_results": [
+ {
+ "report_time": "3600000",
+ "report_url": "https://www.ad-tech1.test/.well-known/attribution-reporting/report-event-attribution",
+ "payload": {
+ "attribution_destination": "android-app://example.2d1.test",
+ "scheduled_report_time": "3600",
+ "source_event_id": "123",
+ "trigger_data": "1",
+ "source_type": "navigation",
+ "source_debug_key": "111",
+ "trigger_summary_bucket": [10, 49],
+ "randomized_trigger_rate": 0.00030175409301020603
+ }
+ },
+ {
+ "report_time": "3600000",
+ "report_url": "https://www.ad-tech1.test/.well-known/attribution-reporting/report-event-attribution",
+ "payload": {
+ "attribution_destination": "android-app://example.2d1.test",
+ "scheduled_report_time": "3600",
+ "source_event_id": "123",
+ "trigger_data": "0",
+ "source_type": "navigation",
+ "source_debug_key": "111",
+ "trigger_debug_keys": ["1", "3"],
+ "trigger_summary_bucket": [10, 49],
+ "randomized_trigger_rate": 0.00030175409301020603
+ }
+ },
+ {
+ "report_time": "5400000",
+ "report_url": "https://www.ad-tech1.test/.well-known/attribution-reporting/report-event-attribution",
+ "payload": {
+ "attribution_destination": "android-app://example.2d1.test",
+ "scheduled_report_time": "5400",
+ "source_event_id": "123",
+ "trigger_data": "2",
+ "source_type": "navigation",
+ "source_debug_key": "111",
+ "trigger_summary_bucket": [20, 69],
+ "randomized_trigger_rate": 0.00030175409301020603
+ }
+ },
+ {
+ "report_time": "9000000",
+ "report_url": "https://www.ad-tech1.test/.well-known/attribution-reporting/report-event-attribution",
+ "payload": {
+ "attribution_destination": "android-app://example.2d1.test",
+ "scheduled_report_time": "9000",
+ "source_event_id": "123",
+ "trigger_data": "2",
+ "source_type": "navigation",
+ "source_debug_key": "111",
+ "trigger_summary_bucket": [70, 2147483646],
+ "randomized_trigger_rate": 0.00030175409301020603
+ }
+ }
+ ],
+ "debug_event_level_results": [
+ {
+ "report_time": "2400000",
+ "report_url": "https://www.ad-tech1.test/.well-known/attribution-reporting/debug/report-event-attribution",
+ "payload": {
+ "attribution_destination": "android-app://example.2d1.test",
+ "scheduled_report_time": "3600",
+ "source_event_id": "123",
+ "trigger_data": "0",
+ "source_type": "navigation",
+ "source_debug_key": "111",
+ "trigger_debug_keys": ["1", "3"],
+ "trigger_summary_bucket": [10, 49],
+ "randomized_trigger_rate": 0.00030175409301020603
+ }
+ },
+ {
+ "report_time": "3000000",
+ "report_url": "https://www.ad-tech1.test/.well-known/attribution-reporting/debug/report-event-attribution",
+ "payload": {
+ "attribution_destination": "android-app://example.2d1.test",
+ "scheduled_report_time": "3600",
+ "source_event_id": "123",
+ "trigger_data": "0",
+ "source_type": "navigation",
+ "source_debug_key": "111",
+ "trigger_debug_keys": ["1", "3"],
+ "trigger_summary_bucket": [10, 49],
+ "randomized_trigger_rate": 0.00030175409301020603
+ }
+ }
+ ],
+ "aggregatable_results": []
+ }
+}
diff --git a/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_two_specs_two_report_windows_multiple_debug_keys.json b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_two_specs_two_report_windows_multiple_debug_keys.json
new file mode 100644
index 0000000..7ef78fb
--- /dev/null
+++ b/adservices/tests/unittest/service-core/assets/msmt_e2e_tests/flex_event/flex_event_value_sum_two_specs_two_report_windows_multiple_debug_keys.json
@@ -0,0 +1,515 @@
+{
+ // Source's trigger specs:
+ //
+ // trigger_data: [0, 1]
+ // end_times: [3600, 7200]
+ // summary_buckets: [10, 50]
+ //
+ // trigger_data: [2, 3]
+ // end_times: [5400, 9000]
+ // summary_buckets: [20, 70]
+ //
+ // max_event_level_reports: 4
+ //
+ // Triggers:
+ //
+ // T1 time 1200, data 0, value 9, priority 200, debug key 1
+ // T2 time 2000, data 1, value 10, priority 150
+ // T3 time 2400, data 0, value 30, priority 100, debug key 3
+ // T4 time 3000, data 2, value 18, priority 150, debug key 4
+ //
+ // Report window 1 at 3600:
+ // Trigger ordering: T1 -> T3 -> T2 -> T4
+ // * T1 + T3 (data 0) generate report and debug report, bucket at 10 (+29 at priority 100)
+ // * T2 (data 1) generates report, bucket at 10
+ // T4 (data 2) does not generate a report, bucket at 18
+ // Fully contributed: T1, T2
+ //
+ // T5 time 4000, data 2, value 1, priority 150, debug key 5
+ // T6 time 5000, data 3, value 19, priority 130
+ // T7 time 5300, data 2, value 40, priority 400, debug key 7
+ //
+ // Report window 1 at 5400:
+ // Trigger ordering: T7 -> T4 -> T5 -> T6 -> T3
+ // * T7 (data 2) generates a report, bucket at 20 (+20 at priority 400)
+ // T4 (data 2) adds to bucket, bucket at 58
+ // T5 (data 2) adds to bucket, bucket at 59
+ // T6 (data 3) does not generate a report, bucket at 19
+ // T3 (data 0) does not generate a report, bucket at 39
+ //
+ // T8 time 6000, data 0, value 5, priority 90
+ // T9 time 6500, data 2, value 20, priority 50, debug key 9
+ // T10 time 7000, data 0, value 20, priority 50, debug key 10
+ //
+ // Report window 2 at 7200:
+ // Trigger ordering: T7 -> T4 -> T5 -> T6 -> T3 -> T8 -> T9 -> T10
+ // T7 + T4 + T5 (data 2) get bucket to 59
+ // T6 (data 3) does not generate a report, bucket at 19
+ // T3 + T8 (data 0) get bucket to 44
+ // * T9 (data 2) crosses bucket to generate a speculative report and debug report,
+ // bucket at 70 (+9 at priority 50)
+ // T10 (data 0) would cross bucket to generate a report, but quota was reached
+ //
+ // Report window 2 at 9000:
+ // Report is sent for T7 + T4 + T5 + T9
+ // Fully contributed: T4, T5, T7
+ "description": "One event source with two trigger specs, see comment above for full description.",
+ "phflags_override": {
+ "measurement_flex_api_max_information_gain_navigation": 15,
+ "measurement_flexible_event_reporting_api_enabled": "true",
+ "measurement_min_event_report_delay_millis": 0
+ },
+ "input": {
+ "sources": [
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "source_type": "navigation",
+ "registrant": "example.1s1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
+ "response": {
+ "Attribution-Reporting-Register-Source": {
+ "source_event_id": "123",
+ "destination": "android-app://example.2d1.test",
+ "trigger_specs": [
+ {
+ "trigger_data": [0, 1],
+ "event_report_windows": {
+ "end_times": [3600, 7200]
+ },
+ "summary_window_operator": "value_sum",
+ "summary_buckets": [10, 50]
+ },
+ {
+ "trigger_data": [2, 3],
+ "event_report_windows": {
+ "end_times": [5400, 9000]
+ },
+ "summary_window_operator": "value_sum",
+ "summary_buckets": [20, 70]
+ }
+ ],
+ "max_event_level_reports": 4,
+ "debug_key": "111"
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "0"
+ }
+ ],
+ "triggers": [
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "0",
+ "value": "9",
+ "priority": "200"
+ }
+ ],
+ "debug_key": "1"
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "1200000"
+ },
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ // No Ad ID permission results in a report without the source debug key
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "1",
+ "value": "10",
+ "priority": "150"
+ }
+ ]
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "2000000"
+ },
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "0",
+ "value": "30",
+ "priority": "100"
+ }
+ ],
+ "debug_key": "3"
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "2400000"
+ },
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "2",
+ "value": "18",
+ "priority": "150"
+ }
+ ],
+ "debug_key": "4"
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "3000000"
+ },
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "2",
+ "value": "1",
+ "priority": "150"
+ }
+ ],
+ "debug_key": "5"
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "4000000"
+ },
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "3",
+ "value": "19",
+ "priority": "130"
+ }
+ ]
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "5000000"
+ },
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "2",
+ "value": "40",
+ "priority": "400"
+ }
+ ],
+ "debug_key": "7"
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "5300000"
+ },
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "0",
+ "value": "5",
+ "priority": "90"
+ }
+ ]
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "6000000"
+ },
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "2",
+ "value": "20",
+ "priority": "50"
+ }
+ ],
+ "debug_key": "9"
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "6500000"
+ },
+ {
+ "registration_request": {
+ "attribution_src_url": "https://www.ad-tech1.test",
+ "registrant": "example.2d1.test"
+ },
+ "responses": [
+ {
+ "url": "https://www.ad-tech1.test",
+ "has_ad_id_permission": true,
+ "response": {
+ "Attribution-Reporting-Register-Trigger": {
+ "event_trigger_data": [
+ {
+ "trigger_data": "0",
+ "value": "20",
+ "priority": "50"
+ }
+ ],
+ "debug_key": "10"
+ },
+ "Location": null,
+ "Attribution-Reporting-Redirect": null
+ }
+ }
+ ],
+ "timestamp": "7000000"
+ }
+ ]
+ },
+ "output": {
+ "event_level_results": [
+ {
+ "report_time": "3600000",
+ "report_url": "https://www.ad-tech1.test/.well-known/attribution-reporting/report-event-attribution",
+ "payload": {
+ "attribution_destination": "android-app://example.2d1.test",
+ "scheduled_report_time": "3600",
+ "source_event_id": "123",
+ "trigger_data": "1",
+ "source_type": "navigation",
+ "trigger_summary_bucket": [10, 49],
+ "randomized_trigger_rate": 0.00030175409301020603
+ }
+ },
+ {
+ "report_time": "3600000",
+ "report_url": "https://www.ad-tech1.test/.well-known/attribution-reporting/report-event-attribution",
+ "payload": {
+ "attribution_destination": "android-app://example.2d1.test",
+ "scheduled_report_time": "3600",
+ "source_event_id": "123",
+ "trigger_data": "0",
+ "source_type": "navigation",
+ "source_debug_key": "111",
+ "trigger_debug_keys": ["1", "3"],
+ "trigger_summary_bucket": [10, 49],
+ "randomized_trigger_rate": 0.00030175409301020603
+ }
+ },
+ {
+ "report_time": "5400000",
+ "report_url": "https://www.ad-tech1.test/.well-known/attribution-reporting/report-event-attribution",
+ "payload": {
+ "attribution_destination": "android-app://example.2d1.test",
+ "scheduled_report_time": "5400",
+ "source_event_id": "123",
+ "trigger_data": "2",
+ "source_type": "navigation",
+ "source_debug_key": "111",
+ "trigger_debug_keys": ["7"],
+ "trigger_summary_bucket": [20, 69],
+ "randomized_trigger_rate": 0.00030175409301020603
+ }
+ },
+ {
+ "report_time": "9000000",
+ "report_url": "https://www.ad-tech1.test/.well-known/attribution-reporting/report-event-attribution",
+ "payload": {
+ "attribution_destination": "android-app://example.2d1.test",
+ "scheduled_report_time": "9000",
+ "source_event_id": "123",
+ "trigger_data": "2",
+ "source_type": "navigation",
+ "source_debug_key": "111",
+ "trigger_debug_keys": ["7", "4", "5", "9"],
+ "trigger_summary_bucket": [70, 2147483646],
+ "randomized_trigger_rate": 0.00030175409301020603
+ }
+ }
+ ],
+ "debug_event_level_results": [
+ {
+ "report_time": "2400000",
+ "report_url": "https://www.ad-tech1.test/.well-known/attribution-reporting/debug/report-event-attribution",
+ "payload": {
+ "attribution_destination": "android-app://example.2d1.test",
+ "scheduled_report_time": "3600",
+ "source_event_id": "123",
+ "trigger_data": "0",
+ "source_type": "navigation",
+ "source_debug_key": "111",
+ "trigger_debug_keys": ["1", "3"],
+ "trigger_summary_bucket": [10, 49],
+ "randomized_trigger_rate": 0.00030175409301020603
+ }
+ },
+ {
+ "report_time": "3000000",
+ "report_url": "https://www.ad-tech1.test/.well-known/attribution-reporting/debug/report-event-attribution",
+ "payload": {
+ "attribution_destination": "android-app://example.2d1.test",
+ "scheduled_report_time": "3600",
+ "source_event_id": "123",
+ "trigger_data": "0",
+ "source_type": "navigation",
+ "source_debug_key": "111",
+ "trigger_debug_keys": ["1", "3"],
+ "trigger_summary_bucket": [10, 49],
+ "randomized_trigger_rate": 0.00030175409301020603
+ }
+ },
+ {
+ "report_time": "5300000",
+ "report_url": "https://www.ad-tech1.test/.well-known/attribution-reporting/debug/report-event-attribution",
+ "payload": {
+ "attribution_destination": "android-app://example.2d1.test",
+ "scheduled_report_time": "5400",
+ "source_event_id": "123",
+ "trigger_data": "2",
+ "source_type": "navigation",
+ "source_debug_key": "111",
+ "trigger_debug_keys": ["7"],
+ "trigger_summary_bucket": [20, 69],
+ "randomized_trigger_rate": 0.00030175409301020603
+ }
+ },
+ {
+ "report_time": "6500000",
+ "report_url": "https://www.ad-tech1.test/.well-known/attribution-reporting/debug/report-event-attribution",
+ "payload": {
+ "attribution_destination": "android-app://example.2d1.test",
+ "scheduled_report_time": "9000",
+ "source_event_id": "123",
+ "trigger_data": "2",
+ "source_type": "navigation",
+ "source_debug_key": "111",
+ "trigger_debug_keys": ["7", "4", "5", "9"],
+ "trigger_summary_bucket": [70, 2147483646],
+ "randomized_trigger_rate": 0.00030175409301020603
+ }
+ },
+ {
+ "report_time": "7000000",
+ "report_url": "https://www.ad-tech1.test/.well-known/attribution-reporting/debug/report-event-attribution",
+ "payload": {
+ "attribution_destination": "android-app://example.2d1.test",
+ "scheduled_report_time": "9000",
+ "source_event_id": "123",
+ "trigger_data": "2",
+ "source_type": "navigation",
+ "source_debug_key": "111",
+ "trigger_debug_keys": ["7", "4", "5", "9"],
+ "trigger_summary_bucket": [70, 2147483646],
+ "randomized_trigger_rate": 0.00030175409301020603
+ }
+ }
+ ],
+ "aggregatable_results": []
+ }
+}
diff --git a/adservices/tests/unittest/service-core/src/com/android/adservices/data/measurement/MeasurementDaoTest.java b/adservices/tests/unittest/service-core/src/com/android/adservices/data/measurement/MeasurementDaoTest.java
index 51b4abc..91071e7 100644
--- a/adservices/tests/unittest/service-core/src/com/android/adservices/data/measurement/MeasurementDaoTest.java
+++ b/adservices/tests/unittest/service-core/src/com/android/adservices/data/measurement/MeasurementDaoTest.java
@@ -9963,7 +9963,9 @@
eventReport.getTriggerData(),
eventReport.getTriggerValue(),
eventReport.getTriggerTime(),
- eventReport.getTriggerDedupKey()));
+ eventReport.getTriggerDedupKey(),
+ eventReport.getTriggerDebugKey(),
+ false));
}
private static void insertAttributedTrigger(List<AttributedTrigger> attributedTriggers,
diff --git a/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/AttributedTriggerTest.java b/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/AttributedTriggerTest.java
index 9b7dc1e..ed9a8b6 100644
--- a/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/AttributedTriggerTest.java
+++ b/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/AttributedTriggerTest.java
@@ -41,6 +41,10 @@
private static final long TRIGGER_TIME2 = 1689564817010L;
private static final UnsignedLong DEDUP_KEY1 = new UnsignedLong("453");
private static final UnsignedLong DEDUP_KEY2 = new UnsignedLong("357");
+ private static final UnsignedLong DEBUG_KEY1 = new UnsignedLong("980");
+ private static final UnsignedLong DEBUG_KEY2 = new UnsignedLong("812");
+ private static final boolean HAS_SOURCE_DEBUG_KEY1 = true;
+ private static final boolean HAS_SOURCE_DEBUG_KEY2 = false;
private static final long CONTRIBUTION = 50L;
@Test
@@ -52,14 +56,18 @@
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1),
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1),
new AttributedTrigger(
TRIGGER_ID1,
PRIORITY1,
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1));
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1));
}
@Test
@@ -71,14 +79,18 @@
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1),
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1),
new AttributedTrigger(
TRIGGER_ID2,
PRIORITY1,
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1));
+ DEDUP_KEY1,
+ DEDUP_KEY1,
+ HAS_SOURCE_DEBUG_KEY1));
assertNotEquals(
new AttributedTrigger(
TRIGGER_ID1,
@@ -86,14 +98,18 @@
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1),
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1),
new AttributedTrigger(
TRIGGER_ID1,
PRIORITY2,
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1));
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1));
assertNotEquals(
new AttributedTrigger(
TRIGGER_ID1,
@@ -101,14 +117,18 @@
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1),
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1),
new AttributedTrigger(
TRIGGER_ID1,
PRIORITY1,
TRIGGER_DATA2,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1));
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1));
assertNotEquals(
new AttributedTrigger(
TRIGGER_ID1,
@@ -116,14 +136,18 @@
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1),
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1),
new AttributedTrigger(
TRIGGER_ID1,
PRIORITY1,
TRIGGER_DATA1,
VALUE2,
TRIGGER_TIME1,
- DEDUP_KEY1));
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1));
assertNotEquals(
new AttributedTrigger(
TRIGGER_ID1,
@@ -131,14 +155,18 @@
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1),
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1),
new AttributedTrigger(
TRIGGER_ID1,
PRIORITY1,
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME2,
- DEDUP_KEY1));
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1));
assertNotEquals(
new AttributedTrigger(
TRIGGER_ID1,
@@ -146,14 +174,56 @@
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1),
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1),
new AttributedTrigger(
TRIGGER_ID1,
PRIORITY1,
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY2));
+ DEDUP_KEY2,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1));
+ assertNotEquals(
+ new AttributedTrigger(
+ TRIGGER_ID1,
+ PRIORITY1,
+ TRIGGER_DATA1,
+ VALUE1,
+ TRIGGER_TIME1,
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1),
+ new AttributedTrigger(
+ TRIGGER_ID1,
+ PRIORITY1,
+ TRIGGER_DATA1,
+ VALUE1,
+ TRIGGER_TIME1,
+ DEDUP_KEY1,
+ DEBUG_KEY2,
+ HAS_SOURCE_DEBUG_KEY1));
+ assertNotEquals(
+ new AttributedTrigger(
+ TRIGGER_ID1,
+ PRIORITY1,
+ TRIGGER_DATA1,
+ VALUE1,
+ TRIGGER_TIME1,
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1),
+ new AttributedTrigger(
+ TRIGGER_ID1,
+ PRIORITY1,
+ TRIGGER_DATA1,
+ VALUE1,
+ TRIGGER_TIME1,
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY2));
}
@Test
@@ -165,14 +235,18 @@
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1).hashCode(),
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1).hashCode(),
new AttributedTrigger(
TRIGGER_ID1,
PRIORITY1,
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1).hashCode());
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1).hashCode());
}
@Test
@@ -184,14 +258,18 @@
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1).hashCode(),
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1).hashCode(),
new AttributedTrigger(
TRIGGER_ID2,
PRIORITY1,
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1).hashCode());
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1).hashCode());
assertNotEquals(
new AttributedTrigger(
TRIGGER_ID1,
@@ -199,14 +277,18 @@
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1).hashCode(),
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1).hashCode(),
new AttributedTrigger(
TRIGGER_ID1,
PRIORITY2,
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1).hashCode());
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1).hashCode());
assertNotEquals(
new AttributedTrigger(
TRIGGER_ID1,
@@ -214,14 +296,18 @@
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1).hashCode(),
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1).hashCode(),
new AttributedTrigger(
TRIGGER_ID1,
PRIORITY1,
TRIGGER_DATA2,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1).hashCode());
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1).hashCode());
assertNotEquals(
new AttributedTrigger(
TRIGGER_ID1,
@@ -229,14 +315,18 @@
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1).hashCode(),
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1).hashCode(),
new AttributedTrigger(
TRIGGER_ID1,
PRIORITY1,
TRIGGER_DATA1,
VALUE2,
TRIGGER_TIME1,
- DEDUP_KEY1).hashCode());
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1).hashCode());
assertNotEquals(
new AttributedTrigger(
TRIGGER_ID1,
@@ -244,14 +334,18 @@
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1).hashCode(),
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1).hashCode(),
new AttributedTrigger(
TRIGGER_ID1,
PRIORITY1,
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME2,
- DEDUP_KEY1).hashCode());
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1).hashCode());
assertNotEquals(
new AttributedTrigger(
TRIGGER_ID1,
@@ -259,14 +353,56 @@
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1).hashCode(),
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1).hashCode(),
new AttributedTrigger(
TRIGGER_ID1,
PRIORITY1,
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY2).hashCode());
+ DEDUP_KEY2,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1).hashCode());
+ assertNotEquals(
+ new AttributedTrigger(
+ TRIGGER_ID1,
+ PRIORITY1,
+ TRIGGER_DATA1,
+ VALUE1,
+ TRIGGER_TIME1,
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1).hashCode(),
+ new AttributedTrigger(
+ TRIGGER_ID1,
+ PRIORITY1,
+ TRIGGER_DATA1,
+ VALUE1,
+ TRIGGER_TIME1,
+ DEDUP_KEY1,
+ DEBUG_KEY2,
+ HAS_SOURCE_DEBUG_KEY1).hashCode());
+ assertNotEquals(
+ new AttributedTrigger(
+ TRIGGER_ID1,
+ PRIORITY1,
+ TRIGGER_DATA1,
+ VALUE1,
+ TRIGGER_TIME1,
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1).hashCode(),
+ new AttributedTrigger(
+ TRIGGER_ID1,
+ PRIORITY1,
+ TRIGGER_DATA1,
+ VALUE1,
+ TRIGGER_TIME1,
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY2).hashCode());
}
@Test
@@ -278,7 +414,9 @@
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1);
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1);
attributedTrigger.addContribution(CONTRIBUTION);
assertEquals(CONTRIBUTION, attributedTrigger.getContribution());
@@ -288,6 +426,8 @@
assertEquals(VALUE1, attributedTrigger.getValue());
assertEquals(TRIGGER_TIME1, attributedTrigger.getTriggerTime());
assertEquals(DEDUP_KEY1, attributedTrigger.getDedupKey());
+ assertEquals(DEBUG_KEY1, attributedTrigger.getDebugKey());
+ assertEquals(HAS_SOURCE_DEBUG_KEY1, attributedTrigger.hasSourceDebugKey());
}
@Test
@@ -299,7 +439,9 @@
TRIGGER_DATA1,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1);
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1);
attributedTrigger1.addContribution(CONTRIBUTION);
assertEquals(-45L, attributedTrigger1.remainingValue());
@@ -311,7 +453,9 @@
TRIGGER_DATA2,
VALUE2,
TRIGGER_TIME2,
- DEDUP_KEY2);
+ DEDUP_KEY2,
+ DEBUG_KEY2,
+ HAS_SOURCE_DEBUG_KEY2);
attributedTrigger2.addContribution(CONTRIBUTION);
assertEquals(16L, attributedTrigger2.remainingValue());
@@ -349,6 +493,8 @@
triggerObj.put("value", VALUE1);
triggerObj.put("trigger_time", TRIGGER_TIME1);
triggerObj.put("dedup_key", DEDUP_KEY1.toString());
+ triggerObj.put("debug_key", DEBUG_KEY1.toString());
+ triggerObj.put("has_source_debug_key", HAS_SOURCE_DEBUG_KEY1);
AttributedTrigger triggerFromJson = new AttributedTrigger(triggerObj);
JSONObject encodedObj = triggerFromJson.encodeToJsonFlexApi();
@@ -374,7 +520,9 @@
/* trigger data */ null,
VALUE1,
TRIGGER_TIME1,
- DEDUP_KEY1);
+ DEDUP_KEY1,
+ DEBUG_KEY1,
+ HAS_SOURCE_DEBUG_KEY1);
assertThrows(
NullPointerException.class,
diff --git a/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/E2ETest.java b/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/E2ETest.java
index 5e0ca01..04b0da9 100644
--- a/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/E2ETest.java
+++ b/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/E2ETest.java
@@ -127,6 +127,7 @@
"trigger_summary_bucket");
String DOUBLE = "randomized_trigger_rate";
String STRING_OR_ARRAY = "attribution_destination";
+ String ARRAY = "trigger_debug_keys";
}
interface AggregateReportPayloadKeys {
@@ -503,7 +504,7 @@
private static int hashForEventReportObject(OutputType outputType, JSONObject obj) {
int n = EventReportPayloadKeys.STRINGS.size();
- int numValuesExcludingN = 3;
+ int numValuesExcludingN = 4;
Object[] objArray = new Object[n + numValuesExcludingN];
// TODO (b/306863121) add time to hash
String url = obj.optString(TestFormatJsonMapping.REPORT_TO_KEY, "");
@@ -518,10 +519,12 @@
if (maybeString != null) {
objArray[2] = maybeString;
}
- JSONArray maybeArray = payload.optJSONArray(EventReportPayloadKeys.STRING_OR_ARRAY);
- if (maybeArray != null) {
- objArray[2] = maybeArray;
+ JSONArray maybeArray1 = payload.optJSONArray(EventReportPayloadKeys.STRING_OR_ARRAY);
+ if (maybeArray1 != null) {
+ objArray[2] = maybeArray1;
}
+ JSONArray maybeArray2 = payload.optJSONArray(EventReportPayloadKeys.ARRAY);
+ objArray[3] = maybeArray2;
for (int i = 0; i < n; i++) {
objArray[i + numValuesExcludingN] =
payload.optString(EventReportPayloadKeys.STRINGS.get(i), "");
@@ -592,6 +595,24 @@
return true;
}
+ private static boolean areNullOrEqualJSONArray(JSONArray expected, JSONArray actual)
+ throws JSONException {
+ if (expected == null) {
+ return actual == null;
+ } else if (actual == null) {
+ return false;
+ }
+ if (expected.length() != actual.length()) {
+ return false;
+ }
+ for (int i = 0; i < expected.length(); i++) {
+ if (!expected.getString(i).equals(actual.getString(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private boolean areEqualEventReportJsons(
ReportType reportType, JSONObject expected, JSONObject actual) throws JSONException {
JSONObject expectedPayload = expected.getJSONObject(TestFormatJsonMapping.PAYLOAD_KEY);
@@ -604,6 +625,13 @@
if (!areEqualStringOrJSONArray(
expectedPayload.get(EventReportPayloadKeys.STRING_OR_ARRAY),
actualPayload.get(EventReportPayloadKeys.STRING_OR_ARRAY))) {
+ log("Event payload string-or-array mismatch. Report type: " + reportType.name());
+ return false;
+ }
+ if (!areNullOrEqualJSONArray(
+ expectedPayload.optJSONArray(EventReportPayloadKeys.ARRAY),
+ actualPayload.optJSONArray(EventReportPayloadKeys.ARRAY))) {
+ log("Event payload array mismatch. Report type: " + reportType.name());
return false;
}
for (String key : EventReportPayloadKeys.STRINGS) {
@@ -895,6 +923,11 @@
result.append("JSONObject::get failed for EventReportPayloadKeys.STRING_OR_ARRAY "
+ e + "\n");
}
+ result.append(EventReportPayloadKeys.ARRAY + ": ")
+ .append(payload1.optJSONArray(EventReportPayloadKeys.ARRAY))
+ .append(" ::: ")
+ .append(payload2.optJSONArray(EventReportPayloadKeys.ARRAY))
+ .append("\n");
for (String key : EventReportPayloadKeys.STRINGS) {
result.append(key)
.append(": ")
@@ -925,6 +958,10 @@
result.append("JSONObject::get failed for EventReportPayloadKeys.STRING_OR_ARRAY "
+ e + "\n");
}
+ result.append(EventReportPayloadKeys.ARRAY + ": ")
+ .append(pad)
+ .append(payload.optJSONArray(EventReportPayloadKeys.ARRAY))
+ .append("\n");
for (String key : EventReportPayloadKeys.STRINGS) {
result.append(key).append(": ").append(pad).append(payload.optString(key)).append("\n");
}
@@ -999,12 +1036,25 @@
expiryTimes.add(
MEASUREMENT_MAX_REPORTING_REGISTER_SOURCE_EXPIRATION_IN_SECONDS);
}
+ if (sourceJson.has("event_report_windows")) {
+ expiryTimes.addAll(
+ getFlexEndTimes(sourceJson.getJSONObject("event_report_windows")));
+ }
}
}
return expiryTimes;
}
+ private static Set<Long> getFlexEndTimes(JSONObject eventReportWindows) throws JSONException {
+ Set<Long> endTimes = new HashSet<>();
+ JSONArray endTimesArray = eventReportWindows.getJSONArray("end_times");
+ for (int i = 0; i < endTimesArray.length(); i++) {
+ endTimes.add(endTimesArray.getLong(i));
+ }
+ return endTimes;
+ }
+
private static long roundSecondsToWholeDays(long seconds) {
long remainder = seconds % TimeUnit.DAYS.toSeconds(1);
boolean roundUp = remainder >= TimeUnit.DAYS.toSeconds(1) / 2L;
diff --git a/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/SourceTest.java b/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/SourceTest.java
index a29478b..baa43e8 100644
--- a/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/SourceTest.java
+++ b/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/SourceTest.java
@@ -82,7 +82,9 @@
/* UnsignedLong triggerData */ new UnsignedLong("89"),
/* long value */ 15L,
/* long triggerTime */ 1934567890L,
- /* UnsignedLong dedupKey */ null));
+ /* UnsignedLong dedupKey */ null,
+ /* UnsignedLong debugKey */ null,
+ /* boolean hasSourceDebugKey */ false));
@Mock private Flags mFlags;
@Before
diff --git a/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/attribution/AttributionJobHandlerTest.java b/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/attribution/AttributionJobHandlerTest.java
index 6ad9943..bd73dca 100644
--- a/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/attribution/AttributionJobHandlerTest.java
+++ b/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/attribution/AttributionJobHandlerTest.java
@@ -4824,36 +4824,45 @@
/**
* Status before attribution: 1 trigger attributed and 1 report generated; Incoming trigger
* status: 2 new reports should be generated; Result: 2 reports written into DB and no
- * competition condition.
+ * competition condition; debug reports and trigger debug keys populated only when all trigger
+ * contributors have debug keys.
*/
- public void performAttribution_flexEventReport_insertSecondTriggerNoCompeting()
+ public void performAttribution_flexEventReportTwoNonCompetingTriggersAllDebugReports()
throws DatastoreException, JSONException {
// Setup
long baseTime = System.currentTimeMillis();
+ UnsignedLong triggerData1 = new UnsignedLong(1L);
+ UnsignedLong triggerData2 = new UnsignedLong(2L);
+ UnsignedLong sourceDebugKey = new UnsignedLong(777L);
+ UnsignedLong debugKey1 = new UnsignedLong(4L);
+ UnsignedLong debugKey2 = new UnsignedLong(55L);
Trigger trigger =
TriggerFixture.getValidTriggerBuilder()
.setId("triggerId1")
+ .setDestinationType(EventSurfaceType.APP)
.setStatus(Trigger.Status.PENDING)
.setEventTriggers(
"[\n"
+ "{\n"
- + " \"trigger_data\": \"2\",\n"
- + " \"priority\": \"123\",\n"
- + " \"value\": \"105\",\n"
- + " \"deduplication_key\": \"123\"\n"
+ + " \"trigger_data\": \"" + triggerData2 + "\","
+ + " \"priority\": \"123\","
+ + " \"value\": \"105\","
+ + " \"deduplication_key\": \"123\""
+ "}"
- + "]\n")
+ + "]")
.setFilters(
- "[{\n"
- + " \"key_1\": [\"value_1\", \"value_2\"],\n"
- + " \"key_2\": [\"value_1\", \"value_2\"]\n"
- + "}]\n")
+ "[{"
+ + " \"key_1\": [\"value_1\", \"value_2\"],"
+ + " \"key_2\": [\"value_1\", \"value_2\"]"
+ + "}]")
.setTriggerTime(
baseTime
+ TimeUnit.DAYS.toMillis(1)
+ MEASUREMENT_MIN_EVENT_REPORT_DELAY_MILLIS)
.setAggregateTriggerData(buildAggregateTriggerData().toString())
.setAggregateValues("{\"campaignCounts\":32768,\"geoValue\":1644}")
+ .setAdIdPermission(true)
+ .setDebugKey(debugKey2)
.build();
Pair<Long, Long> firstBucket = Pair.create(10L, 99L);
@@ -4864,7 +4873,7 @@
.setId("100")
.setSourceEventId(new UnsignedLong(22L))
.setEnrollmentId("another-enrollment-id")
- .setAttributionDestinations(List.of(Uri.parse("https://bar.test")))
+ .setAttributionDestinations(List.of(Uri.parse("android-app://com.ignored")))
.setReportTime(
baseTime
+ TimeUnit.DAYS.toMillis(3)
@@ -4873,11 +4882,12 @@
.setSourceType(Source.SourceType.NAVIGATION)
.setRegistrationOrigin(WebUtil.validUri("https://adtech2.test"))
.setTriggerTime(baseTime + 3000L)
- .setTriggerData(new UnsignedLong(1L))
+ .setTriggerData(triggerData1)
.setTriggerPriority(123L)
.setTriggerValue(30)
.setTriggerSummaryBucket(firstBucket)
.setTriggerDedupKey(new UnsignedLong(3L))
+ .setTriggerDebugKey(debugKey1)
.build();
TriggerSpecs templateTriggerSpecs = SourceFixture.getValidTriggerSpecsValueSum();
@@ -4910,6 +4920,8 @@
.setEventAttributionStatus(existingAttributes.toString())
.setPrivacyParameters(
templateTriggerSpecs.encodePrivacyParametersToJSONString())
+ .setAdIdPermission(true)
+ .setDebugKey(sourceDebugKey)
.build();
when(mFlags.getMeasurementFlexibleEventReportingApiEnabled()).thenReturn(true);
@@ -4956,9 +4968,24 @@
assertEquals(firstBucket, insertedEventReports.get(0).getTriggerSummaryBucket());
assertEquals(firstBucket, insertedEventReports.get(1).getTriggerSummaryBucket());
assertEquals(secondBucket, insertedEventReports.get(2).getTriggerSummaryBucket());
- assertEquals(new UnsignedLong(1L), insertedEventReports.get(0).getTriggerData());
- assertEquals(new UnsignedLong(2L), insertedEventReports.get(1).getTriggerData());
- assertEquals(new UnsignedLong(2L), insertedEventReports.get(2).getTriggerData());
+ assertEquals(triggerData1, insertedEventReports.get(0).getTriggerData());
+ assertEquals(triggerData2, insertedEventReports.get(1).getTriggerData());
+ assertEquals(triggerData2, insertedEventReports.get(2).getTriggerData());
+ assertEquals(List.of(debugKey1), insertedEventReports.get(0).getTriggerDebugKeys());
+ assertEquals(List.of(debugKey2), insertedEventReports.get(1).getTriggerDebugKeys());
+ assertEquals(List.of(debugKey2), insertedEventReports.get(2).getTriggerDebugKeys());
+ assertNull(insertedEventReports.get(0).getSourceDebugKey());
+ assertEquals(sourceDebugKey, insertedEventReports.get(1).getSourceDebugKey());
+ assertEquals(sourceDebugKey, insertedEventReports.get(2).getSourceDebugKey());
+ assertEquals(
+ EventReport.DebugReportStatus.NONE,
+ insertedEventReports.get(0).getDebugReportStatus());
+ assertEquals(
+ EventReport.DebugReportStatus.PENDING,
+ insertedEventReports.get(1).getDebugReportStatus());
+ assertEquals(
+ EventReport.DebugReportStatus.PENDING,
+ insertedEventReports.get(2).getDebugReportStatus());
long reportTime = TimeUnit.DAYS.toMillis(2) + MEASUREMENT_MIN_EVENT_REPORT_DELAY_MILLIS;
assertEquals(reportTime, insertedEventReports.get(0).getReportTime() - baseTime);
assertEquals(reportTime, insertedEventReports.get(1).getReportTime() - baseTime);
@@ -4972,36 +4999,44 @@
}
@Test
- /**
+ /*
* Status before attribution: 1 trigger attributed and 2 report generated with triggerData 1;
* Incoming trigger status: 2 reports should be generated for triggerData 2 Result: incoming
- * trigger has higher priority and one previous report should be deleted
+ * trigger has higher priority and one previous report should be deleted; debug reports and
+ * trigger debug keys populated only when all trigger contributors have debug keys.
*/
- public void performAttribution_flexEventReport_insertSecondTriggerCompetingHigherPriority()
+ public void performAttribution_flexEventReportSecondTriggerHigherPriorityAllDebugReports()
throws DatastoreException, JSONException {
// Setup
long baseTime = System.currentTimeMillis();
+ UnsignedLong triggerData1 = new UnsignedLong(1L);
+ UnsignedLong triggerData2 = new UnsignedLong(2L);
+ UnsignedLong sourceDebugKey = new UnsignedLong(777L);
+ UnsignedLong debugKey1 = new UnsignedLong(4L);
+ UnsignedLong debugKey2 = new UnsignedLong(55L);
Trigger trigger =
TriggerFixture.getValidTriggerBuilder()
.setId("triggerId1")
.setStatus(Trigger.Status.PENDING)
.setEventTriggers(
- "[\n"
- + "{\n"
- + " \"trigger_data\": \"2\",\n"
- + " \"priority\": \"123\",\n"
- + " \"value\": \"105\",\n"
- + " \"deduplication_key\": \"1234\"\n"
+ "["
+ + "{"
+ + " \"trigger_data\": \"" + triggerData2 + "\","
+ + " \"priority\": \"123\","
+ + " \"value\": \"105\","
+ + " \"deduplication_key\": \"1234\""
+ "}"
- + "]\n")
+ + "]")
.setFilters(
- "[{\n"
- + " \"key_1\": [\"value_1\", \"value_2\"],\n"
- + " \"key_2\": [\"value_1\", \"value_2\"]\n"
- + "}]\n")
+ "[{"
+ + " \"key_1\": [\"value_1\", \"value_2\"],"
+ + " \"key_2\": [\"value_1\", \"value_2\"]"
+ + "}]")
.setTriggerTime(baseTime + TimeUnit.DAYS.toMillis(1) + 4800000)
.setAggregateTriggerData(buildAggregateTriggerData().toString())
.setAggregateValues("{\"campaignCounts\":32768,\"geoValue\":1644}")
+ .setAdIdPermission(true)
+ .setDebugKey(debugKey2)
.build();
final EventReport.Builder eventReportBuilder =
@@ -5018,10 +5053,11 @@
.setSourceType(Source.SourceType.NAVIGATION)
.setRegistrationOrigin(WebUtil.validUri("https://adtech2.test"))
.setTriggerTime(baseTime + TimeUnit.DAYS.toMillis(1))
- .setTriggerData(new UnsignedLong(1L))
+ .setTriggerData(triggerData1)
.setTriggerPriority(121L)
.setTriggerValue(101)
- .setTriggerDedupKey(new UnsignedLong(3L));
+ .setTriggerDedupKey(new UnsignedLong(3L))
+ .setTriggerDebugKey(debugKey1);
TriggerSpecs templateTriggerSpecs = SourceFixture.getValidTriggerSpecsValueSum();
JSONArray existingAttributes = new JSONArray();
@@ -5037,10 +5073,10 @@
.setAggregateSource(
"{\"campaignCounts\" : \"0x159\", \"geoValue\" : \"0x5\"}")
.setFilterData(
- "{\n"
- + " \"key_1\": [\"value_1\", \"value_2\"],\n"
- + " \"key_2\": [\"value_1\", \"value_2\"]\n"
- + "}\n")
+ "{"
+ + " \"key_1\": [\"value_1\", \"value_2\"],"
+ + " \"key_2\": [\"value_1\", \"value_2\"]"
+ + "}")
.setEventTime(baseTime)
.setEventReportWindow(
baseTime
@@ -5055,6 +5091,8 @@
.setEventAttributionStatus(existingAttributes.toString())
.setPrivacyParameters(
templateTriggerSpecs.encodePrivacyParametersToJSONString())
+ .setAdIdPermission(true)
+ .setDebugKey(sourceDebugKey)
.build();
Pair<Long, Long> firstBucket = Pair.create(10L, 99L);
@@ -5113,9 +5151,24 @@
assertEquals(firstBucket, insertedEventReports.get(0).getTriggerSummaryBucket());
assertEquals(secondBucket, insertedEventReports.get(1).getTriggerSummaryBucket());
assertEquals(firstBucket, insertedEventReports.get(2).getTriggerSummaryBucket());
- assertEquals(new UnsignedLong(2L), insertedEventReports.get(0).getTriggerData());
- assertEquals(new UnsignedLong(2L), insertedEventReports.get(1).getTriggerData());
- assertEquals(new UnsignedLong(1L), insertedEventReports.get(2).getTriggerData());
+ assertEquals(triggerData2, insertedEventReports.get(0).getTriggerData());
+ assertEquals(triggerData2, insertedEventReports.get(1).getTriggerData());
+ assertEquals(triggerData1, insertedEventReports.get(2).getTriggerData());
+ assertEquals(List.of(debugKey2), insertedEventReports.get(0).getTriggerDebugKeys());
+ assertEquals(List.of(debugKey2), insertedEventReports.get(1).getTriggerDebugKeys());
+ assertEquals(List.of(debugKey1), insertedEventReports.get(2).getTriggerDebugKeys());
+ assertEquals(sourceDebugKey, insertedEventReports.get(0).getSourceDebugKey());
+ assertEquals(sourceDebugKey, insertedEventReports.get(1).getSourceDebugKey());
+ assertNull(insertedEventReports.get(2).getSourceDebugKey());
+ assertEquals(
+ EventReport.DebugReportStatus.PENDING,
+ insertedEventReports.get(0).getDebugReportStatus());
+ assertEquals(
+ EventReport.DebugReportStatus.PENDING,
+ insertedEventReports.get(1).getDebugReportStatus());
+ assertEquals(
+ EventReport.DebugReportStatus.NONE,
+ insertedEventReports.get(2).getDebugReportStatus());
assertEquals(2, deletedReportsCaptor.getAllValues().size());
long reportTime = TimeUnit.DAYS.toMillis(2) + MEASUREMENT_MIN_EVENT_REPORT_DELAY_MILLIS;
assertEquals(reportTime, insertedEventReports.get(0).getReportTime() - baseTime);
@@ -5128,41 +5181,48 @@
}
@Test
- /**
+ /*
* Status before attribution: 1 trigger attributed and 2 report generated with triggerData 1;
* Incoming trigger status: 2 reports should be generated for triggerData 2 Result: incoming
* trigger has lower priority, no previous report should be deleted and only 1 new report
- * inserted into DB
+ * inserted into DB; debug reports and trigger debug keys populated only when all trigger
+ * contributors have debug keys.
*/
- public void performAttribution_flexEventReport_insertSecondTriggerCompetingLowerPriority()
+ public void performAttribution_flexEventReportSecondTriggerLowerPrioritySomeDebugReports()
throws DatastoreException, JSONException {
// Setup
long baseTime = System.currentTimeMillis();
+ UnsignedLong triggerData1 = new UnsignedLong(1L);
+ UnsignedLong triggerData2 = new UnsignedLong(2L);
+ UnsignedLong sourceDebugKey = new UnsignedLong(777L);
+ UnsignedLong debugKey2 = new UnsignedLong(55L);
Trigger trigger =
TriggerFixture.getValidTriggerBuilder()
.setId("triggerId1")
.setStatus(Trigger.Status.PENDING)
.setEventTriggers(
- "[\n"
- + "{\n"
- + " \"trigger_data\": \"2\",\n"
- + " \"priority\": \"123\",\n"
- + " \"value\": \"105\",\n"
- + " \"deduplication_key\": \"1\"\n"
+ "["
+ + "{"
+ + " \"trigger_data\": \"" + triggerData2 + "\","
+ + " \"priority\": \"123\","
+ + " \"value\": \"105\","
+ + " \"deduplication_key\": \"1\""
+ "}"
- + "]\n")
+ + "]")
.setFilters(
- "[{\n"
- + " \"key_1\": [\"value_1\", \"value_2\"],\n"
- + " \"key_2\": [\"value_1\", \"value_2\"]\n"
- + "}]\n")
+ "[{"
+ + " \"key_1\": [\"value_1\", \"value_2\"],"
+ + " \"key_2\": [\"value_1\", \"value_2\"]"
+ + "}]")
.setTriggerTime(
baseTime
+ TimeUnit.DAYS.toMillis(1)
+ MEASUREMENT_MIN_EVENT_REPORT_DELAY_MILLIS)
.setAggregateTriggerData(buildAggregateTriggerData().toString())
.setAggregateValues("{\"campaignCounts\":32768,\"geoValue\":1644}")
+ .setAdIdPermission(true)
+ .setDebugKey(debugKey2)
.build();
Pair<Long, Long> firstBucket = Pair.create(10L, 99L);
@@ -5183,8 +5243,9 @@
.setSourceType(Source.SourceType.NAVIGATION)
.setRegistrationOrigin(WebUtil.validUri("https://adtech2.test"))
.setTriggerTime(baseTime + 3000)
- .setTriggerData(new UnsignedLong(1L))
+ .setTriggerData(triggerData1)
.setTriggerPriority(124L)
+ .setSourceDebugKey(sourceDebugKey)
.setTriggerValue(103)
.setTriggerDedupKey(new UnsignedLong(3L));
@@ -5220,6 +5281,8 @@
.setEventAttributionStatus(existingAttributes.toString())
.setPrivacyParameters(
templateTriggerSpecs.encodePrivacyParametersToJSONString())
+ .setAdIdPermission(true)
+ .setDebugKey(sourceDebugKey)
.build();
when(mFlags.getMeasurementFlexibleEventReportingApiEnabled()).thenReturn(true);
@@ -5273,9 +5336,24 @@
assertEquals(firstBucket, insertedEventReports.get(0).getTriggerSummaryBucket());
assertEquals(secondBucket, insertedEventReports.get(1).getTriggerSummaryBucket());
assertEquals(firstBucket, insertedEventReports.get(2).getTriggerSummaryBucket());
- assertEquals(new UnsignedLong(1L), insertedEventReports.get(0).getTriggerData());
- assertEquals(new UnsignedLong(1L), insertedEventReports.get(1).getTriggerData());
- assertEquals(new UnsignedLong(2L), insertedEventReports.get(2).getTriggerData());
+ assertEquals(triggerData1, insertedEventReports.get(0).getTriggerData());
+ assertEquals(triggerData1, insertedEventReports.get(1).getTriggerData());
+ assertEquals(triggerData2, insertedEventReports.get(2).getTriggerData());
+ assertEquals(Collections.emptyList(), insertedEventReports.get(0).getTriggerDebugKeys());
+ assertEquals(Collections.emptyList(), insertedEventReports.get(1).getTriggerDebugKeys());
+ assertEquals(List.of(debugKey2), insertedEventReports.get(2).getTriggerDebugKeys());
+ assertEquals(sourceDebugKey, insertedEventReports.get(0).getSourceDebugKey());
+ assertEquals(sourceDebugKey, insertedEventReports.get(1).getSourceDebugKey());
+ assertEquals(sourceDebugKey, insertedEventReports.get(2).getSourceDebugKey());
+ assertEquals(
+ EventReport.DebugReportStatus.NONE,
+ insertedEventReports.get(0).getDebugReportStatus());
+ assertEquals(
+ EventReport.DebugReportStatus.NONE,
+ insertedEventReports.get(1).getDebugReportStatus());
+ assertEquals(
+ EventReport.DebugReportStatus.PENDING,
+ insertedEventReports.get(2).getDebugReportStatus());
long reportTime = TimeUnit.DAYS.toMillis(2) + MEASUREMENT_MIN_EVENT_REPORT_DELAY_MILLIS;
assertEquals(reportTime, insertedEventReports.get(0).getReportTime() - baseTime);
assertEquals(reportTime, insertedEventReports.get(1).getReportTime() - baseTime);
@@ -6317,6 +6395,10 @@
triggerRecord.put("trigger_time", eventReport.getTriggerTime());
triggerRecord.put("trigger_data", eventReport.getTriggerData());
triggerRecord.put("dedup_key", eventReport.getTriggerDedupKey());
+ if (eventReport.getTriggerDebugKey() != null) {
+ triggerRecord.put("debug_key", eventReport.getTriggerDebugKey());
+ }
+ triggerRecord.put("has_source_debug_key", eventReport.getSourceDebugKey() != null);
return triggerRecord;
}
diff --git a/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/reporting/EventReportPayloadTest.java b/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/reporting/EventReportPayloadTest.java
index c27b955..cf97585 100644
--- a/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/reporting/EventReportPayloadTest.java
+++ b/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/reporting/EventReportPayloadTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertTrue;
import android.net.Uri;
+import android.util.Pair;
import com.android.adservices.service.measurement.util.UnsignedLong;
@@ -46,6 +47,7 @@
private static final double RANDOMIZED_TRIGGER_RATE = 0.0024;
private static final UnsignedLong SOURCE_DEBUG_KEY = new UnsignedLong(3894783L);
private static final UnsignedLong TRIGGER_DEBUG_KEY = new UnsignedLong(2387222L);
+ private static final Pair<Long, Long> TRIGGER_SUMMARY_BUCKET = Pair.create(5L, 37L);
private static final List<UnsignedLong> TRIGGER_DEBUG_KEYS = List.of(
new UnsignedLong(2387222L), new UnsignedLong("9223372036854775809"));
@@ -85,7 +87,7 @@
attributionDestinations);
}
- private static EventReportPayload createEventReportPayload(
+ private static EventReportPayload.Builder createEventReportPayloadBuilder(
UnsignedLong triggerData,
UnsignedLong sourceDebugKey,
UnsignedLong triggerDebugKey,
@@ -101,19 +103,36 @@
.setRandomizedTriggerRate(RANDOMIZED_TRIGGER_RATE)
.setSourceDebugKey(sourceDebugKey)
.setTriggerDebugKey(triggerDebugKey)
- .setTriggerDebugKeys(triggerDebugKeys)
- .build();
+ .setTriggerDebugKeys(triggerDebugKeys);
+ }
+
+ private static EventReportPayload createEventReportPayload(
+ UnsignedLong triggerData,
+ UnsignedLong sourceDebugKey,
+ UnsignedLong triggerDebugKey,
+ List<UnsignedLong> triggerDebugKeys,
+ List<Uri> destinations) {
+ return createEventReportPayloadBuilder(
+ triggerData,
+ sourceDebugKey,
+ triggerDebugKey,
+ triggerDebugKeys,
+ destinations)
+ .build();
}
@Test
public void toJson_success() throws JSONException {
EventReportPayload eventReport =
- createEventReportPayload(
+ createEventReportPayloadBuilder(
TRIGGER_DATA,
SOURCE_DEBUG_KEY,
TRIGGER_DEBUG_KEY,
TRIGGER_DEBUG_KEYS,
- ATTRIBUTION_DESTINATIONS);
+ ATTRIBUTION_DESTINATIONS)
+ .setTriggerSummaryBucket(TRIGGER_SUMMARY_BUCKET)
+ .build();
+
JSONObject eventPayloadReportJson = eventReport.toJson();
Object destinationsObj = eventPayloadReportJson.get("attribution_destination");
@@ -134,6 +153,16 @@
((JSONArray) triggerDebugKeysObj).getString(0));
assertEquals(TRIGGER_DEBUG_KEYS.get(1).toString(),
((JSONArray) triggerDebugKeysObj).getString(1));
+ // Trigger summary bucket
+ assertTrue(eventPayloadReportJson.get("trigger_summary_bucket") instanceof JSONArray);
+ JSONArray triggerSummaryBucket =
+ eventPayloadReportJson.getJSONArray("trigger_summary_bucket");
+ Object first = triggerSummaryBucket.get(0);
+ assertTrue(first instanceof Number);
+ assertEquals(TRIGGER_SUMMARY_BUCKET.first, Long.valueOf((long) first));
+ Object second = triggerSummaryBucket.get(1);
+ assertTrue(second instanceof Number);
+ assertEquals(TRIGGER_SUMMARY_BUCKET.second, Long.valueOf((long) second));
}
@Test
diff --git a/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/reporting/ReportUtilTest.java b/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/reporting/ReportUtilTest.java
index 8e3356c..9021571 100644
--- a/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/reporting/ReportUtilTest.java
+++ b/adservices/tests/unittest/service-core/src/com/android/adservices/service/measurement/reporting/ReportUtilTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
import android.net.Uri;
import android.util.Pair;
@@ -25,6 +26,7 @@
import com.android.adservices.service.measurement.util.UnsignedLong;
import org.json.JSONArray;
+import org.json.JSONException;
import org.junit.Test;
import java.util.List;
@@ -68,14 +70,26 @@
}
@Test
- public void serializeSummaryBucket_baseCase_returnsExpectedFormat() {
+ public void serializeSummaryBucket_baseCase_returnsExpectedFormat() throws JSONException {
Pair<Long, Long> summaryBucket = new Pair<>(1L, 5L);
- assertEquals("[1,5]", ReportUtil.serializeSummaryBucket(summaryBucket));
+ JSONArray result = ReportUtil.serializeSummaryBucket(summaryBucket);
+ Object first = result.get(0);
+ assertTrue(first instanceof Number);
+ assertEquals(summaryBucket.first, Long.valueOf((long) first));
+ Object second = result.get(1);
+ assertTrue(second instanceof Number);
+ assertEquals(summaryBucket.second, Long.valueOf((long) second));
}
@Test
- public void serializeSummaryBucket_largestBucket_returnsExpectedFormat() {
+ public void serializeSummaryBucket_largestBucket_returnsExpectedFormat() throws JSONException {
Pair<Long, Long> summaryBucket = new Pair<>(100L, Long.MAX_VALUE);
- assertEquals("[100,9223372036854775807]", ReportUtil.serializeSummaryBucket(summaryBucket));
+ JSONArray result = ReportUtil.serializeSummaryBucket(summaryBucket);
+ Object first = result.get(0);
+ assertTrue(first instanceof Number);
+ assertEquals(summaryBucket.first, Long.valueOf((long) first));
+ Object second = result.get(1);
+ assertTrue(second instanceof Number);
+ assertEquals(summaryBucket.second, Long.valueOf((long) second));
}
}