1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.adservices.service.measurement; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertNotEquals; 23 import static org.junit.Assert.assertNotNull; 24 import static org.junit.Assert.assertNull; 25 import static org.junit.Assert.assertThrows; 26 import static org.junit.Assert.assertTrue; 27 import static org.mockito.Mockito.when; 28 29 import android.net.Uri; 30 31 import com.android.adservices.common.WebUtil; 32 import com.android.adservices.service.Flags; 33 import com.android.adservices.service.measurement.TriggerFixture.ValidTriggerParams; 34 import com.android.adservices.service.measurement.aggregation.AggregatableAttributionTrigger; 35 import com.android.adservices.service.measurement.aggregation.AggregatableKeyValue; 36 import com.android.adservices.service.measurement.aggregation.AggregatableValuesConfig; 37 import com.android.adservices.service.measurement.aggregation.AggregateDebugReportData; 38 import com.android.adservices.service.measurement.aggregation.AggregateDebugReporting; 39 import com.android.adservices.service.measurement.aggregation.AggregateTriggerData; 40 import com.android.adservices.service.measurement.reporting.DebugReportApi; 41 import com.android.adservices.service.measurement.util.UnsignedLong; 42 43 import org.json.JSONArray; 44 import org.json.JSONException; 45 import org.json.JSONObject; 46 import org.junit.Test; 47 import org.junit.runner.RunWith; 48 import org.mockito.Mock; 49 import org.mockito.junit.MockitoJUnitRunner; 50 51 import java.math.BigInteger; 52 import java.util.ArrayList; 53 import java.util.Arrays; 54 import java.util.Collections; 55 import java.util.HashSet; 56 import java.util.List; 57 import java.util.Map; 58 import java.util.Optional; 59 import java.util.Set; 60 61 @RunWith(MockitoJUnitRunner.class) 62 public class TriggerTest { 63 private static final String TOP_LEVEL_FILTERS_JSON_STRING = 64 "[{\n" 65 + " \"key_1\": [\"value_1\", \"value_2\"],\n" 66 + " \"key_2\": [\"value_1\", \"value_2\"]\n" 67 + "}]\n"; 68 69 private static final String TOP_LEVEL_FILTERS_JSON_STRING_X = 70 "[{\n" 71 + " \"key_1x\": [\"value_1\", \"value_2\"],\n" 72 + " \"key_2x\": [\"value_1\", \"value_2\"]\n" 73 + "}]\n"; 74 75 private static final String EVENT_TRIGGERS = 76 "[\n" 77 + "{\n" 78 + " \"trigger_data\": \"1\",\n" 79 + " \"priority\": \"345678\",\n" 80 + " \"deduplication_key\": \"2345678\",\n" 81 + " \"filters\": [{\n" 82 + " \"source_type\": [\"navigation\"],\n" 83 + " \"key_1\": [\"value_1\"] \n" 84 + " }]\n" 85 + "}" 86 + "]\n"; 87 88 private static final UnsignedLong DEBUG_KEY = new UnsignedLong(2367372L); 89 private static final Uri APP_DESTINATION = Uri.parse("android-app://com.android.app"); 90 private static final Uri APP_DESTINATION_WITH_PATH = 91 Uri.parse("android-app://com.android.app/with/path"); 92 private static final Uri WEB_DESTINATION = WebUtil.validUri("https://example.test"); 93 private static final Uri WEB_DESTINATION_WITH_PATH = 94 WebUtil.validUri("https://example.test/with/path"); 95 private static final Uri WEB_DESTINATION_WITH_SUBDOMAIN = 96 WebUtil.validUri("https://subdomain.example.test"); 97 private static final Uri WEB_DESTINATION_WITH_SUBDOMAIN_PATH_QUERY_FRAGMENT = 98 WebUtil.validUri("https://subdomain.example.test/with/path?query=0#fragment"); 99 private static final Uri WEB_DESTINATION_INVALID = Uri.parse("https://example.notatld"); 100 101 @Mock Flags mFlags; 102 103 @Test testEqualsPass()104 public void testEqualsPass() throws JSONException { 105 assertEquals(TriggerFixture.getValidTriggerBuilder().build(), 106 TriggerFixture.getValidTriggerBuilder().build()); 107 JSONArray aggregateTriggerDatas = new JSONArray(); 108 JSONObject aggregateTriggerData1 = new JSONObject(); 109 aggregateTriggerData1.put("key_piece", "0x400"); 110 aggregateTriggerData1.put("source_keys", Arrays.asList("campaignCounts")); 111 JSONObject aggregateTriggerData2 = new JSONObject(); 112 aggregateTriggerData2.put("key_piece", "0xA80"); 113 aggregateTriggerData2.put("source_keys", Arrays.asList("geoValue", "nonMatchingKey")); 114 aggregateTriggerDatas.put(aggregateTriggerData1); 115 aggregateTriggerDatas.put(aggregateTriggerData2); 116 JSONObject values = new JSONObject(); 117 values.put("campaignCounts", 32768); 118 values.put("geoValue", 1664); 119 JSONObject adtechBitMapping = new JSONObject(); 120 adtechBitMapping.put("AdTechA-enrollment_id", "0x1"); 121 String debugJoinKey = "SAMPLE_DEBUG_JOIN_KEY"; 122 String debugAppAdId = "SAMPLE_DEBUG_APP_ADID"; 123 String debugWebAdId = "SAMPLE_DEBUG_WEB_ADID"; 124 assertEquals( 125 TriggerFixture.getValidTriggerBuilder() 126 .setEnrollmentId("enrollment-id") 127 .setAttributionDestination(Uri.parse("https://example.test/aD")) 128 .setDestinationType(EventSurfaceType.WEB) 129 .setId("1") 130 .setEventTriggers(EVENT_TRIGGERS) 131 .setTriggerTime(5L) 132 .setIsDebugReporting(true) 133 .setAdIdPermission(true) 134 .setArDebugPermission(true) 135 .setStatus(Trigger.Status.PENDING) 136 .setRegistrant(Uri.parse("android-app://com.example.abc")) 137 .setAggregateTriggerData(aggregateTriggerDatas.toString()) 138 .setAggregateValuesString(values.toString()) 139 .setFilters(TOP_LEVEL_FILTERS_JSON_STRING) 140 .setNotFilters(TOP_LEVEL_FILTERS_JSON_STRING) 141 .setDebugKey(DEBUG_KEY) 142 .setAggregatableAttributionTrigger( 143 TriggerFixture.getValidTrigger() 144 .getAggregatableAttributionTrigger(mFlags) 145 .orElse(null)) 146 .setAttributionConfig(createAttributionConfigJSONArray().toString()) 147 .setAdtechBitMapping(adtechBitMapping.toString()) 148 .setDebugJoinKey(debugJoinKey) 149 .setPlatformAdId(debugAppAdId) 150 .setDebugAdId(debugWebAdId) 151 .setRegistrationOrigin( 152 TriggerFixture.ValidTriggerParams.REGISTRATION_ORIGIN) 153 .setAttributionScopesString( 154 TriggerFixture.ValidTriggerParams.ATTRIBUTION_SCOPES) 155 .setAggregatableFilteringIdMaxBytes( 156 TriggerFixture.ValidTriggerParams 157 .AGGREGATABLE_FILTERING_ID_MAX_BYTES) 158 .setAggregateDebugReportingString( 159 TriggerFixture.ValidTriggerParams.AGGREGATE_DEBUG_REPORT) 160 .build(), 161 TriggerFixture.getValidTriggerBuilder() 162 .setEnrollmentId("enrollment-id") 163 .setAttributionDestination(Uri.parse("https://example.test/aD")) 164 .setDestinationType(EventSurfaceType.WEB) 165 .setId("1") 166 .setEventTriggers(EVENT_TRIGGERS) 167 .setTriggerTime(5L) 168 .setIsDebugReporting(true) 169 .setAdIdPermission(true) 170 .setArDebugPermission(true) 171 .setStatus(Trigger.Status.PENDING) 172 .setRegistrant(Uri.parse("android-app://com.example.abc")) 173 .setAggregateTriggerData(aggregateTriggerDatas.toString()) 174 .setAggregateValuesString(values.toString()) 175 .setFilters(TOP_LEVEL_FILTERS_JSON_STRING) 176 .setNotFilters(TOP_LEVEL_FILTERS_JSON_STRING) 177 .setDebugKey(DEBUG_KEY) 178 .setAggregatableAttributionTrigger( 179 TriggerFixture.getValidTrigger() 180 .getAggregatableAttributionTrigger(mFlags) 181 .orElse(null)) 182 .setAttributionConfig(createAttributionConfigJSONArray().toString()) 183 .setAdtechBitMapping(adtechBitMapping.toString()) 184 .setDebugJoinKey(debugJoinKey) 185 .setPlatformAdId(debugAppAdId) 186 .setDebugAdId(debugWebAdId) 187 .setRegistrationOrigin( 188 TriggerFixture.ValidTriggerParams.REGISTRATION_ORIGIN) 189 .setAttributionScopesString( 190 TriggerFixture.ValidTriggerParams.ATTRIBUTION_SCOPES) 191 .setAggregatableFilteringIdMaxBytes( 192 TriggerFixture.ValidTriggerParams 193 .AGGREGATABLE_FILTERING_ID_MAX_BYTES) 194 .setAggregateDebugReportingString( 195 TriggerFixture.ValidTriggerParams.AGGREGATE_DEBUG_REPORT) 196 .build()); 197 } 198 199 @Test testEqualsFail()200 public void testEqualsFail() throws JSONException { 201 assertNotEquals( 202 TriggerFixture.getValidTriggerBuilder().setId("1").build(), 203 TriggerFixture.getValidTriggerBuilder().setId("2").build()); 204 assertNotEquals( 205 TriggerFixture.getValidTriggerBuilder() 206 .setAttributionDestination(Uri.parse("https://1.test")).build(), 207 TriggerFixture.getValidTriggerBuilder() 208 .setAttributionDestination(Uri.parse("https://2.test")).build()); 209 assertNotEquals( 210 TriggerFixture.getValidTriggerBuilder() 211 .setDestinationType(EventSurfaceType.APP).build(), 212 TriggerFixture.getValidTriggerBuilder() 213 .setDestinationType(EventSurfaceType.WEB).build()); 214 assertNotEquals( 215 TriggerFixture.getValidTriggerBuilder() 216 .setEnrollmentId("enrollment-id-1").build(), 217 TriggerFixture.getValidTriggerBuilder() 218 .setEnrollmentId("enrollment-id-2").build()); 219 assertNotEquals( 220 TriggerFixture.getValidTriggerBuilder().setEventTriggers("a").build(), 221 TriggerFixture.getValidTriggerBuilder().setEventTriggers("b").build()); 222 assertNotEquals( 223 TriggerFixture.getValidTriggerBuilder().setTriggerTime(1L).build(), 224 TriggerFixture.getValidTriggerBuilder().setTriggerTime(2L).build()); 225 assertNotEquals( 226 TriggerFixture.getValidTriggerBuilder() 227 .setStatus(Trigger.Status.PENDING).build(), 228 TriggerFixture.getValidTriggerBuilder() 229 .setStatus(Trigger.Status.IGNORED).build()); 230 assertNotEquals( 231 TriggerFixture.getValidTriggerBuilder() 232 .setRegistrant(Uri.parse("android-app://com.example.abc")) 233 .build(), 234 TriggerFixture.getValidTriggerBuilder() 235 .setRegistrant(Uri.parse("android-app://com.example.xyz")) 236 .build()); 237 JSONArray aggregateTriggerDataList1 = new JSONArray(); 238 JSONObject aggregateTriggerData1 = new JSONObject(); 239 aggregateTriggerData1.put("key_piece", "0x400"); 240 aggregateTriggerData1.put("source_keys", Arrays.asList("campaignCounts")); 241 aggregateTriggerDataList1.put(aggregateTriggerData1); 242 JSONArray aggregateTriggerDataList2 = new JSONArray(); 243 JSONObject aggregateTriggerData2 = new JSONObject(); 244 aggregateTriggerData2.put("key_piece", "0xA80"); 245 aggregateTriggerData2.put("source_keys", Arrays.asList("geoValue", "nonMatchingKey")); 246 aggregateTriggerDataList2.put(aggregateTriggerData2); 247 assertNotEquals( 248 TriggerFixture.getValidTriggerBuilder() 249 .setAggregateTriggerData(aggregateTriggerDataList1.toString()).build(), 250 TriggerFixture.getValidTriggerBuilder() 251 .setAggregateTriggerData(aggregateTriggerDataList2.toString()).build()); 252 JSONObject values1 = new JSONObject(); 253 values1.put("campaignCounts", 32768); 254 JSONObject values2 = new JSONObject(); 255 values2.put("geoValue", 1664); 256 assertThat( 257 TriggerFixture.getValidTriggerBuilder() 258 .setAggregateValuesString(values1.toString()) 259 .build()) 260 .isNotEqualTo( 261 TriggerFixture.getValidTriggerBuilder() 262 .setAggregateValuesString(values2.toString()) 263 .build()); 264 assertNotEquals( 265 TriggerFixture.getValidTriggerBuilder() 266 .setFilters(TOP_LEVEL_FILTERS_JSON_STRING).build(), 267 TriggerFixture.getValidTriggerBuilder() 268 .setFilters(TOP_LEVEL_FILTERS_JSON_STRING_X).build()); 269 assertNotEquals( 270 TriggerFixture.getValidTriggerBuilder() 271 .setNotFilters(TOP_LEVEL_FILTERS_JSON_STRING).build(), 272 TriggerFixture.getValidTriggerBuilder() 273 .setNotFilters(TOP_LEVEL_FILTERS_JSON_STRING_X).build()); 274 JSONArray attributionConfigList1 = new JSONArray(); 275 JSONObject attributionConfig1 = new JSONObject(); 276 attributionConfig1.put("source_network", "AdTech1-Ads"); 277 JSONObject sourcePriorityRange1 = new JSONObject(); 278 sourcePriorityRange1.put("start", 100); 279 sourcePriorityRange1.put("end", 1000); 280 attributionConfig1.put("source_priority_range", sourcePriorityRange1); 281 JSONObject sourceFilters1 = new JSONObject(); 282 sourceFilters1.put("campaign_type", Arrays.asList("install")); 283 sourceFilters1.put("source_type", Arrays.asList("navigation")); 284 attributionConfig1.put("source_filters", sourceFilters1); 285 attributionConfig1.put("priority", "99"); 286 attributionConfig1.put("expiry", "604800"); 287 JSONObject filterData1 = new JSONObject(); 288 filterData1.put("campaign_type", Arrays.asList("install")); 289 attributionConfig1.put("filter_data", filterData1); 290 attributionConfigList1.put(attributionConfig1); 291 292 JSONArray attributionConfigList2 = new JSONArray(); 293 JSONObject attributionConfig2 = new JSONObject(); 294 attributionConfig2.put("source_network", "AdTech2-Ads"); 295 JSONObject sourcePriorityRange2 = new JSONObject(); 296 sourcePriorityRange2.put("start", 100); 297 sourcePriorityRange2.put("end", 1000); 298 attributionConfig1.put("source_priority_range", sourcePriorityRange2); 299 JSONObject sourceFilters2 = new JSONObject(); 300 sourceFilters2.put("campaign_type", Arrays.asList("install")); 301 sourceFilters2.put("source_type", Arrays.asList("navigation")); 302 attributionConfig2.put("source_filters", sourceFilters2); 303 attributionConfig2.put("priority", "99"); 304 attributionConfig2.put("expiry", "604800"); 305 JSONObject filterData2 = new JSONObject(); 306 filterData1.put("campaign_type", Arrays.asList("install")); 307 attributionConfig2.put("filter_data", filterData2); 308 attributionConfigList2.put(attributionConfig2); 309 assertNotEquals( 310 TriggerFixture.getValidTriggerBuilder() 311 .setAttributionConfig(attributionConfigList1.toString()) 312 .build(), 313 TriggerFixture.getValidTriggerBuilder() 314 .setAttributionConfig(attributionConfigList2.toString()) 315 .build()); 316 JSONObject adtechBitMapping1 = new JSONObject(); 317 adtechBitMapping1.put("AdTechA-enrollment_id", "0x1"); 318 JSONObject adtechBitMapping2 = new JSONObject(); 319 adtechBitMapping2.put("AdTechA-enrollment_id", "0x2"); 320 assertNotEquals( 321 TriggerFixture.getValidTriggerBuilder() 322 .setAdtechBitMapping(adtechBitMapping1.toString()) 323 .build(), 324 TriggerFixture.getValidTriggerBuilder() 325 .setAdtechBitMapping(adtechBitMapping2.toString()) 326 .build()); 327 assertNotEquals( 328 TriggerFixture.getValidTriggerBuilder().setDebugJoinKey("debug_key-1").build(), 329 TriggerFixture.getValidTriggerBuilder().setDebugJoinKey("debug_key-2").build()); 330 assertNotEquals( 331 TriggerFixture.getValidTriggerBuilder().setPlatformAdId("debugAppAdId1").build(), 332 TriggerFixture.getValidTriggerBuilder().setPlatformAdId("debugAppAdId2").build()); 333 assertNotEquals( 334 TriggerFixture.getValidTriggerBuilder().setDebugAdId("debugWebAdId1").build(), 335 TriggerFixture.getValidTriggerBuilder().setDebugAdId("debugWebAdId2").build()); 336 assertNotEquals( 337 TriggerFixture.getValidTriggerBuilder() 338 .setRegistrationOrigin(WebUtil.validUri("https://subdomain1.example.test")) 339 .build(), 340 TriggerFixture.getValidTriggerBuilder() 341 .setRegistrationOrigin(WebUtil.validUri("https://subdomain2.example.test")) 342 .build()); 343 assertNotEquals( 344 TriggerFixture.getValidTriggerBuilder().setAttributionScopesString("1").build(), 345 TriggerFixture.getValidTriggerBuilder().setAttributionScopesString("2").build()); 346 assertNotEquals( 347 TriggerFixture.getValidTriggerBuilder() 348 .setAggregatableFilteringIdMaxBytes(1) 349 .build(), 350 TriggerFixture.getValidTriggerBuilder() 351 .setAggregatableFilteringIdMaxBytes(2) 352 .build()); 353 assertThat( 354 TriggerFixture.getValidTriggerBuilder() 355 .setAggregateDebugReportingString( 356 "{\"budget\":1024,\"key_piece\":\"0x1\"}") 357 .build()) 358 .isNotEqualTo( 359 TriggerFixture.getValidTriggerBuilder() 360 .setAggregateDebugReportingString( 361 "{\"budget\":1024,\"key_piece\":\"0x2\"}") 362 .build()); 363 } 364 365 @Test testHashCode_equals()366 public void testHashCode_equals() { 367 final Trigger trigger1 = TriggerFixture.getValidTriggerBuilder().build(); 368 final Trigger trigger2 = TriggerFixture.getValidTriggerBuilder().build(); 369 final Set<Trigger> triggerSet1 = Set.of(trigger1); 370 final Set<Trigger> triggerSet2 = Set.of(trigger2); 371 assertEquals(trigger1.hashCode(), trigger2.hashCode()); 372 assertEquals(trigger1, trigger2); 373 assertEquals(triggerSet1, triggerSet2); 374 } 375 376 @Test testHashCode_notEquals()377 public void testHashCode_notEquals() { 378 final Trigger trigger1 = TriggerFixture.getValidTriggerBuilder().build(); 379 final Trigger trigger2 = TriggerFixture.getValidTriggerBuilder().setId("100").build(); 380 final Set<Trigger> triggerSet1 = Set.of(trigger1); 381 final Set<Trigger> triggerSet2 = Set.of(trigger2); 382 assertNotEquals(trigger1.hashCode(), trigger2.hashCode()); 383 assertNotEquals(trigger1, trigger2); 384 assertNotEquals(triggerSet1, triggerSet2); 385 assertNotEquals( 386 trigger1, 387 TriggerFixture.getValidTriggerBuilder().setAttributionScopesString("5").build()); 388 } 389 390 @Test testTriggerBuilder_validateArgumentAttributionDestination()391 public void testTriggerBuilder_validateArgumentAttributionDestination() { 392 assertInvalidTriggerArguments( 393 null, 394 TriggerFixture.ValidTriggerParams.ENROLLMENT_ID, 395 TriggerFixture.ValidTriggerParams.REGISTRANT, 396 TriggerFixture.ValidTriggerParams.TRIGGER_TIME, 397 TriggerFixture.ValidTriggerParams.EVENT_TRIGGERS, 398 TriggerFixture.ValidTriggerParams.AGGREGATE_TRIGGER_DATA, 399 TriggerFixture.ValidTriggerParams.AGGREGATE_VALUES_STRING, 400 TriggerFixture.ValidTriggerParams.TOP_LEVEL_FILTERS_JSON_STRING, 401 TriggerFixture.ValidTriggerParams.TOP_LEVEL_NOT_FILTERS_JSON_STRING, 402 TriggerFixture.ValidTriggerParams.DEBUG_KEY, 403 TriggerFixture.ValidTriggerParams.ATTRIBUTION_CONFIGS_STRING, 404 TriggerFixture.ValidTriggerParams.X_NETWORK_KEY_MAPPING, 405 TriggerFixture.ValidTriggerParams.REGISTRATION_ORIGIN, 406 TriggerFixture.ValidTriggerParams.AGGREGATABLE_SOURCE_REGISTRATION_TIME_CONFIG); 407 assertInvalidTriggerArguments( 408 Uri.parse("com.destination"), 409 TriggerFixture.ValidTriggerParams.ENROLLMENT_ID, 410 TriggerFixture.ValidTriggerParams.REGISTRANT, 411 TriggerFixture.ValidTriggerParams.TRIGGER_TIME, 412 TriggerFixture.ValidTriggerParams.EVENT_TRIGGERS, 413 TriggerFixture.ValidTriggerParams.AGGREGATE_TRIGGER_DATA, 414 TriggerFixture.ValidTriggerParams.AGGREGATE_VALUES_STRING, 415 TriggerFixture.ValidTriggerParams.TOP_LEVEL_FILTERS_JSON_STRING, 416 TriggerFixture.ValidTriggerParams.TOP_LEVEL_NOT_FILTERS_JSON_STRING, 417 TriggerFixture.ValidTriggerParams.DEBUG_KEY, 418 TriggerFixture.ValidTriggerParams.ATTRIBUTION_CONFIGS_STRING, 419 TriggerFixture.ValidTriggerParams.X_NETWORK_KEY_MAPPING, 420 TriggerFixture.ValidTriggerParams.REGISTRATION_ORIGIN, 421 TriggerFixture.ValidTriggerParams.AGGREGATABLE_SOURCE_REGISTRATION_TIME_CONFIG); 422 } 423 424 @Test testTriggerBuilder_validateArgumentEnrollmentId()425 public void testTriggerBuilder_validateArgumentEnrollmentId() { 426 assertInvalidTriggerArguments( 427 TriggerFixture.ValidTriggerParams.ATTRIBUTION_DESTINATION, 428 null, 429 TriggerFixture.ValidTriggerParams.REGISTRANT, 430 TriggerFixture.ValidTriggerParams.TRIGGER_TIME, 431 TriggerFixture.ValidTriggerParams.EVENT_TRIGGERS, 432 TriggerFixture.ValidTriggerParams.AGGREGATE_TRIGGER_DATA, 433 TriggerFixture.ValidTriggerParams.AGGREGATE_VALUES_STRING, 434 TriggerFixture.ValidTriggerParams.TOP_LEVEL_FILTERS_JSON_STRING, 435 TriggerFixture.ValidTriggerParams.TOP_LEVEL_NOT_FILTERS_JSON_STRING, 436 TriggerFixture.ValidTriggerParams.DEBUG_KEY, 437 TriggerFixture.ValidTriggerParams.ATTRIBUTION_CONFIGS_STRING, 438 TriggerFixture.ValidTriggerParams.X_NETWORK_KEY_MAPPING, 439 TriggerFixture.ValidTriggerParams.REGISTRATION_ORIGIN, 440 TriggerFixture.ValidTriggerParams.AGGREGATABLE_SOURCE_REGISTRATION_TIME_CONFIG); 441 } 442 443 @Test testTriggerBuilder_validateArgumentRegistrant()444 public void testTriggerBuilder_validateArgumentRegistrant() { 445 assertInvalidTriggerArguments( 446 TriggerFixture.ValidTriggerParams.ATTRIBUTION_DESTINATION, 447 TriggerFixture.ValidTriggerParams.ENROLLMENT_ID, 448 null, 449 TriggerFixture.ValidTriggerParams.TRIGGER_TIME, 450 TriggerFixture.ValidTriggerParams.EVENT_TRIGGERS, 451 TriggerFixture.ValidTriggerParams.AGGREGATE_TRIGGER_DATA, 452 TriggerFixture.ValidTriggerParams.AGGREGATE_VALUES_STRING, 453 TriggerFixture.ValidTriggerParams.TOP_LEVEL_FILTERS_JSON_STRING, 454 TriggerFixture.ValidTriggerParams.TOP_LEVEL_NOT_FILTERS_JSON_STRING, 455 TriggerFixture.ValidTriggerParams.DEBUG_KEY, 456 TriggerFixture.ValidTriggerParams.ATTRIBUTION_CONFIGS_STRING, 457 TriggerFixture.ValidTriggerParams.X_NETWORK_KEY_MAPPING, 458 TriggerFixture.ValidTriggerParams.REGISTRATION_ORIGIN, 459 TriggerFixture.ValidTriggerParams.AGGREGATABLE_SOURCE_REGISTRATION_TIME_CONFIG); 460 assertInvalidTriggerArguments( 461 TriggerFixture.ValidTriggerParams.ATTRIBUTION_DESTINATION, 462 TriggerFixture.ValidTriggerParams.ENROLLMENT_ID, 463 Uri.parse("com.registrant"), 464 TriggerFixture.ValidTriggerParams.TRIGGER_TIME, 465 TriggerFixture.ValidTriggerParams.EVENT_TRIGGERS, 466 TriggerFixture.ValidTriggerParams.AGGREGATE_TRIGGER_DATA, 467 TriggerFixture.ValidTriggerParams.AGGREGATE_VALUES_STRING, 468 TriggerFixture.ValidTriggerParams.TOP_LEVEL_FILTERS_JSON_STRING, 469 TriggerFixture.ValidTriggerParams.TOP_LEVEL_NOT_FILTERS_JSON_STRING, 470 TriggerFixture.ValidTriggerParams.DEBUG_KEY, 471 TriggerFixture.ValidTriggerParams.ATTRIBUTION_CONFIGS_STRING, 472 TriggerFixture.ValidTriggerParams.X_NETWORK_KEY_MAPPING, 473 TriggerFixture.ValidTriggerParams.REGISTRATION_ORIGIN, 474 TriggerFixture.ValidTriggerParams.AGGREGATABLE_SOURCE_REGISTRATION_TIME_CONFIG); 475 } 476 477 @Test testTriggerBuilder_validateArgumentRegistrationOrigin()478 public void testTriggerBuilder_validateArgumentRegistrationOrigin() { 479 assertInvalidTriggerArguments( 480 TriggerFixture.ValidTriggerParams.ATTRIBUTION_DESTINATION, 481 TriggerFixture.ValidTriggerParams.ENROLLMENT_ID, 482 TriggerFixture.ValidTriggerParams.REGISTRANT, 483 TriggerFixture.ValidTriggerParams.TRIGGER_TIME, 484 TriggerFixture.ValidTriggerParams.EVENT_TRIGGERS, 485 TriggerFixture.ValidTriggerParams.AGGREGATE_TRIGGER_DATA, 486 TriggerFixture.ValidTriggerParams.AGGREGATE_VALUES_STRING, 487 TriggerFixture.ValidTriggerParams.TOP_LEVEL_FILTERS_JSON_STRING, 488 TriggerFixture.ValidTriggerParams.TOP_LEVEL_NOT_FILTERS_JSON_STRING, 489 TriggerFixture.ValidTriggerParams.DEBUG_KEY, 490 TriggerFixture.ValidTriggerParams.ATTRIBUTION_CONFIGS_STRING, 491 TriggerFixture.ValidTriggerParams.X_NETWORK_KEY_MAPPING, 492 null, 493 TriggerFixture.ValidTriggerParams.AGGREGATABLE_SOURCE_REGISTRATION_TIME_CONFIG); 494 } 495 496 @Test testTriggerBuilder_validateArgumentSourceRegistrationTimeConfig()497 public void testTriggerBuilder_validateArgumentSourceRegistrationTimeConfig() { 498 assertInvalidTriggerArguments( 499 TriggerFixture.ValidTriggerParams.ATTRIBUTION_DESTINATION, 500 TriggerFixture.ValidTriggerParams.ENROLLMENT_ID, 501 TriggerFixture.ValidTriggerParams.REGISTRANT, 502 TriggerFixture.ValidTriggerParams.TRIGGER_TIME, 503 TriggerFixture.ValidTriggerParams.EVENT_TRIGGERS, 504 TriggerFixture.ValidTriggerParams.AGGREGATE_TRIGGER_DATA, 505 TriggerFixture.ValidTriggerParams.AGGREGATE_VALUES_STRING, 506 TriggerFixture.ValidTriggerParams.TOP_LEVEL_FILTERS_JSON_STRING, 507 TriggerFixture.ValidTriggerParams.TOP_LEVEL_NOT_FILTERS_JSON_STRING, 508 TriggerFixture.ValidTriggerParams.DEBUG_KEY, 509 TriggerFixture.ValidTriggerParams.ATTRIBUTION_CONFIGS_STRING, 510 TriggerFixture.ValidTriggerParams.X_NETWORK_KEY_MAPPING, 511 TriggerFixture.ValidTriggerParams.REGISTRATION_ORIGIN, 512 null); 513 } 514 515 @Test testAggregatableAttributionTrigger()516 public void testAggregatableAttributionTrigger() throws Exception { 517 when(mFlags.getMeasurementEnableAggregateValueFilters()).thenReturn(true, false); 518 AggregatableKeyValue value = new AggregatableKeyValue.Builder(93).build(); 519 final Map<String, AggregatableKeyValue> values = Map.of("foo", value); 520 final AggregatableValuesConfig aggregatableValuesConfig = 521 new AggregatableValuesConfig.Builder(values).build(); 522 final List<AggregateTriggerData> triggerData = 523 List.of(new AggregateTriggerData.Builder().build()); 524 final AggregatableAttributionTrigger attributionTrigger = 525 new AggregatableAttributionTrigger.Builder() 526 .setValueConfigs(List.of(aggregatableValuesConfig)) 527 .setTriggerData(triggerData) 528 .build(); 529 530 final Trigger trigger = 531 TriggerFixture.getValidTriggerBuilder() 532 .setAggregatableAttributionTrigger(attributionTrigger) 533 .build(); 534 535 Optional<AggregatableAttributionTrigger> aggregatableAttributionTrigger = 536 trigger.getAggregatableAttributionTrigger(mFlags); 537 assertTrue(aggregatableAttributionTrigger.isPresent()); 538 assertNotNull(aggregatableAttributionTrigger.get().getTriggerData()); 539 assertEquals( 540 values.get("foo").getValue(), 541 aggregatableAttributionTrigger 542 .get() 543 .getValueConfigs() 544 .get(0) 545 .getValues() 546 .get("foo") 547 .getValue()); 548 assertEquals(triggerData, aggregatableAttributionTrigger.get().getTriggerData()); 549 } 550 551 @Test testParseAggregateTrigger()552 public void testParseAggregateTrigger() throws JSONException { 553 when(mFlags.getMeasurementEnableAggregateValueFilters()).thenReturn(true, false); 554 when(mFlags.getMeasurementEnableAggregatableNamedBudgets()).thenReturn(true); 555 JSONArray triggerDatas = new JSONArray(); 556 JSONObject jsonObject1 = new JSONObject(); 557 jsonObject1.put("key_piece", "0x400"); 558 jsonObject1.put("source_keys", new JSONArray(Arrays.asList("campaignCounts"))); 559 jsonObject1.put("filters", createFilterJSONArray()); 560 jsonObject1.put("not_filters", createFilterJSONArray()); 561 jsonObject1.put("x_network_data", createXNetworkDataJSONObject()); 562 JSONObject jsonObject2 = new JSONObject(); 563 jsonObject2.put("key_piece", "0xA80"); 564 jsonObject2.put("source_keys", new JSONArray(Arrays.asList("geoValue", "noMatch"))); 565 jsonObject1.put("x_network_data", createXNetworkDataJSONObject()); 566 triggerDatas.put(jsonObject1); 567 triggerDatas.put(jsonObject2); 568 569 JSONObject values = new JSONObject(); 570 values.put("campaignCounts", 32768); 571 values.put("geoValue", 1664); 572 573 JSONArray aggregateDedupKeys = new JSONArray(); 574 JSONObject dedupKeyJsonObject1 = new JSONObject(); 575 dedupKeyJsonObject1.put("deduplication_key", "10"); 576 dedupKeyJsonObject1.put("filters", createFilterJSONArray()); 577 dedupKeyJsonObject1.put("not_filters", createFilterJSONArray()); 578 JSONObject dedupKeyJsonObject2 = new JSONObject(); 579 dedupKeyJsonObject2.put("deduplication_key", "11"); 580 dedupKeyJsonObject2.put("filters", createFilterJSONArray()); 581 dedupKeyJsonObject2.put("not_filters", createFilterJSONArray()); 582 JSONObject dedupKeyJsonObject3 = new JSONObject(); 583 dedupKeyJsonObject3.put("filters", createFilterJSONArray()); 584 dedupKeyJsonObject3.put("not_filters", createFilterJSONArray()); 585 aggregateDedupKeys.put(dedupKeyJsonObject1); 586 aggregateDedupKeys.put(dedupKeyJsonObject2); 587 aggregateDedupKeys.put(dedupKeyJsonObject3); 588 589 JSONArray namedBudgets = new JSONArray(); 590 JSONObject budgetJsonObject1 = new JSONObject(); 591 budgetJsonObject1.put("name", "biddable"); 592 budgetJsonObject1.put("filters", createFilterJSONArray()); 593 budgetJsonObject1.put("not_filters", createFilterJSONArray()); 594 JSONObject budgetJsonObject2 = new JSONObject(); 595 budgetJsonObject2.put("name", "nonbiddable"); 596 budgetJsonObject2.put("filters", createFilterJSONArray()); 597 budgetJsonObject2.put("not_filters", createFilterJSONArray()); 598 namedBudgets.put(budgetJsonObject1); 599 namedBudgets.put(budgetJsonObject2); 600 601 Trigger trigger = 602 TriggerFixture.getValidTriggerBuilder() 603 .setAggregateTriggerData(triggerDatas.toString()) 604 .setAggregateValuesString(values.toString()) 605 .setAggregateDeduplicationKeys(aggregateDedupKeys.toString()) 606 .setNamedBudgetsString(namedBudgets.toString()) 607 .build(); 608 Optional<AggregatableAttributionTrigger> aggregatableAttributionTrigger = 609 trigger.getAggregatableAttributionTrigger(mFlags); 610 611 assertTrue(aggregatableAttributionTrigger.isPresent()); 612 AggregatableAttributionTrigger aggregateTrigger = aggregatableAttributionTrigger.get(); 613 assertEquals(aggregateTrigger.getTriggerData().size(), 2); 614 assertEquals(aggregateTrigger.getTriggerData().get(0).getSourceKeys().size(), 1); 615 assertEquals(aggregateTrigger.getTriggerData().get(0).getKey().intValue(), 1024); 616 assertTrue(aggregateTrigger.getTriggerData().get(0) 617 .getSourceKeys().contains("campaignCounts")); 618 assertTrue(aggregateTrigger.getTriggerData().get(0).getFilterSet().isPresent()); 619 assertEquals(aggregateTrigger.getTriggerData().get(0).getFilterSet().get() 620 .get(0).getAttributionFilterMap().size(), 2); 621 assertTrue(aggregateTrigger.getTriggerData().get(0).getNotFilterSet().isPresent()); 622 assertEquals(aggregateTrigger.getTriggerData().get(0).getNotFilterSet().get() 623 .get(0).getAttributionFilterMap().size(), 2); 624 assertEquals( 625 aggregateTrigger 626 .getTriggerData() 627 .get(0) 628 .getXNetworkData() 629 .get() 630 .getKeyOffset() 631 .get() 632 .getValue() 633 .longValue(), 634 10L); 635 assertEquals(aggregateTrigger.getTriggerData().get(1).getKey().intValue(), 2688); 636 assertEquals(aggregateTrigger.getTriggerData().get(1).getSourceKeys().size(), 2); 637 assertTrue(aggregateTrigger.getTriggerData().get(1).getSourceKeys().contains("geoValue")); 638 assertTrue(aggregateTrigger.getTriggerData().get(1).getSourceKeys().contains("noMatch")); 639 assertThat(aggregateTrigger.getValueConfigs().size()).isEqualTo(1); 640 assertThat( 641 aggregateTrigger 642 .getValueConfigs() 643 .get(0) 644 .getValues() 645 .get("campaignCounts") 646 .getValue()) 647 .isEqualTo(32768); 648 assertThat(aggregateTrigger.getValueConfigs().get(0).getValues().get("geoValue").getValue()) 649 .isEqualTo(1664); 650 assertEquals( 651 aggregateTrigger 652 .getTriggerData() 653 .get(0) 654 .getXNetworkData() 655 .get() 656 .getKeyOffset() 657 .get() 658 .getValue() 659 .longValue(), 660 10L); 661 assertTrue(aggregateTrigger.getAggregateDeduplicationKeys().isPresent()); 662 assertEquals(aggregateTrigger.getAggregateDeduplicationKeys().get().size(), 3); 663 assertTrue( 664 aggregateTrigger 665 .getAggregateDeduplicationKeys() 666 .get() 667 .get(0) 668 .getDeduplicationKey() 669 .isPresent()); 670 assertEquals( 671 aggregateTrigger 672 .getAggregateDeduplicationKeys() 673 .get() 674 .get(0) 675 .getDeduplicationKey() 676 .get(), 677 new UnsignedLong(10L)); 678 assertTrue( 679 aggregateTrigger 680 .getAggregateDeduplicationKeys() 681 .get() 682 .get(0) 683 .getFilterSet() 684 .isPresent()); 685 assertEquals( 686 aggregateTrigger 687 .getAggregateDeduplicationKeys() 688 .get() 689 .get(0) 690 .getFilterSet() 691 .get() 692 .get(0) 693 .getAttributionFilterMap() 694 .size(), 695 2); 696 assertTrue( 697 aggregateTrigger 698 .getAggregateDeduplicationKeys() 699 .get() 700 .get(0) 701 .getNotFilterSet() 702 .isPresent()); 703 assertEquals( 704 aggregateTrigger 705 .getAggregateDeduplicationKeys() 706 .get() 707 .get(0) 708 .getNotFilterSet() 709 .get() 710 .get(0) 711 .getAttributionFilterMap() 712 .size(), 713 2); 714 715 assertTrue( 716 aggregateTrigger 717 .getAggregateDeduplicationKeys() 718 .get() 719 .get(1) 720 .getFilterSet() 721 .isPresent()); 722 assertEquals( 723 aggregateTrigger 724 .getAggregateDeduplicationKeys() 725 .get() 726 .get(1) 727 .getFilterSet() 728 .get() 729 .get(0) 730 .getAttributionFilterMap() 731 .size(), 732 2); 733 assertTrue( 734 aggregateTrigger 735 .getAggregateDeduplicationKeys() 736 .get() 737 .get(1) 738 .getNotFilterSet() 739 .isPresent()); 740 assertEquals( 741 aggregateTrigger 742 .getAggregateDeduplicationKeys() 743 .get() 744 .get(1) 745 .getNotFilterSet() 746 .get() 747 .get(0) 748 .getAttributionFilterMap() 749 .size(), 750 2); 751 assertEquals( 752 aggregateTrigger 753 .getAggregateDeduplicationKeys() 754 .get() 755 .get(1) 756 .getDeduplicationKey() 757 .get(), 758 new UnsignedLong(11L)); 759 760 assertTrue( 761 aggregateTrigger 762 .getAggregateDeduplicationKeys() 763 .get() 764 .get(2) 765 .getFilterSet() 766 .isPresent()); 767 assertEquals( 768 aggregateTrigger 769 .getAggregateDeduplicationKeys() 770 .get() 771 .get(2) 772 .getFilterSet() 773 .get() 774 .get(0) 775 .getAttributionFilterMap() 776 .size(), 777 2); 778 assertTrue( 779 aggregateTrigger 780 .getAggregateDeduplicationKeys() 781 .get() 782 .get(2) 783 .getNotFilterSet() 784 .isPresent()); 785 assertEquals( 786 aggregateTrigger 787 .getAggregateDeduplicationKeys() 788 .get() 789 .get(2) 790 .getNotFilterSet() 791 .get() 792 .get(0) 793 .getAttributionFilterMap() 794 .size(), 795 2); 796 assertTrue( 797 aggregateTrigger 798 .getAggregateDeduplicationKeys() 799 .get() 800 .get(2) 801 .getDeduplicationKey() 802 .isEmpty()); 803 804 assertThat(aggregateTrigger.getNamedBudgets()).isNotNull(); 805 assertThat(aggregateTrigger.getNamedBudgets().size()).isEqualTo(2); 806 assertThat(aggregateTrigger.getNamedBudgets().get(0).getName()).isEqualTo("biddable"); 807 assertThat(aggregateTrigger.getNamedBudgets().get(0).getFilterSet()).isNotNull(); 808 assertThat( 809 aggregateTrigger 810 .getNamedBudgets() 811 .get(0) 812 .getFilterSet() 813 .get(0) 814 .getAttributionFilterMap() 815 .size()) 816 .isEqualTo(2); 817 assertThat(aggregateTrigger.getNamedBudgets().get(0).getNotFilterSet()).isNotNull(); 818 assertThat( 819 aggregateTrigger 820 .getNamedBudgets() 821 .get(0) 822 .getNotFilterSet() 823 .get(0) 824 .getAttributionFilterMap() 825 .size()) 826 .isEqualTo(2); 827 assertThat(aggregateTrigger.getNamedBudgets().get(1).getFilterSet()).isNotNull(); 828 assertThat( 829 aggregateTrigger 830 .getNamedBudgets() 831 .get(1) 832 .getFilterSet() 833 .get(0) 834 .getAttributionFilterMap() 835 .size()) 836 .isEqualTo(2); 837 assertThat(aggregateTrigger.getNamedBudgets().get(1).getNotFilterSet()).isNotNull(); 838 assertThat( 839 aggregateTrigger 840 .getNamedBudgets() 841 .get(1) 842 .getNotFilterSet() 843 .get(0) 844 .getAttributionFilterMap() 845 .size()) 846 .isEqualTo(2); 847 assertThat(aggregateTrigger.getNamedBudgets().get(1).getName()).isEqualTo("nonbiddable"); 848 } 849 850 @Test testParseAggregateTrigger_noNamedBudgets()851 public void testParseAggregateTrigger_noNamedBudgets() throws JSONException { 852 when(mFlags.getMeasurementEnableAggregateValueFilters()).thenReturn(true, false); 853 when(mFlags.getMeasurementEnableAggregatableNamedBudgets()).thenReturn(true); 854 JSONArray triggerDatas = new JSONArray(); 855 JSONObject jsonObject1 = new JSONObject(); 856 jsonObject1.put("key_piece", "0x400"); 857 jsonObject1.put("source_keys", new JSONArray(Arrays.asList("campaignCounts"))); 858 jsonObject1.put("filters", createFilterJSONArray()); 859 jsonObject1.put("not_filters", createFilterJSONArray()); 860 jsonObject1.put("x_network_data", createXNetworkDataJSONObject()); 861 JSONObject jsonObject2 = new JSONObject(); 862 jsonObject2.put("key_piece", "0xA80"); 863 jsonObject2.put("source_keys", new JSONArray(Arrays.asList("geoValue", "noMatch"))); 864 jsonObject1.put("x_network_data", createXNetworkDataJSONObject()); 865 triggerDatas.put(jsonObject1); 866 triggerDatas.put(jsonObject2); 867 868 JSONObject values = new JSONObject(); 869 values.put("campaignCounts", 32768); 870 values.put("geoValue", 1664); 871 872 Trigger trigger = 873 TriggerFixture.getValidTriggerBuilder() 874 .setAggregateTriggerData(triggerDatas.toString()) 875 .setAggregateValuesString(values.toString()) 876 .build(); 877 Optional<AggregatableAttributionTrigger> aggregatableAttributionTrigger = 878 trigger.getAggregatableAttributionTrigger(mFlags); 879 880 assertThat(aggregatableAttributionTrigger).isPresent(); 881 AggregatableAttributionTrigger aggregateTrigger = aggregatableAttributionTrigger.get(); 882 883 assertThat(aggregateTrigger.getNamedBudgets()).isNull(); 884 } 885 886 @Test testGetAttributionDestinationBaseUri_appDestination()887 public void testGetAttributionDestinationBaseUri_appDestination() { 888 Trigger trigger = TriggerFixture.getValidTriggerBuilder() 889 .setAttributionDestination(APP_DESTINATION) 890 .setDestinationType(EventSurfaceType.APP) 891 .build(); 892 assertEquals(APP_DESTINATION, trigger.getAttributionDestinationBaseUri()); 893 } 894 895 @Test testGetAttributionDestinationBaseUri_webDestination()896 public void testGetAttributionDestinationBaseUri_webDestination() { 897 Trigger trigger = TriggerFixture.getValidTriggerBuilder() 898 .setAttributionDestination(WEB_DESTINATION) 899 .setDestinationType(EventSurfaceType.WEB) 900 .build(); 901 assertEquals(WEB_DESTINATION, trigger.getAttributionDestinationBaseUri()); 902 } 903 904 @Test testGetAttributionDestinationBaseUri_trimsWebDestinationWithSubdomain()905 public void testGetAttributionDestinationBaseUri_trimsWebDestinationWithSubdomain() { 906 Trigger trigger = TriggerFixture.getValidTriggerBuilder() 907 .setAttributionDestination(WEB_DESTINATION_WITH_SUBDOMAIN) 908 .setDestinationType(EventSurfaceType.WEB) 909 .build(); 910 assertEquals(WEB_DESTINATION, trigger.getAttributionDestinationBaseUri()); 911 } 912 913 @Test testGetAttributionDestinationBaseUri_trimsWebDestinationWithPath()914 public void testGetAttributionDestinationBaseUri_trimsWebDestinationWithPath() { 915 Trigger trigger = TriggerFixture.getValidTriggerBuilder() 916 .setAttributionDestination(WEB_DESTINATION_WITH_PATH) 917 .setDestinationType(EventSurfaceType.WEB) 918 .build(); 919 assertEquals(WEB_DESTINATION, trigger.getAttributionDestinationBaseUri()); 920 } 921 922 @Test 923 public void testGetAttributionDestinationBaseUri_trimsWebDestinationWithSubdomainPathQueryFrag()924 testGetAttributionDestinationBaseUri_trimsWebDestinationWithSubdomainPathQueryFrag() { 925 Trigger trigger = TriggerFixture.getValidTriggerBuilder() 926 .setAttributionDestination(WEB_DESTINATION_WITH_SUBDOMAIN_PATH_QUERY_FRAGMENT) 927 .setDestinationType(EventSurfaceType.WEB) 928 .build(); 929 assertEquals(WEB_DESTINATION, trigger.getAttributionDestinationBaseUri()); 930 } 931 932 @Test testGetAttributionDestinationBaseUri_invalidWebDestination()933 public void testGetAttributionDestinationBaseUri_invalidWebDestination() { 934 Trigger trigger = TriggerFixture.getValidTriggerBuilder() 935 .setAttributionDestination(WEB_DESTINATION_INVALID) 936 .setDestinationType(EventSurfaceType.WEB) 937 .build(); 938 assertNull(trigger.getAttributionDestinationBaseUri()); 939 } 940 941 @Test parseEventTriggers_handlesValueField()942 public void parseEventTriggers_handlesValueField() throws JSONException { 943 // setup 944 JSONObject filtersMap1 = 945 new JSONObject( 946 "{\n" 947 + " \"filter_key_1\": [\"filter_value_1\"], \n" 948 + " \"filter_key_2\": [\"filter_value_2\"] \n" 949 + " }"); 950 JSONObject notFiltersMap1 = 951 new JSONObject( 952 "{\n" 953 + " \"not_filter_key_1\": [\"not_filter_value_1\", " 954 + "\"not_filter_value_2\"]" 955 + " }"); 956 JSONObject notFiltersMap2 = 957 new JSONObject("{\n" + " \"key_1\": [\"value_1_x\"] \n" + " }"); 958 959 Trigger trigger = 960 TriggerFixture.getValidTriggerBuilder() 961 .setId("triggerId1") 962 .setStatus(Trigger.Status.PENDING) 963 .setEventTriggers( 964 "[\n" 965 + "{\n" 966 + " \"trigger_data\": \"2\",\n" 967 + " \"priority\": \"2\",\n" 968 + " \"value\": \"100\",\n" 969 + " \"deduplication_key\": \"2\",\n" 970 + " \"filters\": [{\n" 971 + " \"filter_key_1\": [\"filter_value_1\"], \n" 972 + " \"filter_key_2\": [\"filter_value_2\"] \n" 973 + " }],\n" 974 + " \"not_filters\": [{\n" 975 + " \"not_filter_key_1\": [\"not_filter_value_1\", " 976 + "\"not_filter_value_2\"]" 977 + " }]\n" 978 + "}," 979 + "{\n" 980 + " \"trigger_data\": \"3\",\n" 981 + " \"priority\": \"3\",\n" 982 + " \"value\": \"120\",\n" 983 + " \"deduplication_key\": \"3\",\n" 984 + " \"not_filters\": [{\n" 985 + " \"key_1\": [\"value_1_x\"] \n" 986 + " }]\n" 987 + "}" 988 + "]\n") 989 .setTriggerTime(234324L) 990 .build(); 991 EventTrigger eventTrigger1 = 992 new EventTrigger.Builder(new UnsignedLong(2L)) 993 .setTriggerPriority(2L) 994 .setTriggerValue(100L) 995 .setDedupKey(new UnsignedLong(2L)) 996 .setFilterSet( 997 List.of( 998 new FilterMap.Builder() 999 .buildFilterData(filtersMap1) 1000 .build())) 1001 .setNotFilterSet( 1002 List.of( 1003 new FilterMap.Builder() 1004 .buildFilterData(notFiltersMap1) 1005 .build())) 1006 .build(); 1007 EventTrigger eventTrigger2 = 1008 new EventTrigger.Builder(new UnsignedLong(3L)) 1009 .setTriggerPriority(3L) 1010 .setTriggerValue(120L) 1011 .setDedupKey(new UnsignedLong(3L)) 1012 .setNotFilterSet( 1013 List.of( 1014 new FilterMap.Builder() 1015 .buildFilterData(notFiltersMap2) 1016 .build())) 1017 .build(); 1018 1019 when(mFlags.getMeasurementFlexibleEventReportingApiEnabled()).thenReturn(true); 1020 1021 // Action 1022 List<EventTrigger> actualEventTriggers = trigger.parseEventTriggers(mFlags); 1023 1024 // Assertion 1025 assertEquals(Arrays.asList(eventTrigger1, eventTrigger2), actualEventTriggers); 1026 } 1027 1028 @Test parseAdtechBitMapping_nonEmpty_parseSuccess()1029 public void parseAdtechBitMapping_nonEmpty_parseSuccess() throws JSONException { 1030 Trigger trigger = 1031 TriggerFixture.getValidTriggerBuilder() 1032 .setId("triggerId1") 1033 .setStatus(Trigger.Status.PENDING) 1034 .setAdtechBitMapping( 1035 "{\"AdTechA-enrollment_id\": \"0x1\"," 1036 + "\"AdTechB-enrollment_id\": \"0x2\"}") 1037 .build(); 1038 1039 Map<String, BigInteger> adtechMapping = trigger.parseAdtechKeyMapping(); 1040 assertEquals(adtechMapping.size(), 2); 1041 BigInteger adtechBit1 = new BigInteger("1", 16); 1042 BigInteger adtechBit2 = new BigInteger("2", 16); 1043 assertEquals(adtechMapping.get("AdTechA-enrollment_id"), adtechBit1); 1044 assertEquals(adtechMapping.get("AdTechB-enrollment_id"), adtechBit2); 1045 } 1046 1047 @Test getAttributionScopes_validJsonStringArray_parseSuccess()1048 public void getAttributionScopes_validJsonStringArray_parseSuccess() throws JSONException { 1049 Trigger trigger = 1050 TriggerFixture.getValidTriggerBuilder() 1051 .setId("triggerId1") 1052 .setAttributionScopesString("[\"1\", \"2\"]") 1053 .build(); 1054 assertThat(trigger.getAttributionScopes()).containsExactly("1", "2"); 1055 } 1056 1057 @Test testParseAggregateTrigger_anyUnsupportedAggValuesJsonObject_throwsException()1058 public void testParseAggregateTrigger_anyUnsupportedAggValuesJsonObject_throwsException() { 1059 String unsupportedAggregatableValues = 1060 "{\"campaignCounts\": 32768, \"geoValue\":{\"value\": " + "1664}}"; 1061 Trigger trigger = 1062 TriggerFixture.getValidTriggerBuilder() 1063 .setAggregateValuesString(unsupportedAggregatableValues) 1064 .build(); 1065 assertThrows(JSONException.class, () -> trigger.getAggregatableAttributionTrigger(mFlags)); 1066 } 1067 1068 @Test testParseAggregateTrigger_anyUnsupportedAggValuesJsonArray_throwsException()1069 public void testParseAggregateTrigger_anyUnsupportedAggValuesJsonArray_throwsException() { 1070 when(mFlags.getMeasurementEnableAggregateValueFilters()).thenReturn(true); 1071 String unsupportedAggregatableValues = 1072 "[ {\"values\": {\"campaignCounts\": 32768, \"geoValue\":{\"value\": " + "1664}}"; 1073 Trigger trigger = 1074 TriggerFixture.getValidTriggerBuilder() 1075 .setAggregateValuesString(unsupportedAggregatableValues) 1076 .build(); 1077 assertThrows(JSONException.class, () -> trigger.getAggregatableAttributionTrigger(mFlags)); 1078 } 1079 1080 @Test testParseAggregateTrigger_aggValuesJsonObjectFlexibleFilterOn_passes()1081 public void testParseAggregateTrigger_aggValuesJsonObjectFlexibleFilterOn_passes() 1082 throws Exception { 1083 when(mFlags.getMeasurementEnableFlexibleContributionFiltering()).thenReturn(true); 1084 String validAggregatableValues = 1085 "{\"campaignCounts\": {\"value\":32768, \"filtering_id\":\"255\"}," 1086 + " \"geoValue\":1664}}"; 1087 Trigger trigger = 1088 TriggerFixture.getValidTriggerBuilder() 1089 .setAggregateValuesString(validAggregatableValues) 1090 .build(); 1091 Optional<AggregatableAttributionTrigger> aggregatableAttributionTrigger = 1092 trigger.getAggregatableAttributionTrigger(mFlags); 1093 assertThat(aggregatableAttributionTrigger).isNotNull(); 1094 AggregatableValuesConfig config = 1095 aggregatableAttributionTrigger.get().getValueConfigs().get(0); 1096 assertThat(config.getValues().keySet().size()).isEqualTo(2); 1097 assertThat(config.getValues().get("campaignCounts").getFilteringId()) 1098 .isEqualTo(new UnsignedLong("255")); 1099 assertThat(config.getValues().get("campaignCounts").getValue()).isEqualTo(32768); 1100 assertThat(config.getValues().get("geoValue").getValue()).isEqualTo(1664); 1101 assertThat(config.getValues().get("geoValue").getFilteringId()) 1102 .isEqualTo(UnsignedLong.ZERO); 1103 } 1104 1105 @Test testParseAggregateTrigger_aggValuesJsonArrayAggregateValueFiltersOff_returnsEmpty()1106 public void testParseAggregateTrigger_aggValuesJsonArrayAggregateValueFiltersOff_returnsEmpty() 1107 throws JSONException { 1108 String invalidAggregatableValues = 1109 "[ {\"values\": {\"campaignCounts\": {\"value\": 1664}}} ]"; 1110 // Aggregate Values in Trigger table is persisted in JSONArray string format. 1111 Trigger trigger = 1112 TriggerFixture.getValidTriggerBuilder() 1113 .setAggregateValuesString(invalidAggregatableValues) 1114 .build(); 1115 // Values are not parsable and trigger is rejected. 1116 assertThat(trigger.getAggregatableAttributionTrigger(mFlags)).isEqualTo(Optional.empty()); 1117 } 1118 1119 @Test testParseAggregateTrigger_aggValuesJsonArrayFlexibleFilterAggUnsupported_throws()1120 public void testParseAggregateTrigger_aggValuesJsonArrayFlexibleFilterAggUnsupported_throws() { 1121 when(mFlags.getMeasurementEnableAggregateValueFilters()).thenReturn(true); 1122 String unsupportedAggregatableValues = 1123 "[ {\"values\": {\"campaignCounts\": {\"value\": 1664}}} ]"; 1124 Trigger trigger = 1125 TriggerFixture.getValidTriggerBuilder() 1126 .setAggregateValuesString(unsupportedAggregatableValues) 1127 .build(); 1128 assertThrows(JSONException.class, () -> trigger.getAggregatableAttributionTrigger(mFlags)); 1129 } 1130 1131 @Test testParseAggregateTrigger_aggValuesJsonArrayAggregateValueFiltersOn_success()1132 public void testParseAggregateTrigger_aggValuesJsonArrayAggregateValueFiltersOn_success() 1133 throws Exception { 1134 when(mFlags.getMeasurementEnableAggregateValueFilters()).thenReturn(true); 1135 String validAggregatableValues = 1136 "[{\"values\":{\"campaignCounts\":32768, \"geoValue\":1664}},{\"values\":{\"a\":1," 1137 + " \"b\":2, \"c\":3}}]"; 1138 // Verify aggregatable values string gets parsed into AggregatableValuesConfig. 1139 Trigger trigger = 1140 TriggerFixture.getValidTriggerBuilder() 1141 .setAggregateValuesString(validAggregatableValues) 1142 .build(); 1143 Optional<AggregatableAttributionTrigger> aggregatableAttributionTrigger = 1144 trigger.getAggregatableAttributionTrigger(mFlags); 1145 assertThat(aggregatableAttributionTrigger).isNotNull(); 1146 assertThat(aggregatableAttributionTrigger.get().getValueConfigs().size()) 1147 .isEqualTo(2); 1148 assertThat(aggregatableAttributionTrigger.get().getValueConfigs().get(0).getValues().size()) 1149 .isEqualTo(2); 1150 assertThat(aggregatableAttributionTrigger.get().getValueConfigs().get(1).getValues().size()) 1151 .isEqualTo(3); 1152 } 1153 1154 @Test 1155 public void testParseAggregateTrigger_aggregateValuesJsonArrayFlagsEnabledWithFilteringId_passes()1156 testParseAggregateTrigger_aggregateValuesJsonArrayFlagsEnabledWithFilteringId_passes() 1157 throws Exception { 1158 when(mFlags.getMeasurementEnableAggregateValueFilters()).thenReturn(true); 1159 when(mFlags.getMeasurementEnableFlexibleContributionFiltering()).thenReturn(true); 1160 String validAggregatableValues = 1161 "[{\"values\":{\"campaignCounts\":{\"value\":32768,\"filtering_id\":\"123\"}," 1162 + "\"geoValue\":1664}}]"; 1163 Trigger trigger = 1164 TriggerFixture.getValidTriggerBuilder() 1165 .setAggregateValuesString(validAggregatableValues) 1166 .build(); 1167 Optional<AggregatableAttributionTrigger> aggregatableAttributionTrigger = 1168 trigger.getAggregatableAttributionTrigger(mFlags); 1169 assertThat(aggregatableAttributionTrigger).isNotNull(); 1170 AggregatableValuesConfig config = 1171 aggregatableAttributionTrigger.get().getValueConfigs().get(0); 1172 assertThat(config.getValues().get("campaignCounts").getValue()).isEqualTo(32768); 1173 assertThat(config.getValues().get("campaignCounts").getFilteringId()) 1174 .isEqualTo(new UnsignedLong("123")); 1175 assertThat(config.getValues().get("geoValue").getValue()).isEqualTo(1664); 1176 assertThat(config.getValues().get("geoValue").getFilteringId()) 1177 .isEqualTo(UnsignedLong.ZERO); 1178 } 1179 1180 1181 @Test aggregateDebugReport_parsing_asExpected()1182 public void aggregateDebugReport_parsing_asExpected() throws JSONException { 1183 // Setup 1184 String aggregateDebugReport = 1185 "{\"key_piece\":\"0x222\"," 1186 + "\"debug_data\":[" 1187 + "{" 1188 + "\"types\": [\"trigger-aggregate-insufficient-budget\", " 1189 + "\"trigger-aggregate-deduplicated\"]," 1190 + "\"key_piece\": \"0x333\"," 1191 + "\"value\": 333" 1192 + "}," 1193 + "{" 1194 + "\"types\": [\"trigger-aggregate-report-window-passed\", " 1195 + "\"trigger-event-low-priority\"]," 1196 + "\"key_piece\": \"0x444\"," 1197 + "\"value\": 444" 1198 + "}," 1199 + "{" 1200 + "\"types\": [\"unspecified\"]," 1201 + "\"key_piece\": \"0x555\"," 1202 + "\"value\": 555" 1203 + "}" 1204 + "]," 1205 + "\"aggregation_coordinator_origin\":\"https://aws.example\"}"; 1206 Source source = 1207 SourceFixture.getValidSourceBuilder() 1208 .setAggregateDebugReportingString(aggregateDebugReport) 1209 .build(); 1210 1211 // Execution 1212 AggregateDebugReportData debugData1 = 1213 new AggregateDebugReportData.Builder( 1214 new HashSet<>( 1215 Arrays.asList( 1216 DebugReportApi.Type 1217 .TRIGGER_AGGREGATE_INSUFFICIENT_BUDGET 1218 .getValue(), 1219 DebugReportApi.Type.TRIGGER_AGGREGATE_DEDUPLICATED 1220 .getValue())), 1221 new BigInteger("333", 16), 1222 333) 1223 .build(); 1224 AggregateDebugReportData debugData2 = 1225 new AggregateDebugReportData.Builder( 1226 new HashSet<>( 1227 Arrays.asList( 1228 DebugReportApi.Type 1229 .TRIGGER_AGGREGATE_REPORT_WINDOW_PASSED 1230 .getValue(), 1231 DebugReportApi.Type.TRIGGER_EVENT_LOW_PRIORITY 1232 .getValue())), 1233 new BigInteger("444", 16), 1234 444) 1235 .build(); 1236 AggregateDebugReportData debugData3 = 1237 new AggregateDebugReportData.Builder( 1238 Collections.singleton(DebugReportApi.Type.UNSPECIFIED.getValue()), 1239 new BigInteger("555", 16), 1240 555) 1241 .build(); 1242 1243 // Assertion 1244 assertThat(source.getAggregateDebugReportingObject()) 1245 .isEqualTo( 1246 new AggregateDebugReporting.Builder( 1247 0, 1248 new BigInteger("222", 16), 1249 Arrays.asList(debugData1, debugData2, debugData3), 1250 Uri.parse("https://aws.example")) 1251 .build()); 1252 } 1253 1254 @Test hasAggregatableData_aggregateValuesAndDataNonEmpty_success()1255 public void hasAggregatableData_aggregateValuesAndDataNonEmpty_success() throws JSONException { 1256 Trigger trigger = 1257 TriggerFixture.getValidTriggerBuilder() 1258 .setId("triggerId1") 1259 .setAggregateTriggerData(ValidTriggerParams.AGGREGATE_TRIGGER_DATA) 1260 .setAggregateValuesString(ValidTriggerParams.AGGREGATE_VALUES_STRING) 1261 .build(); 1262 assertThat(trigger.hasAggregatableData(mFlags)).isTrue(); 1263 } 1264 1265 @Test hasAggregatableData_aggregateDataNonEmptyAggregateValuesEmptyArray_success()1266 public void hasAggregatableData_aggregateDataNonEmptyAggregateValuesEmptyArray_success() 1267 throws JSONException { 1268 when(mFlags.getMeasurementEnableAggregateValueFilters()).thenReturn(true); 1269 Trigger trigger = 1270 TriggerFixture.getValidTriggerBuilder() 1271 .setId("triggerId1") 1272 .setAggregateValuesString("[]") 1273 .setAggregateTriggerData(ValidTriggerParams.AGGREGATE_TRIGGER_DATA) 1274 .build(); 1275 assertThat(trigger.hasAggregatableData(mFlags)).isTrue(); 1276 } 1277 1278 @Test hasAggregatableData_aggregateDataNonEmptyAggregateValuesEmptyObject_success()1279 public void hasAggregatableData_aggregateDataNonEmptyAggregateValuesEmptyObject_success() 1280 throws JSONException { 1281 Trigger trigger = 1282 TriggerFixture.getValidTriggerBuilder() 1283 .setId("triggerId1") 1284 .setAggregateValuesString("{}") 1285 .setAggregateTriggerData(ValidTriggerParams.AGGREGATE_TRIGGER_DATA) 1286 .build(); 1287 assertThat(trigger.hasAggregatableData(mFlags)).isTrue(); 1288 } 1289 1290 @Test hasAggregatableData_aggregateValuesPresent_success()1291 public void hasAggregatableData_aggregateValuesPresent_success() throws JSONException { 1292 Trigger trigger = 1293 TriggerFixture.getValidTriggerBuilder() 1294 .setId("triggerId1") 1295 .setAggregateValuesString(ValidTriggerParams.AGGREGATE_VALUES_STRING) 1296 .setAggregateTriggerData("[]") 1297 .build(); 1298 assertThat(trigger.hasAggregatableData(mFlags)).isTrue(); 1299 } 1300 1301 @Test hasAggregatableData_aggregateValuesAndDataNotPresent_fail()1302 public void hasAggregatableData_aggregateValuesAndDataNotPresent_fail() throws JSONException { 1303 Trigger trigger = TriggerFixture.getValidTriggerBuilder().setId("triggerId1").build(); 1304 assertThat(trigger.hasAggregatableData(mFlags)).isFalse(); 1305 } 1306 1307 @Test hasAggregatableData_aggregateValuesObjectAndDataEmpty_fail()1308 public void hasAggregatableData_aggregateValuesObjectAndDataEmpty_fail() throws JSONException { 1309 Trigger trigger = 1310 TriggerFixture.getValidTriggerBuilder() 1311 .setId("triggerId1") 1312 .setAggregateValuesString("{}") 1313 .setAggregateTriggerData("[]") 1314 .build(); 1315 assertThat(trigger.hasAggregatableData(mFlags)).isFalse(); 1316 } 1317 1318 @Test hasAggregatableData_aggregateValuesArrayAndDataEmpty_fail()1319 public void hasAggregatableData_aggregateValuesArrayAndDataEmpty_fail() throws JSONException { 1320 when(mFlags.getMeasurementEnableAggregateValueFilters()).thenReturn(true); 1321 Trigger trigger = 1322 TriggerFixture.getValidTriggerBuilder() 1323 .setId("triggerId1") 1324 .setAggregateValuesString("[]") 1325 .setAggregateTriggerData("[]") 1326 .build(); 1327 assertThat(trigger.hasAggregatableData(mFlags)).isFalse(); 1328 } 1329 assertInvalidTriggerArguments( Uri attributionDestination, String enrollmentId, Uri registrant, Long triggerTime, String eventTriggers, String aggregateTriggerData, String aggregateValues, String filters, String notFilters, UnsignedLong debugKey, String mAttributionConfig, String mAdtechBitMapping, Uri registrationOrigin, Trigger.SourceRegistrationTimeConfig sourceRegistrationTimeConfig)1330 private void assertInvalidTriggerArguments( 1331 Uri attributionDestination, 1332 String enrollmentId, 1333 Uri registrant, 1334 Long triggerTime, 1335 String eventTriggers, 1336 String aggregateTriggerData, 1337 String aggregateValues, 1338 String filters, 1339 String notFilters, 1340 UnsignedLong debugKey, 1341 String mAttributionConfig, 1342 String mAdtechBitMapping, 1343 Uri registrationOrigin, 1344 Trigger.SourceRegistrationTimeConfig sourceRegistrationTimeConfig) { 1345 assertThrows( 1346 IllegalArgumentException.class, 1347 () -> 1348 new Trigger.Builder() 1349 .setAttributionDestination(attributionDestination) 1350 .setEnrollmentId(enrollmentId) 1351 .setRegistrant(registrant) 1352 .setTriggerTime(triggerTime) 1353 .setEventTriggers(eventTriggers) 1354 .setAggregateTriggerData(aggregateTriggerData) 1355 .setAggregateValuesString(aggregateValues) 1356 .setFilters(filters) 1357 .setNotFilters(notFilters) 1358 .setDebugKey(debugKey) 1359 .setAttributionConfig(mAttributionConfig) 1360 .setAdtechBitMapping(mAdtechBitMapping) 1361 .setRegistrationOrigin(registrationOrigin) 1362 .setAggregatableSourceRegistrationTimeConfig( 1363 sourceRegistrationTimeConfig) 1364 .build()); 1365 } 1366 createFilterJSONArray()1367 private JSONArray createFilterJSONArray() throws JSONException { 1368 JSONObject filterMap = new JSONObject(); 1369 filterMap.put( 1370 "conversion_subdomain", new JSONArray(Arrays.asList("electronics.megastore"))); 1371 filterMap.put("product", new JSONArray(Arrays.asList("1234", "2345"))); 1372 JSONArray filterSet = new JSONArray(); 1373 filterSet.put(filterMap); 1374 return filterSet; 1375 } 1376 createXNetworkDataJSONObject()1377 private JSONObject createXNetworkDataJSONObject() throws JSONException { 1378 JSONObject xNetworkData = new JSONObject(); 1379 xNetworkData.put("key_offset", 10L); 1380 return xNetworkData; 1381 } 1382 createAttributionConfigJSONArray()1383 private JSONArray createAttributionConfigJSONArray() throws JSONException { 1384 JSONArray attributionConfigList = new JSONArray(); 1385 List<String> adtechIds = new ArrayList<>(Arrays.asList("AdTech1-Ads", "AdTech2-Ads")); 1386 for (String adtechId : adtechIds) { 1387 JSONObject attributionConfig = new JSONObject(); 1388 attributionConfig.put("source_network", adtechId); 1389 JSONObject sourcePriorityRange = new JSONObject(); 1390 sourcePriorityRange.put("start", 100L); 1391 sourcePriorityRange.put("end", 1000L); 1392 attributionConfig.put("source_priority_range", sourcePriorityRange); 1393 JSONObject sourceFilters = new JSONObject(); 1394 sourceFilters.put("campaign_type", new JSONArray(Arrays.asList("install"))); 1395 sourceFilters.put("source_type", new JSONArray(Arrays.asList("navigation"))); 1396 JSONArray sourceFilterSet = new JSONArray(); 1397 sourceFilterSet.put(sourceFilters); 1398 attributionConfig.put("source_filters", sourceFilterSet); 1399 JSONObject sourceNotFilters = new JSONObject(); 1400 sourceNotFilters.put("campaign_type", new JSONArray(Arrays.asList("product"))); 1401 JSONArray sourceNotFilterSet = new JSONArray(); 1402 sourceNotFilterSet.put(sourceNotFilters); 1403 attributionConfig.put("source_not_filters", sourceNotFilterSet); 1404 attributionConfig.put("source_expiry_override", 600000L); 1405 attributionConfig.put("priority", 99L); 1406 attributionConfig.put("expiry", 604800L); 1407 JSONObject filterData = new JSONObject(); 1408 filterData.put("campaign_type", new JSONArray(Arrays.asList("install"))); 1409 JSONArray filterDataSet = new JSONArray(); 1410 filterDataSet.put(filterData); 1411 attributionConfig.put("filter_data", filterDataSet); 1412 attributionConfig.put("post_install_exclusivity_window", 100000L); 1413 attributionConfigList.put(attributionConfig); 1414 } 1415 return attributionConfigList; 1416 } 1417 } 1418