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.common;
18 
19 import static android.adservices.adselection.CustomAudienceBiddingInfoFixture.DATA_VERSION_1;
20 import static android.adservices.adselection.CustomAudienceBiddingInfoFixture.DATA_VERSION_2;
21 import static android.adservices.customaudience.CustomAudienceFixture.VALID_OWNER;
22 
23 import static com.android.adservices.data.adselection.AdSelectionDatabase.DATABASE_NAME;
24 import static com.android.adservices.service.adselection.AdSelectionScriptEngine.NUM_BITS_STOCHASTIC_ROUNDING;
25 import static com.android.adservices.service.adselection.DataVersionFetcher.DATA_VERSION_HEADER_BIDDING_KEY;
26 import static com.android.adservices.service.adselection.DataVersionFetcher.DATA_VERSION_HEADER_SCORING_KEY;
27 import static com.android.adservices.service.adselection.ImpressionReporterLegacy.CALLER_PACKAGE_NAME_MISMATCH;
28 import static com.android.adservices.service.customaudience.FetchCustomAudienceImplTest.FetchCustomAudienceTestCallback;
29 import static com.android.adservices.service.stats.AdSelectionExecutionLoggerTest.DB_AD_SELECTION_FILE_SIZE;
30 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION;
31 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__REPORT_INTERACTION;
32 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
33 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
34 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
35 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
36 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow;
37 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
38 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
39 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
40 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
41 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
42 
43 import static com.google.common.truth.Truth.assertThat;
44 import static com.google.common.truth.Truth.assertWithMessage;
45 
46 import static org.junit.Assert.assertEquals;
47 import static org.junit.Assert.assertFalse;
48 import static org.junit.Assert.assertNotNull;
49 import static org.junit.Assert.assertNull;
50 import static org.junit.Assert.assertTrue;
51 import static org.mockito.ArgumentMatchers.anyInt;
52 import static org.mockito.ArgumentMatchers.anyString;
53 import static org.mockito.Mockito.never;
54 import static org.mockito.Mockito.spy;
55 
56 import android.adservices.adid.AdId;
57 import android.adservices.adselection.AdSelectionCallback;
58 import android.adservices.adselection.AdSelectionConfig;
59 import android.adservices.adselection.AdSelectionConfigFixture;
60 import android.adservices.adselection.AdSelectionInput;
61 import android.adservices.adselection.AdSelectionOverrideCallback;
62 import android.adservices.adselection.AdSelectionResponse;
63 import android.adservices.adselection.DecisionLogic;
64 import android.adservices.adselection.PerBuyerDecisionLogic;
65 import android.adservices.adselection.ReportEventRequest;
66 import android.adservices.adselection.ReportImpressionCallback;
67 import android.adservices.adselection.ReportImpressionInput;
68 import android.adservices.adselection.ReportInteractionCallback;
69 import android.adservices.adselection.ReportInteractionInput;
70 import android.adservices.adselection.SetAppInstallAdvertisersCallback;
71 import android.adservices.adselection.SetAppInstallAdvertisersInput;
72 import android.adservices.adselection.SignedContextualAds;
73 import android.adservices.adselection.SignedContextualAdsFixture;
74 import android.adservices.adselection.UpdateAdCounterHistogramInput;
75 import android.adservices.common.AdData;
76 import android.adservices.common.AdDataFixture;
77 import android.adservices.common.AdFilters;
78 import android.adservices.common.AdSelectionSignals;
79 import android.adservices.common.AdServicesStatusUtils;
80 import android.adservices.common.AdTechIdentifier;
81 import android.adservices.common.AppInstallFilters;
82 import android.adservices.common.CallerMetadata;
83 import android.adservices.common.CallingAppUidSupplierProcessImpl;
84 import android.adservices.common.CommonFixture;
85 import android.adservices.common.FledgeErrorResponse;
86 import android.adservices.common.FrequencyCapFilters;
87 import android.adservices.common.KeyedFrequencyCap;
88 import android.adservices.common.KeyedFrequencyCapFixture;
89 import android.adservices.customaudience.CustomAudience;
90 import android.adservices.customaudience.CustomAudienceFixture;
91 import android.adservices.customaudience.CustomAudienceOverrideCallback;
92 import android.adservices.customaudience.FetchAndJoinCustomAudienceInput;
93 import android.adservices.customaudience.ICustomAudienceCallback;
94 import android.adservices.customaudience.TrustedBiddingData;
95 import android.adservices.customaudience.TrustedBiddingDataFixture;
96 import android.adservices.http.MockWebServerRule;
97 import android.content.Context;
98 import android.content.pm.PackageManager;
99 import android.net.Uri;
100 import android.os.IBinder;
101 import android.os.Process;
102 import android.os.RemoteException;
103 
104 import androidx.room.Room;
105 import androidx.test.core.app.ApplicationProvider;
106 import androidx.test.filters.FlakyTest;
107 
108 import com.android.adservices.MockWebServerRuleFactory;
109 import com.android.adservices.common.AdServicesExtendedMockitoTestCase;
110 import com.android.adservices.common.WebViewSupportUtil;
111 import com.android.adservices.concurrency.AdServicesExecutors;
112 import com.android.adservices.data.adselection.AdSelectionDatabase;
113 import com.android.adservices.data.adselection.AdSelectionDebugReportDao;
114 import com.android.adservices.data.adselection.AdSelectionDebugReportingDatabase;
115 import com.android.adservices.data.adselection.AdSelectionEntryDao;
116 import com.android.adservices.data.adselection.AdSelectionServerDatabase;
117 import com.android.adservices.data.adselection.AppInstallDao;
118 import com.android.adservices.data.adselection.ConsentedDebugConfigurationDao;
119 import com.android.adservices.data.adselection.DBAdSelectionDebugReport;
120 import com.android.adservices.data.adselection.FrequencyCapDao;
121 import com.android.adservices.data.adselection.SharedStorageDatabase;
122 import com.android.adservices.data.common.DBAdData;
123 import com.android.adservices.data.customaudience.AdDataConversionStrategy;
124 import com.android.adservices.data.customaudience.AdDataConversionStrategyFactory;
125 import com.android.adservices.data.customaudience.CustomAudienceDao;
126 import com.android.adservices.data.customaudience.CustomAudienceDatabase;
127 import com.android.adservices.data.customaudience.DBCustomAudience;
128 import com.android.adservices.data.customaudience.DBTrustedBiddingData;
129 import com.android.adservices.data.encryptionkey.EncryptionKeyDao;
130 import com.android.adservices.data.enrollment.EnrollmentDao;
131 import com.android.adservices.data.signals.EncodedPayloadDao;
132 import com.android.adservices.data.signals.ProtectedSignalsDatabase;
133 import com.android.adservices.service.Flags;
134 import com.android.adservices.service.FlagsFactory;
135 import com.android.adservices.service.adid.AdIdCacheManager;
136 import com.android.adservices.service.adselection.AdCost;
137 import com.android.adservices.service.adselection.AdFilteringFeatureFactory;
138 import com.android.adservices.service.adselection.AdIdFetcher;
139 import com.android.adservices.service.adselection.AdSelectionServiceImpl;
140 import com.android.adservices.service.adselection.DebugReportSenderJobService;
141 import com.android.adservices.service.adselection.EventReporter;
142 import com.android.adservices.service.adselection.JsVersionHelper;
143 import com.android.adservices.service.adselection.JsVersionRegister;
144 import com.android.adservices.service.adselection.MockAdIdWorker;
145 import com.android.adservices.service.adselection.MultiCloudSupportStrategy;
146 import com.android.adservices.service.adselection.MultiCloudTestStrategyFactory;
147 import com.android.adservices.service.adselection.UpdateAdCounterHistogramWorkerTest;
148 import com.android.adservices.service.adselection.debug.ConsentedDebugConfigurationGeneratorFactory;
149 import com.android.adservices.service.adselection.encryption.ObliviousHttpEncryptor;
150 import com.android.adservices.service.common.cache.CacheProviderFactory;
151 import com.android.adservices.service.common.httpclient.AdServicesHttpsClient;
152 import com.android.adservices.service.consent.AdServicesApiConsent;
153 import com.android.adservices.service.consent.AdServicesApiType;
154 import com.android.adservices.service.consent.ConsentManager;
155 import com.android.adservices.service.customaudience.BackgroundFetchJob;
156 import com.android.adservices.service.customaudience.CustomAudienceBlobFixture;
157 import com.android.adservices.service.customaudience.CustomAudienceImpl;
158 import com.android.adservices.service.customaudience.CustomAudienceQuantityChecker;
159 import com.android.adservices.service.customaudience.CustomAudienceServiceImpl;
160 import com.android.adservices.service.customaudience.CustomAudienceValidator;
161 import com.android.adservices.service.devapi.DevContext;
162 import com.android.adservices.service.devapi.DevContextFilter;
163 import com.android.adservices.service.exception.FilterException;
164 import com.android.adservices.service.kanon.KAnonSignJoinFactory;
165 import com.android.adservices.service.signals.EgressConfigurationGenerator;
166 import com.android.adservices.service.stats.AdServicesLogger;
167 import com.android.adservices.shared.testing.SupportedByConditionRule;
168 import com.android.modules.utils.testing.ExtendedMockitoRule.MockStatic;
169 import com.android.modules.utils.testing.ExtendedMockitoRule.SpyStatic;
170 
171 import com.google.common.collect.ImmutableList;
172 import com.google.common.collect.ImmutableMap;
173 import com.google.common.collect.ImmutableSet;
174 import com.google.common.util.concurrent.MoreExecutors;
175 import com.google.mockwebserver.MockResponse;
176 import com.google.mockwebserver.MockWebServer;
177 
178 import org.junit.Before;
179 import org.junit.Rule;
180 import org.junit.Test;
181 import org.mockito.Mock;
182 
183 import java.io.File;
184 import java.time.Duration;
185 import java.util.ArrayList;
186 import java.util.Arrays;
187 import java.util.Collections;
188 import java.util.HashMap;
189 import java.util.HashSet;
190 import java.util.List;
191 import java.util.Map;
192 import java.util.Objects;
193 import java.util.Optional;
194 import java.util.Set;
195 import java.util.concurrent.CountDownLatch;
196 import java.util.concurrent.ExecutorService;
197 import java.util.concurrent.ScheduledThreadPoolExecutor;
198 import java.util.concurrent.Semaphore;
199 import java.util.concurrent.TimeUnit;
200 import java.util.stream.Collectors;
201 
202 @SpyStatic(FlagsFactory.class)
203 @MockStatic(BackgroundJobsManager.class)
204 @MockStatic(ConsentManager.class)
205 @MockStatic(AppImportanceFilter.class)
206 @MockStatic(DebugReportSenderJobService.class)
207 @MockStatic(BackgroundFetchJob.class)
208 public final class FledgeE2ETest extends AdServicesExtendedMockitoTestCase {
209     public static final String CUSTOM_AUDIENCE_SEQ_1 = "/ca1";
210     public static final String CUSTOM_AUDIENCE_SEQ_2 = "/ca2";
211     private static final String FETCH_CA_PATH = "/fetch";
212     public static final AppInstallFilters CURRENT_APP_FILTER =
213             new AppInstallFilters.Builder()
214                     .setPackageNames(new HashSet<>(Arrays.asList(CommonFixture.TEST_PACKAGE_NAME)))
215                     .build();
216     public static final FrequencyCapFilters CLICK_ONCE_PER_DAY_KEY1 =
217             new FrequencyCapFilters.Builder()
218                     .setKeyedFrequencyCapsForClickEvents(
219                             ImmutableList.of(
220                                     new KeyedFrequencyCap.Builder(
221                                                     KeyedFrequencyCapFixture.KEY1,
222                                                     1,
223                                                     Duration.ofDays(1))
224                                             .build()))
225                     .build();
226     public static final FrequencyCapFilters WIN_ONCE_PER_DAY_KEY1 =
227             new FrequencyCapFilters.Builder()
228                     .setKeyedFrequencyCapsForWinEvents(
229                             ImmutableList.of(
230                                     new KeyedFrequencyCap.Builder(
231                                                     KeyedFrequencyCapFixture.KEY1,
232                                                     1,
233                                                     Duration.ofDays(1))
234                                             .build()))
235                     .build();
236     private static final AdTechIdentifier LOCALHOST_BUYER =
237             AdTechIdentifier.fromString("localhost");
238     private static final Uri BUYER_DOMAIN_1 =
239             CommonFixture.getUri(AdSelectionConfigFixture.BUYER_1, "");
240     private static final Uri BUYER_DOMAIN_2 =
241             CommonFixture.getUri(AdSelectionConfigFixture.BUYER_2, "");
242     private static final String AD_URI_PREFIX = "/adverts/123";
243     private static final String BUYER_BIDDING_LOGIC_URI_PATH = "/buyer/bidding/logic";
244     private static final String BUYER_TRUSTED_SIGNAL_URI_PATH = "/kv/buyer/signals";
245     private static final String BUYER_TRUSTED_SIGNAL_URI_PATH_WITH_DATA_VERSION =
246             "/kv/buyer/data/version/signals/";
247     private static final String SELLER_DECISION_LOGIC_URI_PATH = "/ssp/decision/logic/";
248     private static final String SELLER_TRUSTED_SIGNAL_URI_PATH = "/kv/seller/signals/";
249     private static final String SELLER_TRUSTED_SIGNAL_URI_PATH_WITH_DATA_VERSION =
250             "/kv/seller/data/version/signals/";
251     private static final String SELLER_TRUSTED_SIGNAL_PARAMS = "?renderuris=";
252     private static final String SELLER_REPORTING_PATH = "/reporting/seller";
253     private static final String SELLER_DEBUG_REPORT_WIN_PATH = "/seller/reportWin";
254     private static final String SELLER_DEBUG_REPORT_LOSS_PATH = "/seller/reportLoss";
255     private static final String DEBUG_REPORT_WINNING_BID_PARAM = "?wb=${winningBid}";
256     private static final String DEBUG_REPORT_WINNING_BID_RESPONSE = "?wb=10.0";
257     private static final String BUYER_REPORTING_PATH = "/reporting/buyer";
258     private static final String BUYER_DEBUG_REPORT_WIN_PATH = "/buyer/reportWin";
259     private static final String BUYER_DEBUG_REPORT_LOSS_PATH = "/buyer/reportLoss";
260     private static final AdSelectionSignals TRUSTED_BIDDING_SIGNALS =
261             AdSelectionSignals.fromString(
262                     "{\n"
263                             + "\t\"example\": \"example\",\n"
264                             + "\t\"valid\": \"Also valid\",\n"
265                             + "\t\"list\": \"list\",\n"
266                             + "\t\"of\": \"of\",\n"
267                             + "\t\"keys\": \"trusted bidding signal Values\"\n"
268                             + "}");
269     private static final AdSelectionSignals TRUSTED_SCORING_SIGNALS =
270             AdSelectionSignals.fromString(
271                     "{\n"
272                             + "\t\"render_uri_1\": \"signals_for_1\",\n"
273                             + "\t\"render_uri_2\": \"signals_for_2\"\n"
274                             + "}");
275     private static final PerBuyerDecisionLogic BUYERS_DECISION_LOGIC =
276             new PerBuyerDecisionLogic(
277                     ImmutableMap.of(
278                             CommonFixture.VALID_BUYER_1, new DecisionLogic("reportWin()"),
279                             CommonFixture.VALID_BUYER_2, new DecisionLogic("reportWin()")));
280 
281     // Interaction reporting contestants
282     private static final String CLICK_INTERACTION = "click";
283 
284     private static final String CLICK_SELLER_PATH = "/click/seller";
285     private static final String HOVER_SELLER_PATH = "/hover/seller";
286 
287     private static final String CLICK_BUYER_PATH = "/click/buyer";
288     private static final String HOVER_BUYER_PATH = "/hover/buyer";
289 
290     private static final String INTERACTION_DATA = "{\"key\":\"value\"}";
291 
292     private static final int BUYER_DESTINATION =
293             ReportEventRequest.FLAG_REPORTING_DESTINATION_BUYER;
294     private static final int SELLER_DESTINATION =
295             ReportEventRequest.FLAG_REPORTING_DESTINATION_SELLER;
296 
297     private static final long BINDER_ELAPSED_TIMESTAMP = 100L;
298     private static final List<Double> BIDS_FOR_BUYER_1 = ImmutableList.of(1.1, 2.2);
299     private static final List<Double> BIDS_FOR_BUYER_2 = ImmutableList.of(4.5, 6.7, 10.0);
300     // A list of empty ad counter keys to apply to ads for buyer when not doing fcap filtering.
301     private static final List<Set<Integer>> EMPTY_AD_COUNTER_KEYS_FOR_BUYER_2 =
302             Arrays.asList(new HashSet[BIDS_FOR_BUYER_2.size()]);
303     private static final List<Double> INVALID_BIDS = ImmutableList.of(0.0, -1.0, -2.0);
304 
305     private static final AdCost AD_COST_1 = new AdCost(1.2, NUM_BITS_STOCHASTIC_ROUNDING);
306     private static final AdCost AD_COST_2 = new AdCost(2.2, NUM_BITS_STOCHASTIC_ROUNDING);
307     private static final boolean CONSOLE_MESSAGE_IN_LOGS_ENABLED = true;
308     @Mock private AdServicesLogger mAdServicesLoggerMock;
309 
310     // Every test in this class requires that the JS Sandbox be available. The JS Sandbox
311     // availability depends on an external component (the system webview) being higher than a
312     // certain minimum version.
313     @Rule(order = 11)
314     public final SupportedByConditionRule webViewSupportsJSSandbox =
315             WebViewSupportUtil.createJSSandboxAvailableRule(
316                     ApplicationProvider.getApplicationContext());
317 
318     @Rule(order = 12)
319     public final MockWebServerRule mockWebServerRule = MockWebServerRuleFactory.createForHttps();
320 
321     @Mock private ConsentManager mConsentManagerMock;
322     @Mock private FledgeConsentFilter mFledgeConsentFilterMock;
323     // This object access some system APIs
324     @Mock private DevContextFilter mDevContextFilterMock;
325     @Mock private FledgeApiThrottleFilter mFledgeApiThrottleFilterMock;
326     private AdSelectionConfig mAdSelectionConfig;
327     private AdServicesHttpsClient mAdServicesHttpsClient;
328     private CustomAudienceDao mCustomAudienceDao;
329     private EncodedPayloadDao mEncodedPayloadDao;
330     private AdSelectionEntryDao mAdSelectionEntryDao;
331     private AppInstallDao mAppInstallDao;
332     private FrequencyCapDao mFrequencyCapDao;
333     private EncryptionKeyDao mEncryptionKeyDao;
334     private EnrollmentDao mEnrollmentDao;
335     private ExecutorService mLightweightExecutorService;
336     private ExecutorService mBackgroundExecutorService;
337     private ScheduledThreadPoolExecutor mScheduledExecutor;
338     private CustomAudienceServiceImpl mCustomAudienceService;
339     private AdSelectionServiceImpl mAdSelectionService;
340 
341     private static final Flags DEFAULT_FLAGS =
342             new FledgeE2ETestFlags(
343                     false, true, true, true, true, false, false, false, false, false, false, false);
344     private MockWebServerRule.RequestMatcher<String> mRequestMatcherPrefixMatch;
345     private Uri mLocalhostBuyerDomain;
346     private AdFilteringFeatureFactory mAdFilteringFeatureFactory;
347     private FledgeAllowListsFilter mFledgeAllowListsFilterSpy;
348     @Mock private FledgeAuthorizationFilter mFledgeAuthorizationFilterMock;
349     @Mock private File mMockDBAdSelectionFile;
350     @Mock private AdSelectionServiceFilter mAdSelectionServiceFilterMock;
351     @Mock private AppImportanceFilter mAppImportanceFilterMock;
352     @Mock private ObliviousHttpEncryptor mObliviousHttpEncryptor;
353     private MultiCloudSupportStrategy mMultiCloudSupportStrategy =
354             MultiCloudTestStrategyFactory.getDisabledTestStrategy(mObliviousHttpEncryptor);
355     private AdSelectionDebugReportDao mAdSelectionDebugReportDao;
356     private MockAdIdWorker mMockAdIdWorker;
357     private AdIdFetcher mAdIdFetcher;
358     @Mock private KAnonSignJoinFactory mUnusedKAnonSignJoinFactory;
359     private RetryStrategyFactory mRetryStrategyFactory;
360     private ConsentedDebugConfigurationDao mConsentedDebugConfigurationDao;
361     private ConsentedDebugConfigurationGeneratorFactory
362             mConsentedDebugConfigurationGeneratorFactory;
363     private EgressConfigurationGenerator mEgressConfigurationGenerator;
364 
365     @Before
setUp()366     public void setUp() throws Exception {
367         mocker.mockGetFlags(DEFAULT_FLAGS);
368 
369         mFledgeAllowListsFilterSpy =
370                 spy(new FledgeAllowListsFilter(DEFAULT_FLAGS, mAdServicesLoggerMock));
371 
372         mCustomAudienceDao =
373                 Room.inMemoryDatabaseBuilder(mSpyContext, CustomAudienceDatabase.class)
374                         .addTypeConverter(new DBCustomAudience.Converters(true, true, true))
375                         .build()
376                         .customAudienceDao();
377         mEncodedPayloadDao =
378                 Room.inMemoryDatabaseBuilder(mSpyContext, ProtectedSignalsDatabase.class)
379                         .build()
380                         .getEncodedPayloadDao();
381 
382         mAdSelectionEntryDao =
383                 Room.inMemoryDatabaseBuilder(mSpyContext, AdSelectionDatabase.class)
384                         .build()
385                         .adSelectionEntryDao();
386         SharedStorageDatabase sharedDb =
387                 Room.inMemoryDatabaseBuilder(mSpyContext, SharedStorageDatabase.class).build();
388         mAppInstallDao = sharedDb.appInstallDao();
389         mFrequencyCapDao = sharedDb.frequencyCapDao();
390         AdSelectionServerDatabase serverDb =
391                 Room.inMemoryDatabaseBuilder(mSpyContext, AdSelectionServerDatabase.class).build();
392         mEncryptionKeyDao = EncryptionKeyDao.getInstance();
393         mEnrollmentDao = EnrollmentDao.getInstance();
394         mAdFilteringFeatureFactory =
395                 new AdFilteringFeatureFactory(mAppInstallDao, mFrequencyCapDao, DEFAULT_FLAGS);
396 
397         mLightweightExecutorService = AdServicesExecutors.getLightWeightExecutor();
398         mBackgroundExecutorService = AdServicesExecutors.getBackgroundExecutor();
399         mScheduledExecutor = AdServicesExecutors.getScheduler();
400 
401         mAdServicesHttpsClient =
402                 new AdServicesHttpsClient(
403                         AdServicesExecutors.getBlockingExecutor(),
404                         CacheProviderFactory.createNoOpCache());
405         mAdSelectionDebugReportDao =
406                 Room.inMemoryDatabaseBuilder(mSpyContext, AdSelectionDebugReportingDatabase.class)
407                         .build()
408                         .getAdSelectionDebugReportDao();
409         mMockAdIdWorker = new MockAdIdWorker(new AdIdCacheManager(mSpyContext));
410         mAdIdFetcher =
411                 new AdIdFetcher(
412                         mSpyContext,
413                         mMockAdIdWorker,
414                         mLightweightExecutorService,
415                         mScheduledExecutor);
416         mRetryStrategyFactory = RetryStrategyFactory.createInstanceForTesting();
417         mConsentedDebugConfigurationDao =
418                 Room.inMemoryDatabaseBuilder(mSpyContext, AdSelectionDatabase.class)
419                         .build()
420                         .consentedDebugConfigurationDao();
421         mConsentedDebugConfigurationGeneratorFactory =
422                 new ConsentedDebugConfigurationGeneratorFactory(
423                         false, mConsentedDebugConfigurationDao);
424         mEgressConfigurationGenerator =
425                 EgressConfigurationGenerator.createInstance(
426                         Flags.DEFAULT_FLEDGE_AUCTION_SERVER_ENABLE_PAS_UNLIMITED_EGRESS,
427                         mAdIdFetcher,
428                         Flags.DEFAULT_AUCTION_SERVER_AD_ID_FETCHER_TIMEOUT_MS,
429                         mLightweightExecutorService);
430 
431         initClients(false, true, false, false, false, false);
432 
433         mRequestMatcherPrefixMatch = (a, b) -> !b.isEmpty() && a.startsWith(b);
434 
435         mLocalhostBuyerDomain = Uri.parse(mockWebServerRule.getServerBaseAddress());
436         when(mSpyContext.getDatabasePath(DATABASE_NAME)).thenReturn(mMockDBAdSelectionFile);
437         when(mMockDBAdSelectionFile.length()).thenReturn(DB_AD_SELECTION_FILE_SIZE);
438         doNothing()
439                 .when(mAdSelectionServiceFilterMock)
440                 .filterRequest(
441                         any(),
442                         anyString(),
443                         anyBoolean(),
444                         anyBoolean(),
445                         anyInt(),
446                         anyInt(),
447                         any(),
448                         any());
449         when(ConsentManager.getInstance()).thenReturn(mConsentManagerMock);
450         when(AppImportanceFilter.create(any(), anyInt(), any()))
451                 .thenReturn(mAppImportanceFilterMock);
452         doNothing()
453                 .when(mAppImportanceFilterMock)
454                 .assertCallerIsInForeground(anyInt(), anyInt(), any());
455         mMockAdIdWorker.setResult(AdId.ZERO_OUT, true);
456     }
457 
458     @Test
testFledgeFlowSuccessWithDevOverridesRegisterAdBeaconDisabled()459     public void testFledgeFlowSuccessWithDevOverridesRegisterAdBeaconDisabled() throws Exception {
460         // Re init clients with registerAdBeacon false
461         initClients(false, false, false, false, false, false);
462 
463         setupConsentGivenStubs();
464 
465         setupAdSelectionConfig();
466 
467         String decisionLogicJs = getDecisionLogicJs();
468         String biddingLogicJs = getBiddingLogicJs();
469 
470         MockWebServer server =
471                 mockWebServerRule.startMockWebServer(
472                         request -> new MockResponse().setResponseCode(404));
473 
474         when(mDevContextFilterMock.createDevContext())
475                 .thenReturn(
476                         DevContext.builder()
477                                 .setDevOptionsEnabled(true)
478                                 .setCallingAppPackageName(CommonFixture.TEST_PACKAGE_NAME)
479                                 .build());
480 
481         CustomAudience customAudience1 =
482                 createCustomAudience(
483                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
484 
485         CustomAudience customAudience2 =
486                 createCustomAudience(
487                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, BIDS_FOR_BUYER_2);
488 
489         joinCustomAudienceAndAssertSuccess(customAudience1);
490         joinCustomAudienceAndAssertSuccess(customAudience2);
491 
492         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
493 
494         setupOverridesAndAssertSuccess(
495                 customAudience1, customAudience2, biddingLogicJs, decisionLogicJs);
496 
497         // Run Ad Selection
498         AdSelectionTestCallback resultsCallback =
499                 invokeRunAdSelection(
500                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
501 
502         assertTrue(resultsCallback.mIsSuccess);
503         long resultSelectionId = resultsCallback.mAdSelectionResponse.getAdSelectionId();
504         assertTrue(mAdSelectionEntryDao.doesAdSelectionIdExist(resultSelectionId));
505         assertEquals(
506                 CommonFixture.getUri(
507                         mLocalhostBuyerDomain.getAuthority(),
508                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad3"),
509                 resultsCallback.mAdSelectionResponse.getRenderUri());
510 
511         reportImpressionAndAssertSuccess(resultsCallback.mAdSelectionResponse.getAdSelectionId());
512         mockWebServerRule.verifyMockServerRequests(
513                 server, 0, ImmutableList.of(), mRequestMatcherPrefixMatch);
514     }
515 
516     @Test
testFledgeFlowSuccessWithDevOverridesWithAdCostCpcBillingEnabled()517     public void testFledgeFlowSuccessWithDevOverridesWithAdCostCpcBillingEnabled()
518             throws Exception {
519         // Re init with cpc billing enabled
520         initClients(false, false, true, false, false, false);
521 
522         setupConsentGivenStubs();
523 
524         setupAdSelectionConfig();
525 
526         String decisionLogicJs = getDecisionLogicJs();
527         String biddingLogicJs = getBiddingLogicJsWithAdCost();
528 
529         MockWebServer server =
530                 mockWebServerRule.startMockWebServer(
531                         request -> new MockResponse().setResponseCode(404));
532 
533         when(mDevContextFilterMock.createDevContext())
534                 .thenReturn(
535                         DevContext.builder()
536                                 .setDevOptionsEnabled(true)
537                                 .setCallingAppPackageName(CommonFixture.TEST_PACKAGE_NAME)
538                                 .build());
539 
540         CustomAudience customAudience1 =
541                 createCustomAudienceWithAdCost(
542                         mLocalhostBuyerDomain,
543                         CUSTOM_AUDIENCE_SEQ_1,
544                         BIDS_FOR_BUYER_1,
545                         AD_COST_1.getAdCost());
546 
547         CustomAudience customAudience2 =
548                 createCustomAudienceWithAdCost(
549                         mLocalhostBuyerDomain,
550                         CUSTOM_AUDIENCE_SEQ_2,
551                         BIDS_FOR_BUYER_2,
552                         AD_COST_2.getAdCost());
553 
554         joinCustomAudienceAndAssertSuccess(customAudience1);
555         joinCustomAudienceAndAssertSuccess(customAudience2);
556 
557         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
558 
559         setupOverridesAndAssertSuccess(
560                 customAudience1, customAudience2, biddingLogicJs, decisionLogicJs);
561 
562         // Run Ad Selection
563         AdSelectionTestCallback resultsCallback =
564                 invokeRunAdSelection(
565                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
566 
567         assertTrue(resultsCallback.mIsSuccess);
568         long resultSelectionId = resultsCallback.mAdSelectionResponse.getAdSelectionId();
569         assertTrue(mAdSelectionEntryDao.doesAdSelectionIdExist(resultSelectionId));
570         assertEquals(
571                 CommonFixture.getUri(
572                         mLocalhostBuyerDomain.getAuthority(),
573                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad3"),
574                 resultsCallback.mAdSelectionResponse.getRenderUri());
575 
576         reportImpressionAndAssertSuccess(resultsCallback.mAdSelectionResponse.getAdSelectionId());
577         mockWebServerRule.verifyMockServerRequests(
578                 server, 0, ImmutableList.of(), mRequestMatcherPrefixMatch);
579     }
580 
581     @Test
testFledgeFlowSuccessWithDevOverridesWithAdCostCpcBillingDisabled()582     public void testFledgeFlowSuccessWithDevOverridesWithAdCostCpcBillingDisabled()
583             throws Exception {
584         // Re init with cpc billing enabled
585         initClients(false, false, false, false, false, false);
586 
587         setupConsentGivenStubs();
588 
589         setupAdSelectionConfig();
590 
591         String decisionLogicJs = getDecisionLogicJs();
592         String biddingLogicJs = getBiddingLogicJsWithAdCost();
593 
594         MockWebServer server =
595                 mockWebServerRule.startMockWebServer(
596                         request -> new MockResponse().setResponseCode(404));
597 
598         when(mDevContextFilterMock.createDevContext())
599                 .thenReturn(
600                         DevContext.builder()
601                                 .setDevOptionsEnabled(true)
602                                 .setCallingAppPackageName(CommonFixture.TEST_PACKAGE_NAME)
603                                 .build());
604 
605         CustomAudience customAudience1 =
606                 createCustomAudienceWithAdCost(
607                         mLocalhostBuyerDomain,
608                         CUSTOM_AUDIENCE_SEQ_1,
609                         BIDS_FOR_BUYER_1,
610                         AD_COST_1.getAdCost());
611 
612         CustomAudience customAudience2 =
613                 createCustomAudienceWithAdCost(
614                         mLocalhostBuyerDomain,
615                         CUSTOM_AUDIENCE_SEQ_2,
616                         BIDS_FOR_BUYER_2,
617                         AD_COST_2.getAdCost());
618 
619         joinCustomAudienceAndAssertSuccess(customAudience1);
620         joinCustomAudienceAndAssertSuccess(customAudience2);
621 
622         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
623 
624         setupOverridesAndAssertSuccess(
625                 customAudience1, customAudience2, biddingLogicJs, decisionLogicJs);
626 
627         // Run Ad Selection
628         AdSelectionTestCallback resultsCallback =
629                 invokeRunAdSelection(
630                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
631 
632         assertTrue(resultsCallback.mIsSuccess);
633         long resultSelectionId = resultsCallback.mAdSelectionResponse.getAdSelectionId();
634         assertTrue(mAdSelectionEntryDao.doesAdSelectionIdExist(resultSelectionId));
635         assertEquals(
636                 CommonFixture.getUri(
637                         mLocalhostBuyerDomain.getAuthority(),
638                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad3"),
639                 resultsCallback.mAdSelectionResponse.getRenderUri());
640 
641         reportImpressionAndAssertSuccess(resultsCallback.mAdSelectionResponse.getAdSelectionId());
642         mockWebServerRule.verifyMockServerRequests(
643                 server, 0, ImmutableList.of(), mRequestMatcherPrefixMatch);
644     }
645 
646     @Test
testFledgeFlowSuccessWithMockServerReportsAdCostCpcBillingEnabled()647     public void testFledgeFlowSuccessWithMockServerReportsAdCostCpcBillingEnabled()
648             throws Exception {
649         // Re init with cpc billing enabled
650         initClients(false, true, true, false, false, false);
651         doReturn(AdServicesApiConsent.GIVEN)
652                 .when(mConsentManagerMock)
653                 .getConsent(AdServicesApiType.FLEDGE);
654         doReturn(false)
655                 .when(mConsentManagerMock)
656                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
657 
658         setupAdSelectionConfig();
659         String decisionLogicJs = getDecisionLogicWithBeacons();
660         String biddingLogicJs = getBiddingLogicWithBeaconsWithAdCost();
661 
662         CustomAudience customAudience1 =
663                 createCustomAudienceWithAdCost(
664                         mLocalhostBuyerDomain,
665                         CUSTOM_AUDIENCE_SEQ_1,
666                         BIDS_FOR_BUYER_1,
667                         AD_COST_1.getAdCost());
668 
669         CustomAudience customAudience2 =
670                 createCustomAudienceWithAdCost(
671                         mLocalhostBuyerDomain,
672                         CUSTOM_AUDIENCE_SEQ_2,
673                         BIDS_FOR_BUYER_2,
674                         AD_COST_2.getAdCost());
675 
676         // We add permits to the semaphores when the MWS is called and remove them in the asserts
677         Semaphore impressionReportingSemaphore = new Semaphore(0);
678         Semaphore interactionReportingSemaphore = new Semaphore(0);
679 
680         MockWebServer server =
681                 getMockWebServer(
682                         decisionLogicJs,
683                         biddingLogicJs,
684                         impressionReportingSemaphore,
685                         interactionReportingSemaphore,
686                         false);
687 
688         joinCustomAudienceAndAssertSuccess(customAudience1);
689         joinCustomAudienceAndAssertSuccess(customAudience2);
690 
691         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
692 
693         selectAdsAndReport(
694                 CommonFixture.getUri(
695                         mLocalhostBuyerDomain.getAuthority(),
696                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad3"),
697                 impressionReportingSemaphore,
698                 interactionReportingSemaphore);
699         verifyStandardServerRequests(server);
700     }
701 
702     @Test
testFledgeFlowSuccessWithMockServerWithDataVersionHeaderEnabled()703     public void testFledgeFlowSuccessWithMockServerWithDataVersionHeaderEnabled() throws Exception {
704         // Re init with data version header enabled
705         initClients(false, true, false, true, false, false);
706         doReturn(AdServicesApiConsent.GIVEN)
707                 .when(mConsentManagerMock)
708                 .getConsent(AdServicesApiType.FLEDGE);
709         doReturn(false)
710                 .when(mConsentManagerMock)
711                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
712 
713         setupAdSelectionConfigWithDataVersionHeader();
714 
715         String decisionLogicJs = getDecisionLogicWithDataVersion();
716         String biddingLogicJs = getBiddingLogicWithDataVersion();
717 
718         CustomAudience customAudience1 =
719                 createCustomAudienceWithDataVersion(
720                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
721 
722         CustomAudience customAudience2 =
723                 createCustomAudienceWithDataVersion(
724                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, BIDS_FOR_BUYER_2);
725 
726         // We add permits to the semaphores when the MWS is called and remove them in the asserts
727         Semaphore impressionReportingSemaphore = new Semaphore(0);
728         Semaphore interactionReportingSemaphore = new Semaphore(0);
729 
730         MockWebServer server =
731                 getMockWebServer(
732                         decisionLogicJs,
733                         biddingLogicJs,
734                         impressionReportingSemaphore,
735                         interactionReportingSemaphore,
736                         false);
737 
738         joinCustomAudienceAndAssertSuccess(customAudience1);
739         joinCustomAudienceAndAssertSuccess(customAudience2);
740 
741         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
742 
743         AdSelectionTestCallback resultsCallback =
744                 invokeRunAdSelection(
745                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
746 
747         Uri expectedWinningrUi =
748                 CommonFixture.getUri(
749                         mLocalhostBuyerDomain.getAuthority(),
750                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad3");
751 
752         assertTrue(resultsCallback.mIsSuccess);
753         long resultSelectionId = resultsCallback.mAdSelectionResponse.getAdSelectionId();
754         assertTrue(mAdSelectionEntryDao.doesAdSelectionIdExist(resultSelectionId));
755         assertEquals(expectedWinningrUi, resultsCallback.mAdSelectionResponse.getRenderUri());
756 
757         reportImpressionAndAssertSuccess(resultSelectionId);
758 
759         assertTrue(impressionReportingSemaphore.tryAcquire(2, 10, TimeUnit.SECONDS));
760         assertEquals(
761                 "Extra calls made to MockWebServer",
762                 0,
763                 impressionReportingSemaphore.availablePermits());
764 
765         // interaction should not happen, so there should be no permits
766         assertEquals(
767                 "Extra calls made to MockWebServer",
768                 0,
769                 interactionReportingSemaphore.availablePermits());
770 
771         mockWebServerRule.verifyMockServerRequests(
772                 server,
773                 8,
774                 ImmutableList.of(
775                         SELLER_DECISION_LOGIC_URI_PATH,
776                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1,
777                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_2,
778                         BUYER_TRUSTED_SIGNAL_URI_PATH_WITH_DATA_VERSION,
779                         SELLER_TRUSTED_SIGNAL_URI_PATH_WITH_DATA_VERSION
780                                 + SELLER_TRUSTED_SIGNAL_PARAMS,
781                         SELLER_REPORTING_PATH + "?dataVersion=" + DATA_VERSION_2,
782                         BUYER_REPORTING_PATH + "?dataVersion=" + DATA_VERSION_1),
783                 mRequestMatcherPrefixMatch);
784     }
785 
786     @Test
testFledgeFlowSuccessWithMockServerWithDataVersionHeaderDisabled()787     public void testFledgeFlowSuccessWithMockServerWithDataVersionHeaderDisabled()
788             throws Exception {
789         // Re init with data version header disabled
790         initClients(false, true, false, false, false, false);
791         doReturn(AdServicesApiConsent.GIVEN)
792                 .when(mConsentManagerMock)
793                 .getConsent(AdServicesApiType.FLEDGE);
794         doReturn(false)
795                 .when(mConsentManagerMock)
796                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
797 
798         setupAdSelectionConfigWithDataVersionHeader();
799 
800         String decisionLogicJs = getDecisionLogicJs();
801         String biddingLogicJs = getBiddingLogicJs();
802 
803         CustomAudience customAudience1 =
804                 createCustomAudienceWithDataVersion(
805                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
806 
807         CustomAudience customAudience2 =
808                 createCustomAudienceWithDataVersion(
809                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, BIDS_FOR_BUYER_2);
810 
811         // We add permits to the semaphores when the MWS is called and remove them in the asserts
812         Semaphore impressionReportingSemaphore = new Semaphore(0);
813         Semaphore interactionReportingSemaphore = new Semaphore(0);
814 
815         MockWebServer server =
816                 getMockWebServer(
817                         decisionLogicJs,
818                         biddingLogicJs,
819                         impressionReportingSemaphore,
820                         interactionReportingSemaphore,
821                         false);
822 
823         joinCustomAudienceAndAssertSuccess(customAudience1);
824         joinCustomAudienceAndAssertSuccess(customAudience2);
825 
826         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
827 
828         AdSelectionTestCallback resultsCallback =
829                 invokeRunAdSelection(
830                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
831 
832         Uri expectedWinningrUi =
833                 CommonFixture.getUri(
834                         mLocalhostBuyerDomain.getAuthority(),
835                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad3");
836 
837         assertTrue(resultsCallback.mIsSuccess);
838         long resultSelectionId = resultsCallback.mAdSelectionResponse.getAdSelectionId();
839         assertTrue(mAdSelectionEntryDao.doesAdSelectionIdExist(resultSelectionId));
840         assertEquals(expectedWinningrUi, resultsCallback.mAdSelectionResponse.getRenderUri());
841 
842         reportImpressionAndAssertSuccess(resultSelectionId);
843 
844         assertTrue(impressionReportingSemaphore.tryAcquire(2, 10, TimeUnit.SECONDS));
845         assertEquals(
846                 "Extra calls made to MockWebServer",
847                 0,
848                 impressionReportingSemaphore.availablePermits());
849 
850         // interaction should not happen, so there should be no permits
851         assertEquals(
852                 "Extra calls made to MockWebServer",
853                 0,
854                 interactionReportingSemaphore.availablePermits());
855 
856         // Verify requests without data version header are made
857         mockWebServerRule.verifyMockServerRequests(
858                 server,
859                 8,
860                 ImmutableList.of(
861                         SELLER_DECISION_LOGIC_URI_PATH,
862                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1,
863                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_2,
864                         BUYER_TRUSTED_SIGNAL_URI_PATH_WITH_DATA_VERSION,
865                         SELLER_TRUSTED_SIGNAL_URI_PATH_WITH_DATA_VERSION
866                                 + SELLER_TRUSTED_SIGNAL_PARAMS,
867                         SELLER_REPORTING_PATH,
868                         BUYER_REPORTING_PATH),
869                 mRequestMatcherPrefixMatch);
870     }
871 
872     @Test
testFledgeFlowSuccessWithMockServerReportsAdCostCpcBillingDisabled()873     public void testFledgeFlowSuccessWithMockServerReportsAdCostCpcBillingDisabled()
874             throws Exception {
875         // Re init with cpc billing enabled
876         initClients(false, true, false, false, false, false);
877         doReturn(AdServicesApiConsent.GIVEN)
878                 .when(mConsentManagerMock)
879                 .getConsent(AdServicesApiType.FLEDGE);
880         doReturn(false)
881                 .when(mConsentManagerMock)
882                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
883 
884         setupAdSelectionConfig();
885         String decisionLogicJs = getDecisionLogicWithBeacons();
886         String biddingLogicJs = getBiddingLogicWithBeaconsWithAdCost();
887 
888         CustomAudience customAudience1 =
889                 createCustomAudienceWithAdCost(
890                         mLocalhostBuyerDomain,
891                         CUSTOM_AUDIENCE_SEQ_1,
892                         BIDS_FOR_BUYER_1,
893                         AD_COST_1.getAdCost());
894 
895         CustomAudience customAudience2 =
896                 createCustomAudienceWithAdCost(
897                         mLocalhostBuyerDomain,
898                         CUSTOM_AUDIENCE_SEQ_2,
899                         BIDS_FOR_BUYER_2,
900                         AD_COST_2.getAdCost());
901 
902         // We add permits to the semaphores when the MWS is called and remove them in the asserts
903         Semaphore impressionReportingSemaphore = new Semaphore(0);
904         Semaphore interactionReportingSemaphore = new Semaphore(0);
905 
906         MockWebServer server =
907                 getMockWebServer(
908                         decisionLogicJs,
909                         biddingLogicJs,
910                         impressionReportingSemaphore,
911                         interactionReportingSemaphore,
912                         false);
913 
914         joinCustomAudienceAndAssertSuccess(customAudience1);
915         joinCustomAudienceAndAssertSuccess(customAudience2);
916 
917         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
918 
919         selectAdsAndReport(
920                 CommonFixture.getUri(
921                         mLocalhostBuyerDomain.getAuthority(),
922                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad3"),
923                 impressionReportingSemaphore,
924                 interactionReportingSemaphore);
925         verifyStandardServerRequests(server);
926     }
927 
928     @FlakyTest(bugId = 301009903)
929     @Test
testFledgeFlowSuccessWithDevOverridesRegisterAdBeaconEnabled()930     public void testFledgeFlowSuccessWithDevOverridesRegisterAdBeaconEnabled() throws Exception {
931         setupConsentGivenStubs();
932 
933         setupAdSelectionConfig();
934         String decisionLogicJs = getDecisionLogicWithBeacons();
935         String biddingLogicJs = getBiddingLogicWithBeacons();
936 
937         MockWebServer server =
938                 mockWebServerRule.startMockWebServer(
939                         request -> new MockResponse().setResponseCode(404));
940 
941         when(mDevContextFilterMock.createDevContext())
942                 .thenReturn(
943                         DevContext.builder()
944                                 .setDevOptionsEnabled(true)
945                                 .setCallingAppPackageName(CommonFixture.TEST_PACKAGE_NAME)
946                                 .build());
947 
948         CustomAudience customAudience1 =
949                 createCustomAudience(
950                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
951 
952         CustomAudience customAudience2 =
953                 createCustomAudience(
954                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, BIDS_FOR_BUYER_2);
955 
956         joinCustomAudienceAndAssertSuccess(customAudience1);
957         joinCustomAudienceAndAssertSuccess(customAudience2);
958 
959         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
960 
961         setupOverridesAndAssertSuccess(
962                 customAudience1, customAudience2, biddingLogicJs, decisionLogicJs);
963 
964         // Run Ad Selection
965         AdSelectionTestCallback resultsCallback =
966                 invokeRunAdSelection(
967                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
968 
969         assertTrue(resultsCallback.mIsSuccess);
970         long resultSelectionId = resultsCallback.mAdSelectionResponse.getAdSelectionId();
971         assertTrue(mAdSelectionEntryDao.doesAdSelectionIdExist(resultSelectionId));
972         assertEquals(
973                 CommonFixture.getUri(
974                         mLocalhostBuyerDomain.getAuthority(),
975                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad3"),
976                 resultsCallback.mAdSelectionResponse.getRenderUri());
977 
978         reportImpressionAndAssertSuccess(resultsCallback.mAdSelectionResponse.getAdSelectionId());
979 
980         reportInteractionAndAssertSuccess(resultsCallback);
981 
982         mockWebServerRule.verifyMockServerRequests(
983                 server, 0, ImmutableList.of(), mRequestMatcherPrefixMatch);
984     }
985 
986     @Test
testFledgeFlowSuccessWithDevOverridesGaUxEnabled()987     public void testFledgeFlowSuccessWithDevOverridesGaUxEnabled() throws Exception {
988         initClients(true, true, false, false, false, false);
989         doReturn(AdServicesApiConsent.GIVEN)
990                 .when(mConsentManagerMock)
991                 .getConsent(AdServicesApiType.FLEDGE);
992         doReturn(false).when(mConsentManagerMock).isFledgeConsentRevokedForApp(any());
993         doReturn(false)
994                 .when(mConsentManagerMock)
995                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
996 
997         setupAdSelectionConfig();
998         String decisionLogicJs = getDecisionLogicWithBeacons();
999         String biddingLogicJs = getBiddingLogicWithBeacons();
1000 
1001         MockWebServer server =
1002                 mockWebServerRule.startMockWebServer(
1003                         request -> new MockResponse().setResponseCode(404));
1004 
1005         when(mDevContextFilterMock.createDevContext())
1006                 .thenReturn(
1007                         DevContext.builder()
1008                                 .setDevOptionsEnabled(true)
1009                                 .setCallingAppPackageName(CommonFixture.TEST_PACKAGE_NAME)
1010                                 .build());
1011 
1012         CustomAudience customAudience1 =
1013                 createCustomAudience(
1014                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
1015 
1016         CustomAudience customAudience2 =
1017                 createCustomAudience(
1018                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, BIDS_FOR_BUYER_2);
1019 
1020         // Join first custom audience
1021         joinCustomAudienceAndAssertSuccess(customAudience1);
1022 
1023         // Join second custom audience
1024         joinCustomAudienceAndAssertSuccess(customAudience2);
1025 
1026         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
1027 
1028         setupOverridesAndAssertSuccess(
1029                 customAudience1, customAudience2, biddingLogicJs, decisionLogicJs);
1030 
1031         // Run Ad Selection
1032         AdSelectionTestCallback resultsCallback =
1033                 invokeRunAdSelection(
1034                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
1035 
1036         assertTrue(resultsCallback.mIsSuccess);
1037         long resultSelectionId = resultsCallback.mAdSelectionResponse.getAdSelectionId();
1038         assertTrue(mAdSelectionEntryDao.doesAdSelectionIdExist(resultSelectionId));
1039         assertEquals(
1040                 CommonFixture.getUri(
1041                         mLocalhostBuyerDomain.getAuthority(),
1042                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad3"),
1043                 resultsCallback.mAdSelectionResponse.getRenderUri());
1044 
1045         reportImpressionAndAssertSuccess(resultsCallback.mAdSelectionResponse.getAdSelectionId());
1046 
1047         reportInteractionAndAssertSuccess(resultsCallback);
1048 
1049         mockWebServerRule.verifyMockServerRequests(
1050                 server, 0, ImmutableList.of(), mRequestMatcherPrefixMatch);
1051     }
1052 
1053     @FlakyTest(bugId = 301016443)
1054     @Test
testFledgeFlowSuccessWithDevOverridesWithRevokedUserConsentForApp()1055     public void testFledgeFlowSuccessWithDevOverridesWithRevokedUserConsentForApp()
1056             throws Exception {
1057         doReturn(AdServicesApiConsent.GIVEN)
1058                 .when(mConsentManagerMock)
1059                 .getConsent(AdServicesApiType.FLEDGE);
1060         // Allow the first calls to succeed so that we can verify the rest of the flow works
1061         when(mConsentManagerMock.isFledgeConsentRevokedForApp(any()))
1062                 .thenReturn(false)
1063                 .thenReturn(true);
1064         when(mConsentManagerMock.isFledgeConsentRevokedForAppAfterSettingFledgeUse(any()))
1065                 .thenReturn(false)
1066                 .thenReturn(true);
1067 
1068         setupAdSelectionConfig();
1069         String decisionLogicJs = getDecisionLogicWithBeacons();
1070         String biddingLogicJs = getBiddingLogicWithBeacons();
1071 
1072         MockWebServer server =
1073                 mockWebServerRule.startMockWebServer(
1074                         request -> new MockResponse().setResponseCode(404));
1075 
1076         when(mDevContextFilterMock.createDevContext())
1077                 .thenReturn(
1078                         DevContext.builder()
1079                                 .setDevOptionsEnabled(true)
1080                                 .setCallingAppPackageName(CommonFixture.TEST_PACKAGE_NAME)
1081                                 .build());
1082 
1083         CustomAudience customAudience1 =
1084                 createCustomAudience(
1085                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
1086 
1087         CustomAudience customAudience2 =
1088                 createCustomAudience(
1089                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, BIDS_FOR_BUYER_2);
1090 
1091         joinCustomAudienceAndAssertSuccess(customAudience1);
1092         joinCustomAudienceAndAssertSuccess(customAudience2);
1093 
1094         setupOverridesAndAssertSuccess(
1095                 customAudience1, customAudience2, biddingLogicJs, decisionLogicJs);
1096 
1097         // Run Ad Selection
1098         AdSelectionTestCallback resultsCallback =
1099                 invokeRunAdSelection(
1100                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
1101 
1102         // Verify that CA1/ad2 won because CA2 was not joined due to user consent
1103         assertTrue(resultsCallback.mIsSuccess);
1104         long resultSelectionId = resultsCallback.mAdSelectionResponse.getAdSelectionId();
1105         assertTrue(mAdSelectionEntryDao.doesAdSelectionIdExist(resultSelectionId));
1106         assertEquals(
1107                 CommonFixture.getUri(
1108                         mLocalhostBuyerDomain.getAuthority(),
1109                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_1 + "/ad2"),
1110                 resultsCallback.mAdSelectionResponse.getRenderUri());
1111 
1112         reportImpressionAndAssertSuccess(resultsCallback.mAdSelectionResponse.getAdSelectionId());
1113 
1114         reportInteractionAndAssertSuccess(resultsCallback);
1115 
1116         mockWebServerRule.verifyMockServerRequests(
1117                 server, 0, ImmutableList.of(), mRequestMatcherPrefixMatch);
1118     }
1119 
1120     @Test
testFledgeFlowSuccessWithDevOverridesWithRevokedUserConsentForAppGaUxEnabled()1121     public void testFledgeFlowSuccessWithDevOverridesWithRevokedUserConsentForAppGaUxEnabled()
1122             throws Exception {
1123         initClients(true, true, false, false, false, false);
1124         doReturn(AdServicesApiConsent.GIVEN)
1125                 .when(mConsentManagerMock)
1126                 .getConsent(AdServicesApiType.FLEDGE);
1127         // Allow the first calls to succeed so that we can verify the rest of the flow works
1128         when(mConsentManagerMock.isFledgeConsentRevokedForApp(any()))
1129                 .thenReturn(false)
1130                 .thenReturn(true);
1131         when(mConsentManagerMock.isFledgeConsentRevokedForAppAfterSettingFledgeUse(any()))
1132                 .thenReturn(false)
1133                 .thenReturn(true);
1134 
1135         setupAdSelectionConfig();
1136         String decisionLogicJs = getDecisionLogicWithBeacons();
1137         String biddingLogicJs = getBiddingLogicWithBeacons();
1138 
1139         MockWebServer server =
1140                 mockWebServerRule.startMockWebServer(
1141                         request -> new MockResponse().setResponseCode(404));
1142 
1143         when(mDevContextFilterMock.createDevContext())
1144                 .thenReturn(
1145                         DevContext.builder()
1146                                 .setDevOptionsEnabled(true)
1147                                 .setCallingAppPackageName(CommonFixture.TEST_PACKAGE_NAME)
1148                                 .build());
1149 
1150         CustomAudience customAudience1 =
1151                 createCustomAudience(
1152                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
1153 
1154         CustomAudience customAudience2 =
1155                 createCustomAudience(
1156                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, BIDS_FOR_BUYER_2);
1157 
1158         joinCustomAudienceAndAssertSuccess(customAudience1);
1159         joinCustomAudienceAndAssertSuccess(customAudience2);
1160 
1161         setupOverridesAndAssertSuccess(
1162                 customAudience1, customAudience2, biddingLogicJs, decisionLogicJs);
1163 
1164         // Run Ad Selection
1165         AdSelectionTestCallback resultsCallback =
1166                 invokeRunAdSelection(
1167                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
1168 
1169         // Verify that CA1/ad2 won because CA2 was not joined due to user consent
1170         assertTrue(resultsCallback.mIsSuccess);
1171         long resultSelectionId = resultsCallback.mAdSelectionResponse.getAdSelectionId();
1172         assertTrue(mAdSelectionEntryDao.doesAdSelectionIdExist(resultSelectionId));
1173         assertEquals(
1174                 CommonFixture.getUri(
1175                         mLocalhostBuyerDomain.getAuthority(),
1176                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_1 + "/ad2"),
1177                 resultsCallback.mAdSelectionResponse.getRenderUri());
1178 
1179         reportImpressionAndAssertSuccess(resultsCallback.mAdSelectionResponse.getAdSelectionId());
1180 
1181         reportInteractionAndAssertSuccess(resultsCallback);
1182 
1183         mockWebServerRule.verifyMockServerRequests(
1184                 server, 0, ImmutableList.of(), mRequestMatcherPrefixMatch);
1185     }
1186 
1187     @Test
testFledgeFlowFailsWithMismatchedPackageNamesReportImpression()1188     public void testFledgeFlowFailsWithMismatchedPackageNamesReportImpression() throws Exception {
1189         setupConsentGivenStubs();
1190 
1191         String otherPackageName = CommonFixture.TEST_PACKAGE_NAME + "different_package";
1192 
1193         // Mocking PackageManager so it passes package name validation, but fails impression
1194         // reporting
1195         // due to package mismatch
1196         PackageManager packageManagerMock = mock(PackageManager.class);
1197         when(mSpyContext.getPackageManager()).thenReturn(packageManagerMock);
1198         when(packageManagerMock.getPackagesForUid(Process.myUid()))
1199                 .thenReturn(new String[] {CommonFixture.TEST_PACKAGE_NAME, otherPackageName});
1200 
1201         // Reinitializing service so mocking takes effect
1202         // Create an instance of AdSelection Service with real dependencies
1203         mAdSelectionService =
1204                 new AdSelectionServiceImpl(
1205                         mAdSelectionEntryDao,
1206                         mAppInstallDao,
1207                         mCustomAudienceDao,
1208                         mEncodedPayloadDao,
1209                         mFrequencyCapDao,
1210                         mEncryptionKeyDao,
1211                         mEnrollmentDao,
1212                         mAdServicesHttpsClient,
1213                         mDevContextFilterMock,
1214                         mLightweightExecutorService,
1215                         mBackgroundExecutorService,
1216                         mScheduledExecutor,
1217                         mSpyContext,
1218                         mAdServicesLoggerMock,
1219                         DEFAULT_FLAGS,
1220                         CallingAppUidSupplierProcessImpl.create(),
1221                         mFledgeAuthorizationFilterMock,
1222                         mAdSelectionServiceFilterMock,
1223                         mAdFilteringFeatureFactory,
1224                         mConsentManagerMock,
1225                         mMultiCloudSupportStrategy,
1226                         mAdSelectionDebugReportDao,
1227                         mAdIdFetcher,
1228                         mUnusedKAnonSignJoinFactory,
1229                         false,
1230                         mRetryStrategyFactory,
1231                         mConsentedDebugConfigurationGeneratorFactory,
1232                         mEgressConfigurationGenerator,
1233                         CONSOLE_MESSAGE_IN_LOGS_ENABLED);
1234 
1235         mAdSelectionConfig =
1236                 AdSelectionConfigFixture.anAdSelectionConfigBuilder()
1237                         .setCustomAudienceBuyers(
1238                                 ImmutableList.of(
1239                                         AdTechIdentifier.fromString(BUYER_DOMAIN_1.getHost()),
1240                                         AdTechIdentifier.fromString(BUYER_DOMAIN_2.getHost())))
1241                         .setSeller(
1242                                 AdTechIdentifier.fromString(
1243                                         mockWebServerRule
1244                                                 .uriForPath(SELLER_DECISION_LOGIC_URI_PATH)
1245                                                 .getHost()))
1246                         .setDecisionLogicUri(
1247                                 mockWebServerRule.uriForPath(SELLER_DECISION_LOGIC_URI_PATH))
1248                         .setTrustedScoringSignalsUri(
1249                                 mockWebServerRule.uriForPath(SELLER_TRUSTED_SIGNAL_URI_PATH))
1250                         .build();
1251 
1252         AdSelectionConfig adSelectionConfigWithDifferentCallerPackageName =
1253                 AdSelectionConfigFixture.anAdSelectionConfigBuilder()
1254                         .setCustomAudienceBuyers(
1255                                 ImmutableList.of(
1256                                         AdTechIdentifier.fromString(BUYER_DOMAIN_1.getHost()),
1257                                         AdTechIdentifier.fromString(BUYER_DOMAIN_2.getHost())))
1258                         .setSeller(
1259                                 AdTechIdentifier.fromString(
1260                                         mockWebServerRule
1261                                                 .uriForPath(SELLER_DECISION_LOGIC_URI_PATH)
1262                                                 .getHost()))
1263                         .setDecisionLogicUri(
1264                                 mockWebServerRule.uriForPath(SELLER_DECISION_LOGIC_URI_PATH))
1265                         .setTrustedScoringSignalsUri(
1266                                 mockWebServerRule.uriForPath(SELLER_TRUSTED_SIGNAL_URI_PATH))
1267                         .build();
1268 
1269         String decisionLogicJs =
1270                 "function scoreAd(ad, bid, auction_config, seller_signals,"
1271                         + " trusted_scoring_signals, contextual_signal, user_signal,"
1272                         + " custom_audience_signal) { \n"
1273                         + "  return {'status': 0, 'score': bid };\n"
1274                         + "}\n"
1275                         + "function reportResult(ad_selection_config, render_uri, bid,"
1276                         + " contextual_signals) { \n"
1277                         + " return {'status': 0, 'results': {'signals_for_buyer':"
1278                         + " '{\"signals_for_buyer\":1}', 'reporting_uri': '"
1279                         + SELLER_REPORTING_PATH
1280                         + "' } };\n"
1281                         + "}";
1282         String biddingLogicJs =
1283                 "function generateBid(ad, auction_signals, per_buyer_signals,"
1284                     + " trusted_bidding_signals, contextual_signals, custom_audience_signals) { \n"
1285                     + "  return {'status': 0, 'ad': ad, 'bid': ad.metadata.result };\n"
1286                     + "}\n"
1287                     + "function reportWin(ad_selection_signals, per_buyer_signals,"
1288                     + " signals_for_buyer, contextual_signals, custom_audience_signals) { \n"
1289                     + " return {'status': 0, 'results': {'reporting_uri': '"
1290                         + BUYER_REPORTING_PATH
1291                         + "' } };\n"
1292                         + "}";
1293 
1294         mockWebServerRule.startMockWebServer(request -> new MockResponse().setResponseCode(404));
1295 
1296         when(mDevContextFilterMock.createDevContext())
1297                 .thenReturn(
1298                         DevContext.builder()
1299                                 .setDevOptionsEnabled(true)
1300                                 .setCallingAppPackageName(CommonFixture.TEST_PACKAGE_NAME)
1301                                 .build());
1302 
1303         CustomAudience customAudience1 = createCustomAudience(BUYER_DOMAIN_1, BIDS_FOR_BUYER_1);
1304 
1305         CustomAudience customAudience2 = createCustomAudience(BUYER_DOMAIN_2, BIDS_FOR_BUYER_2);
1306 
1307         joinCustomAudienceAndAssertSuccess(customAudience1);
1308         joinCustomAudienceAndAssertSuccess(customAudience2);
1309 
1310         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
1311 
1312         setupOverridesAndAssertSuccess(
1313                 customAudience1, customAudience2, biddingLogicJs, decisionLogicJs);
1314 
1315         // Run Ad Selection
1316         AdSelectionTestCallback resultsCallback =
1317                 invokeRunAdSelection(
1318                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
1319 
1320         assertTrue(resultsCallback.mIsSuccess);
1321         long resultSelectionId = resultsCallback.mAdSelectionResponse.getAdSelectionId();
1322         assertTrue(mAdSelectionEntryDao.doesAdSelectionIdExist(resultSelectionId));
1323         assertEquals(
1324                 CommonFixture.getUri(BUYER_DOMAIN_2.getHost(), AD_URI_PREFIX + "/ad3"),
1325                 resultsCallback.mAdSelectionResponse.getRenderUri());
1326 
1327         // Run Report Impression with different package name
1328         ReportImpressionInput input =
1329                 new ReportImpressionInput.Builder()
1330                         .setAdSelectionConfig(adSelectionConfigWithDifferentCallerPackageName)
1331                         .setAdSelectionId(resultsCallback.mAdSelectionResponse.getAdSelectionId())
1332                         .setCallerPackageName(otherPackageName)
1333                         .build();
1334 
1335         ReportImpressionTestCallback reportImpressionTestCallback =
1336                 callReportImpression(mAdSelectionService, input);
1337 
1338         assertFalse(reportImpressionTestCallback.mIsSuccess);
1339         assertEquals(
1340                 reportImpressionTestCallback.mFledgeErrorResponse.getStatusCode(),
1341                 AdServicesStatusUtils.STATUS_INVALID_ARGUMENT);
1342         assertEquals(
1343                 reportImpressionTestCallback.mFledgeErrorResponse.getErrorMessage(),
1344                 CALLER_PACKAGE_NAME_MISMATCH);
1345 
1346         // Run Report Interaction, should fail silently due to no registered beacons
1347         reportInteractionAndAssertSuccess(resultsCallback);
1348     }
1349 
1350     @Test
testFledgeFlowFailsWithWrongPackageNameReportInteraction()1351     public void testFledgeFlowFailsWithWrongPackageNameReportInteraction() throws Exception {
1352         setupConsentGivenStubs();
1353 
1354         String otherPackageName = CommonFixture.TEST_PACKAGE_NAME + "different_package";
1355 
1356         // Mocking PackageManager so it passes package name validation, but fails in interaction
1357         // reporting
1358         // due to package mismatch
1359         PackageManager packageManagerMock = mock(PackageManager.class);
1360         when(mSpyContext.getPackageManager()).thenReturn(packageManagerMock);
1361         when(packageManagerMock.getPackagesForUid(Process.myUid()))
1362                 .thenReturn(new String[] {CommonFixture.TEST_PACKAGE_NAME, otherPackageName});
1363 
1364         // Reinitializing service so mocking takes effect
1365         // Create an instance of AdSelection Service with real dependencies
1366         mAdSelectionService =
1367                 new AdSelectionServiceImpl(
1368                         mAdSelectionEntryDao,
1369                         mAppInstallDao,
1370                         mCustomAudienceDao,
1371                         mEncodedPayloadDao,
1372                         mFrequencyCapDao,
1373                         mEncryptionKeyDao,
1374                         mEnrollmentDao,
1375                         mAdServicesHttpsClient,
1376                         mDevContextFilterMock,
1377                         mLightweightExecutorService,
1378                         mBackgroundExecutorService,
1379                         mScheduledExecutor,
1380                         mSpyContext,
1381                         mAdServicesLoggerMock,
1382                         DEFAULT_FLAGS,
1383                         CallingAppUidSupplierProcessImpl.create(),
1384                         mFledgeAuthorizationFilterMock,
1385                         mAdSelectionServiceFilterMock,
1386                         mAdFilteringFeatureFactory,
1387                         mConsentManagerMock,
1388                         mMultiCloudSupportStrategy,
1389                         mAdSelectionDebugReportDao,
1390                         mAdIdFetcher,
1391                         mUnusedKAnonSignJoinFactory,
1392                         false,
1393                         mRetryStrategyFactory,
1394                         mConsentedDebugConfigurationGeneratorFactory,
1395                         mEgressConfigurationGenerator,
1396                         CONSOLE_MESSAGE_IN_LOGS_ENABLED);
1397 
1398         mAdSelectionConfig =
1399                 AdSelectionConfigFixture.anAdSelectionConfigBuilder()
1400                         .setCustomAudienceBuyers(
1401                                 ImmutableList.of(
1402                                         AdTechIdentifier.fromString(BUYER_DOMAIN_1.getHost()),
1403                                         AdTechIdentifier.fromString(BUYER_DOMAIN_2.getHost())))
1404                         .setSeller(
1405                                 AdTechIdentifier.fromString(
1406                                         mockWebServerRule
1407                                                 .uriForPath(SELLER_DECISION_LOGIC_URI_PATH)
1408                                                 .getHost()))
1409                         .setDecisionLogicUri(
1410                                 mockWebServerRule.uriForPath(SELLER_DECISION_LOGIC_URI_PATH))
1411                         .setTrustedScoringSignalsUri(
1412                                 mockWebServerRule.uriForPath(SELLER_TRUSTED_SIGNAL_URI_PATH))
1413                         .build();
1414         String decisionLogicJs = getDecisionLogicWithBeacons();
1415         String biddingLogicJs = getBiddingLogicWithBeacons();
1416 
1417         mockWebServerRule.startMockWebServer(request -> new MockResponse().setResponseCode(404));
1418 
1419         when(mDevContextFilterMock.createDevContext())
1420                 .thenReturn(
1421                         DevContext.builder()
1422                                 .setDevOptionsEnabled(true)
1423                                 .setCallingAppPackageName(CommonFixture.TEST_PACKAGE_NAME)
1424                                 .build());
1425 
1426         CustomAudience customAudience1 = createCustomAudience(BUYER_DOMAIN_1, BIDS_FOR_BUYER_1);
1427 
1428         CustomAudience customAudience2 = createCustomAudience(BUYER_DOMAIN_2, BIDS_FOR_BUYER_2);
1429 
1430         joinCustomAudienceAndAssertSuccess(customAudience1);
1431         joinCustomAudienceAndAssertSuccess(customAudience2);
1432 
1433         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
1434 
1435         setupOverridesAndAssertSuccess(
1436                 customAudience1, customAudience2, biddingLogicJs, decisionLogicJs);
1437 
1438         // Run Ad Selection
1439         AdSelectionTestCallback resultsCallback =
1440                 invokeRunAdSelection(
1441                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
1442 
1443         assertTrue(resultsCallback.mIsSuccess);
1444         long resultSelectionId = resultsCallback.mAdSelectionResponse.getAdSelectionId();
1445         assertTrue(mAdSelectionEntryDao.doesAdSelectionIdExist(resultSelectionId));
1446         assertEquals(
1447                 CommonFixture.getUri(BUYER_DOMAIN_2.getHost(), AD_URI_PREFIX + "/ad3"),
1448                 resultsCallback.mAdSelectionResponse.getRenderUri());
1449 
1450         reportImpressionAndAssertSuccess(resultsCallback.mAdSelectionResponse.getAdSelectionId());
1451 
1452         // Run Report Interaction with different package name
1453         ReportInteractionInput reportInteractionInput =
1454                 new ReportInteractionInput.Builder()
1455                         .setAdSelectionId(resultsCallback.mAdSelectionResponse.getAdSelectionId())
1456                         .setInteractionKey(CLICK_INTERACTION)
1457                         .setInteractionData(INTERACTION_DATA)
1458                         .setCallerPackageName(otherPackageName)
1459                         .setReportingDestinations(BUYER_DESTINATION | SELLER_DESTINATION)
1460                         .build();
1461 
1462         ReportInteractionTestCallback reportInteractionTestCallback =
1463                 callReportInteraction(mAdSelectionService, reportInteractionInput);
1464         assertFalse(reportInteractionTestCallback.mIsSuccess);
1465 
1466         assertEquals(
1467                 reportInteractionTestCallback.mFledgeErrorResponse.getStatusCode(),
1468                 AdServicesStatusUtils.STATUS_INVALID_ARGUMENT);
1469         assertEquals(
1470                 reportInteractionTestCallback.mFledgeErrorResponse.getErrorMessage(),
1471                 EventReporter.NO_MATCH_FOUND_IN_AD_SELECTION_DB);
1472     }
1473 
1474     @Test
1475     @FlakyTest(bugId = 298130832)
testFledgeFlowSuccessWithOneCAWithNegativeBidsWithDevOverrides()1476     public void testFledgeFlowSuccessWithOneCAWithNegativeBidsWithDevOverrides() throws Exception {
1477         setupConsentGivenStubs();
1478 
1479         setupAdSelectionConfig();
1480         String decisionLogicJs = getDecisionLogicWithBeacons();
1481         String biddingLogicJs = getBiddingLogicWithBeacons();
1482 
1483         MockWebServer server =
1484                 mockWebServerRule.startMockWebServer(
1485                         request -> {
1486                             // With overrides the server should not be called
1487                             return new MockResponse().setResponseCode(404);
1488                         });
1489 
1490         when(mDevContextFilterMock.createDevContext())
1491                 .thenReturn(
1492                         DevContext.builder()
1493                                 .setDevOptionsEnabled(true)
1494                                 .setCallingAppPackageName(CommonFixture.TEST_PACKAGE_NAME)
1495                                 .build());
1496 
1497         CustomAudience customAudience1 =
1498                 createCustomAudience(
1499                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
1500 
1501         CustomAudience customAudience2 =
1502                 createCustomAudience(mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, INVALID_BIDS);
1503         joinCustomAudienceAndAssertSuccess(customAudience1);
1504         joinCustomAudienceAndAssertSuccess(customAudience2);
1505 
1506         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
1507 
1508         setupOverridesAndAssertSuccess(
1509                 customAudience1, customAudience2, biddingLogicJs, decisionLogicJs);
1510 
1511         // Run Ad Selection
1512         AdSelectionTestCallback resultsCallback =
1513                 invokeRunAdSelection(
1514                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
1515 
1516         assertTrue(resultsCallback.mIsSuccess);
1517         long resultSelectionId = resultsCallback.mAdSelectionResponse.getAdSelectionId();
1518         assertTrue(mAdSelectionEntryDao.doesAdSelectionIdExist(resultSelectionId));
1519         // Expect that ad from buyer 1 won since buyer 2 had negative bids
1520         assertEquals(
1521                 CommonFixture.getUri(
1522                         mLocalhostBuyerDomain.getAuthority(),
1523                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_1 + "/ad2"),
1524                 resultsCallback.mAdSelectionResponse.getRenderUri());
1525 
1526         reportImpressionAndAssertSuccess(resultsCallback.mAdSelectionResponse.getAdSelectionId());
1527         reportInteractionAndAssertSuccess(resultsCallback);
1528 
1529         mockWebServerRule.verifyMockServerRequests(
1530                 server, 0, ImmutableList.of(), mRequestMatcherPrefixMatch);
1531     }
1532 
1533     @Test
testFledgeFlowSuccessWithOneCAWithNegativeBidsWithDevOverrides_v3BiddingLogic()1534     public void testFledgeFlowSuccessWithOneCAWithNegativeBidsWithDevOverrides_v3BiddingLogic()
1535             throws Exception {
1536         setupConsentGivenStubs();
1537 
1538         setupAdSelectionConfig();
1539         String decisionLogicJs = getDecisionLogicWithBeacons();
1540         String biddingLogicJs =
1541                 "function generateBid(custom_audience, auction_signals, per_buyer_signals,\n"
1542                         + "    trusted_bidding_signals, contextual_signals) {\n"
1543                         + "    const ads = custom_audience.ads;\n"
1544                         + "    let result = null;\n"
1545                         + "    for (const ad of ads) {\n"
1546                         + "        if (!result || ad.metadata.result > result.metadata.result) {\n"
1547                         + "            result = ad;\n"
1548                         + "        }\n"
1549                         + "    }\n"
1550                         + "    return { 'status': 0, 'ad': result, 'bid': result.metadata.result, "
1551                         + "'render': result.render_uri };\n"
1552                         + "}\n"
1553                         + "function reportWin(ad_selection_signals, per_buyer_signals,"
1554                         + " signals_for_buyer ,contextual_signals, custom_audience_signals) {\n"
1555                         + "const beacons = {'click': '"
1556                         + mockWebServerRule.uriForPath(CLICK_BUYER_PATH)
1557                         + "', 'hover': '"
1558                         + mockWebServerRule.uriForPath(HOVER_BUYER_PATH)
1559                         + "'};\n"
1560                         + "registerAdBeacon(beacons);"
1561                         + " return {'status': 0, 'results': {'reporting_uri': '"
1562                         + mockWebServerRule.uriForPath(BUYER_REPORTING_PATH)
1563                         + "' } };\n"
1564                         + "}";
1565 
1566         MockWebServer server =
1567                 mockWebServerRule.startMockWebServer(
1568                         request -> {
1569                             // With overrides the server should not be called
1570                             return new MockResponse().setResponseCode(404);
1571                         });
1572 
1573         when(mDevContextFilterMock.createDevContext())
1574                 .thenReturn(
1575                         DevContext.builder()
1576                                 .setDevOptionsEnabled(true)
1577                                 .setCallingAppPackageName(CommonFixture.TEST_PACKAGE_NAME)
1578                                 .build());
1579 
1580         CustomAudience customAudience1 =
1581                 createCustomAudience(
1582                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
1583 
1584         CustomAudience customAudience2 =
1585                 createCustomAudience(mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, INVALID_BIDS);
1586         joinCustomAudienceAndAssertSuccess(customAudience1);
1587         joinCustomAudienceAndAssertSuccess(customAudience2);
1588 
1589         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
1590 
1591         // Add AdSelection Override
1592         AdSelectionOverrideTestCallback adSelectionOverrideTestCallback =
1593                 callAddAdSelectionOverride(
1594                         mAdSelectionService,
1595                         mAdSelectionConfig,
1596                         decisionLogicJs,
1597                         TRUSTED_SCORING_SIGNALS,
1598                         BUYERS_DECISION_LOGIC);
1599 
1600         assertTrue(adSelectionOverrideTestCallback.mIsSuccess);
1601 
1602         // Add Custom Audience Overrides
1603         CustomAudienceOverrideTestCallback customAudienceOverrideTestCallback1 =
1604                 callAddCustomAudienceOverride(
1605                         CommonFixture.TEST_PACKAGE_NAME,
1606                         customAudience1.getBuyer(),
1607                         customAudience1.getName(),
1608                         biddingLogicJs,
1609                         JsVersionRegister.BUYER_BIDDING_LOGIC_VERSION_VERSION_3,
1610                         TRUSTED_BIDDING_SIGNALS,
1611                         mCustomAudienceService);
1612 
1613         assertTrue(customAudienceOverrideTestCallback1.mIsSuccess);
1614 
1615         CustomAudienceOverrideTestCallback customAudienceOverrideTestCallback2 =
1616                 callAddCustomAudienceOverride(
1617                         CommonFixture.TEST_PACKAGE_NAME,
1618                         customAudience2.getBuyer(),
1619                         customAudience2.getName(),
1620                         biddingLogicJs,
1621                         JsVersionRegister.BUYER_BIDDING_LOGIC_VERSION_VERSION_3,
1622                         TRUSTED_BIDDING_SIGNALS,
1623                         mCustomAudienceService);
1624 
1625         assertTrue(customAudienceOverrideTestCallback2.mIsSuccess);
1626 
1627         // Run Ad Selection
1628         AdSelectionTestCallback resultsCallback =
1629                 invokeRunAdSelection(
1630                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
1631 
1632         assertTrue(resultsCallback.mIsSuccess);
1633         long resultSelectionId = resultsCallback.mAdSelectionResponse.getAdSelectionId();
1634         assertTrue(mAdSelectionEntryDao.doesAdSelectionIdExist(resultSelectionId));
1635         // Expect that ad from buyer 1 won since buyer 2 had negative bids
1636         assertEquals(
1637                 CommonFixture.getUri(
1638                         mLocalhostBuyerDomain.getAuthority(),
1639                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_1 + "/ad2"),
1640                 resultsCallback.mAdSelectionResponse.getRenderUri());
1641 
1642         reportImpressionAndAssertSuccess(resultsCallback.mAdSelectionResponse.getAdSelectionId());
1643 
1644         reportInteractionAndAssertSuccess(resultsCallback);
1645 
1646         mockWebServerRule.verifyMockServerRequests(
1647                 server, 0, ImmutableList.of(), mRequestMatcherPrefixMatch);
1648     }
1649 
1650     @Test
testFledgeFlowFailsWithBothCANegativeBidsWithDevOverrides()1651     public void testFledgeFlowFailsWithBothCANegativeBidsWithDevOverrides() throws Exception {
1652         setupConsentGivenStubs();
1653 
1654         mAdSelectionConfig =
1655                 AdSelectionConfigFixture.anAdSelectionConfigBuilder()
1656                         .setCustomAudienceBuyers(
1657                                 ImmutableList.of(
1658                                         AdTechIdentifier.fromString(BUYER_DOMAIN_1.getHost()),
1659                                         AdTechIdentifier.fromString(BUYER_DOMAIN_2.getHost())))
1660                         .setSeller(
1661                                 AdTechIdentifier.fromString(
1662                                         mockWebServerRule
1663                                                 .uriForPath(SELLER_DECISION_LOGIC_URI_PATH)
1664                                                 .getHost()))
1665                         .setDecisionLogicUri(
1666                                 mockWebServerRule.uriForPath(SELLER_DECISION_LOGIC_URI_PATH))
1667                         .setTrustedScoringSignalsUri(
1668                                 mockWebServerRule.uriForPath(SELLER_TRUSTED_SIGNAL_URI_PATH))
1669                         .build();
1670 
1671         String decisionLogicJs =
1672                 "function scoreAd(ad, bid, auction_config, seller_signals,"
1673                         + " trusted_scoring_signals, contextual_signal, user_signal,"
1674                         + " custom_audience_signal) { \n"
1675                         + "  return {'status': 0, 'score': bid };\n"
1676                         + "}\n"
1677                         + "function reportResult(ad_selection_config, render_uri, bid,"
1678                         + " contextual_signals) { \n"
1679                         + " return {'status': 0, 'results': {'signals_for_buyer':"
1680                         + " '{\"signals_for_buyer\":1}', 'reporting_uri': '"
1681                         + SELLER_REPORTING_PATH
1682                         + "' } };\n"
1683                         + "}";
1684         String biddingLogicJs =
1685                 "function generateBid(ad, auction_signals, per_buyer_signals,"
1686                     + " trusted_bidding_signals, contextual_signals, custom_audience_signals) { \n"
1687                     + "  return {'status': 0, 'ad': ad, 'bid': ad.metadata.result };\n"
1688                     + "}\n"
1689                     + "function reportWin(ad_selection_signals, per_buyer_signals,"
1690                     + " signals_for_buyer, contextual_signals, custom_audience_signals) { \n"
1691                     + " return {'status': 0, 'results': {'reporting_uri': '"
1692                         + BUYER_REPORTING_PATH
1693                         + "' } };\n"
1694                         + "}";
1695 
1696         MockWebServer server =
1697                 mockWebServerRule.startMockWebServer(
1698                         request -> {
1699                             // with overrides the server should not be invoked
1700                             return new MockResponse().setResponseCode(404);
1701                         });
1702 
1703         when(mDevContextFilterMock.createDevContext())
1704                 .thenReturn(
1705                         DevContext.builder()
1706                                 .setDevOptionsEnabled(true)
1707                                 .setCallingAppPackageName(CommonFixture.TEST_PACKAGE_NAME)
1708                                 .build());
1709 
1710         CustomAudience customAudience1 = createCustomAudience(BUYER_DOMAIN_1, INVALID_BIDS);
1711 
1712         CustomAudience customAudience2 = createCustomAudience(BUYER_DOMAIN_2, INVALID_BIDS);
1713 
1714         joinCustomAudienceAndAssertSuccess(customAudience1);
1715         joinCustomAudienceAndAssertSuccess(customAudience2);
1716 
1717         // Add AdSelection Override
1718         AdSelectionOverrideTestCallback adSelectionOverrideTestCallback =
1719                 callAddAdSelectionOverride(
1720                         mAdSelectionService,
1721                         mAdSelectionConfig,
1722                         decisionLogicJs,
1723                         TRUSTED_SCORING_SIGNALS,
1724                         BUYERS_DECISION_LOGIC);
1725 
1726         assertTrue(adSelectionOverrideTestCallback.mIsSuccess);
1727 
1728         // Add Custom Audience Overrides
1729         CustomAudienceOverrideTestCallback customAudienceOverrideTestCallback1 =
1730                 callAddCustomAudienceOverride(
1731                         CommonFixture.TEST_PACKAGE_NAME,
1732                         customAudience1.getBuyer(),
1733                         customAudience1.getName(),
1734                         biddingLogicJs,
1735                         null,
1736                         AdSelectionSignals.EMPTY,
1737                         mCustomAudienceService);
1738 
1739         assertTrue(customAudienceOverrideTestCallback1.mIsSuccess);
1740 
1741         CustomAudienceOverrideTestCallback customAudienceOverrideTestCallback2 =
1742                 callAddCustomAudienceOverride(
1743                         CommonFixture.TEST_PACKAGE_NAME,
1744                         customAudience2.getBuyer(),
1745                         customAudience2.getName(),
1746                         biddingLogicJs,
1747                         null,
1748                         AdSelectionSignals.EMPTY,
1749                         mCustomAudienceService);
1750 
1751         assertTrue(customAudienceOverrideTestCallback2.mIsSuccess);
1752 
1753         // Run Ad Selection
1754         AdSelectionTestCallback resultsCallback =
1755                 invokeRunAdSelection(
1756                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
1757 
1758         // Assert that ad selection fails since both Custom Audiences have invalid bids
1759         assertFalse(resultsCallback.mIsSuccess);
1760         assertNull(resultsCallback.mAdSelectionResponse);
1761 
1762         // Run Report Impression with random ad selection id
1763         ReportImpressionInput input =
1764                 new ReportImpressionInput.Builder()
1765                         .setAdSelectionConfig(mAdSelectionConfig)
1766                         .setAdSelectionId(1)
1767                         .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME)
1768                         .build();
1769 
1770         ReportImpressionTestCallback reportImpressionTestCallback =
1771                 callReportImpression(mAdSelectionService, input);
1772 
1773         assertFalse(reportImpressionTestCallback.mIsSuccess);
1774 
1775         // Run Report Interaction with random ad selection id
1776         ReportInteractionInput reportInteractionInput =
1777                 new ReportInteractionInput.Builder()
1778                         .setAdSelectionId(1)
1779                         .setInteractionKey(CLICK_INTERACTION)
1780                         .setInteractionData(INTERACTION_DATA)
1781                         .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME)
1782                         .setReportingDestinations(BUYER_DESTINATION | SELLER_DESTINATION)
1783                         .build();
1784 
1785         ReportInteractionTestCallback reportInteractionTestCallback =
1786                 callReportInteraction(mAdSelectionService, reportInteractionInput);
1787         assertFalse(reportInteractionTestCallback.mIsSuccess);
1788 
1789         mockWebServerRule.verifyMockServerRequests(
1790                 server, 0, Collections.emptyList(), mRequestMatcherPrefixMatch);
1791     }
1792 
1793     @Test
testFledgeFlowSuccessWithMockServer_preV3BiddingLogic()1794     public void testFledgeFlowSuccessWithMockServer_preV3BiddingLogic() throws Exception {
1795         doReturn(AdServicesApiConsent.GIVEN)
1796                 .when(mConsentManagerMock)
1797                 .getConsent(AdServicesApiType.FLEDGE);
1798         doReturn(false)
1799                 .when(mConsentManagerMock)
1800                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
1801 
1802         setupAdSelectionConfig();
1803         String decisionLogicJs = getDecisionLogicWithBeacons();
1804         String biddingLogicJs = getBiddingLogicWithBeacons();
1805 
1806         CustomAudience customAudience1 =
1807                 createCustomAudience(
1808                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
1809 
1810         CustomAudience customAudience2 =
1811                 createCustomAudience(
1812                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, BIDS_FOR_BUYER_2);
1813 
1814         // We add permits to the semaphores when the MWS is called and remove them in the asserts
1815         Semaphore impressionReportingSemaphore = new Semaphore(0);
1816         Semaphore interactionReportingSemaphore = new Semaphore(0);
1817 
1818         MockWebServer server =
1819                 getMockWebServer(
1820                         decisionLogicJs,
1821                         biddingLogicJs,
1822                         impressionReportingSemaphore,
1823                         interactionReportingSemaphore,
1824                         false);
1825 
1826         joinCustomAudienceAndAssertSuccess(customAudience1);
1827         joinCustomAudienceAndAssertSuccess(customAudience2);
1828 
1829         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
1830 
1831         selectAdsAndReport(
1832                 CommonFixture.getUri(
1833                         mLocalhostBuyerDomain.getAuthority(),
1834                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad3"),
1835                 impressionReportingSemaphore,
1836                 interactionReportingSemaphore);
1837         verifyStandardServerRequests(server);
1838     }
1839 
1840     @Test
testFledgeFlowSuccessWithMockServer_v3BiddingLogic()1841     public void testFledgeFlowSuccessWithMockServer_v3BiddingLogic() throws Exception {
1842         doReturn(AdServicesApiConsent.GIVEN)
1843                 .when(mConsentManagerMock)
1844                 .getConsent(AdServicesApiType.FLEDGE);
1845         doReturn(false)
1846                 .when(mConsentManagerMock)
1847                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
1848 
1849         setupAdSelectionConfig();
1850 
1851         CustomAudience customAudience1 =
1852                 createCustomAudience(
1853                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
1854 
1855         CustomAudience customAudience2 =
1856                 createCustomAudience(
1857                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, BIDS_FOR_BUYER_2);
1858 
1859         // We add permits to the semaphores when the MWS is called and remove them in the asserts
1860         Semaphore impressionReportingSemaphore = new Semaphore(0);
1861         Semaphore interactionReportingSemaphore = new Semaphore(0);
1862 
1863         MockWebServer server =
1864                 getMockWebServer(
1865                         getDecisionLogicWithBeacons(),
1866                         getV3BiddingLogicJs(),
1867                         impressionReportingSemaphore,
1868                         interactionReportingSemaphore,
1869                         true);
1870 
1871         joinCustomAudienceAndAssertSuccess(customAudience1);
1872         joinCustomAudienceAndAssertSuccess(customAudience2);
1873 
1874         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
1875 
1876         // Run Ad Selection
1877         selectAdsAndReport(
1878                 CommonFixture.getUri(
1879                         mLocalhostBuyerDomain.getAuthority(),
1880                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad3"),
1881                 impressionReportingSemaphore,
1882                 interactionReportingSemaphore);
1883         verifyStandardServerRequests(server);
1884     }
1885 
1886     @Test
testFledgeFlowSuccessWithDebugReportingSentImmediately()1887     public void testFledgeFlowSuccessWithDebugReportingSentImmediately() throws Exception {
1888         initClients(false, false, true, true, false, false, true, false, true, false, false, false);
1889         doReturn(AdServicesApiConsent.GIVEN)
1890                 .when(mConsentManagerMock)
1891                 .getConsent(AdServicesApiType.FLEDGE);
1892         setupAdSelectionConfig();
1893         joinCustomAudienceAndAssertSuccess(
1894                 createCustomAudience(
1895                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1));
1896         joinCustomAudienceAndAssertSuccess(
1897                 createCustomAudience(
1898                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, BIDS_FOR_BUYER_2));
1899         CountDownLatch debugReportingLatch = new CountDownLatch(4);
1900         MockWebServer server =
1901                 getMockWebServer(
1902                         getDecisionLogicJsWithDebugReporting(
1903                                 mLocalhostBuyerDomain
1904                                                 .buildUpon()
1905                                                 .path(SELLER_DEBUG_REPORT_WIN_PATH)
1906                                                 .build()
1907                                         + DEBUG_REPORT_WINNING_BID_PARAM,
1908                                 mLocalhostBuyerDomain
1909                                                 .buildUpon()
1910                                                 .path(SELLER_DEBUG_REPORT_LOSS_PATH)
1911                                                 .build()
1912                                         + DEBUG_REPORT_WINNING_BID_PARAM),
1913                         getBiddingLogicWithDebugReporting(
1914                                 mLocalhostBuyerDomain
1915                                                 .buildUpon()
1916                                                 .path(BUYER_DEBUG_REPORT_WIN_PATH)
1917                                                 .build()
1918                                         + DEBUG_REPORT_WINNING_BID_PARAM,
1919                                 mLocalhostBuyerDomain
1920                                                 .buildUpon()
1921                                                 .path(BUYER_DEBUG_REPORT_LOSS_PATH)
1922                                                 .build()
1923                                         + DEBUG_REPORT_WINNING_BID_PARAM),
1924                         /* debugReportingLatch= */ debugReportingLatch);
1925 
1926         mMockAdIdWorker.setResult(MockAdIdWorker.MOCK_AD_ID, false);
1927 
1928         AdSelectionTestCallback resultsCallback =
1929                 invokeRunAdSelection(
1930                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
1931 
1932         assertTrue(resultsCallback.mIsSuccess);
1933         debugReportingLatch.await(10, TimeUnit.SECONDS);
1934         mockWebServerRule.verifyMockServerRequests(
1935                 server,
1936                 9,
1937                 ImmutableList.of(
1938                         SELLER_DECISION_LOGIC_URI_PATH,
1939                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1,
1940                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_2,
1941                         BUYER_TRUSTED_SIGNAL_URI_PATH,
1942                         SELLER_TRUSTED_SIGNAL_URI_PATH + SELLER_TRUSTED_SIGNAL_PARAMS,
1943                         BUYER_DEBUG_REPORT_WIN_PATH + DEBUG_REPORT_WINNING_BID_RESPONSE,
1944                         BUYER_DEBUG_REPORT_LOSS_PATH + DEBUG_REPORT_WINNING_BID_RESPONSE,
1945                         SELLER_DEBUG_REPORT_WIN_PATH + DEBUG_REPORT_WINNING_BID_RESPONSE,
1946                         SELLER_DEBUG_REPORT_LOSS_PATH + DEBUG_REPORT_WINNING_BID_RESPONSE),
1947                 mRequestMatcherPrefixMatch);
1948     }
1949 
1950     @Test
testFledgeFlowSuccessWithDebugReportingSentInBatch()1951     public void testFledgeFlowSuccessWithDebugReportingSentInBatch() throws Exception {
1952         initClients(
1953                 false, false, true, true, false, false, true, false, false, false, false, false);
1954         doReturn(AdServicesApiConsent.GIVEN)
1955                 .when(mConsentManagerMock)
1956                 .getConsent(AdServicesApiType.FLEDGE);
1957         setupAdSelectionConfig();
1958         joinCustomAudienceAndAssertSuccess(
1959                 createCustomAudience(
1960                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1));
1961         joinCustomAudienceAndAssertSuccess(
1962                 createCustomAudience(
1963                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, BIDS_FOR_BUYER_2));
1964         MockWebServer server =
1965                 getMockWebServer(
1966                         getDecisionLogicJsWithDebugReporting(
1967                                 mLocalhostBuyerDomain
1968                                                 .buildUpon()
1969                                                 .path(SELLER_DEBUG_REPORT_WIN_PATH)
1970                                                 .build()
1971                                         + DEBUG_REPORT_WINNING_BID_PARAM,
1972                                 mLocalhostBuyerDomain
1973                                                 .buildUpon()
1974                                                 .path(SELLER_DEBUG_REPORT_LOSS_PATH)
1975                                                 .build()
1976                                         + DEBUG_REPORT_WINNING_BID_PARAM),
1977                         getBiddingLogicWithDebugReporting(
1978                                 mLocalhostBuyerDomain
1979                                                 .buildUpon()
1980                                                 .path(BUYER_DEBUG_REPORT_WIN_PATH)
1981                                                 .build()
1982                                         + DEBUG_REPORT_WINNING_BID_PARAM,
1983                                 mLocalhostBuyerDomain
1984                                                 .buildUpon()
1985                                                 .path(BUYER_DEBUG_REPORT_LOSS_PATH)
1986                                                 .build()
1987                                         + DEBUG_REPORT_WINNING_BID_PARAM),
1988                         /* debugReportingLatch= */ null);
1989 
1990         doNothing().when(() -> DebugReportSenderJobService.scheduleIfNeeded(any(), anyBoolean()));
1991         mMockAdIdWorker.setResult(MockAdIdWorker.MOCK_AD_ID, false);
1992 
1993         AdSelectionTestCallback resultsCallback =
1994                 invokeRunAdSelectionAndWaitForFullCallback(
1995                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
1996 
1997         assertTrue(resultsCallback.mIsSuccess);
1998         mockWebServerRule.verifyMockServerRequests(
1999                 server,
2000                 5,
2001                 ImmutableList.of(
2002                         SELLER_DECISION_LOGIC_URI_PATH,
2003                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1,
2004                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_2,
2005                         BUYER_TRUSTED_SIGNAL_URI_PATH,
2006                         SELLER_TRUSTED_SIGNAL_URI_PATH + SELLER_TRUSTED_SIGNAL_PARAMS),
2007                 mRequestMatcherPrefixMatch);
2008         List<DBAdSelectionDebugReport> debugReports =
2009                 mAdSelectionDebugReportDao.getDebugReportsBeforeTime(
2010                         CommonFixture.FIXED_NEXT_ONE_DAY, 1000);
2011         assertNotNull(debugReports);
2012         assertFalse(debugReports.isEmpty());
2013         assertEquals(4, debugReports.size());
2014         String buyerReportWinUrl =
2015                 mLocalhostBuyerDomain.buildUpon().path(BUYER_DEBUG_REPORT_WIN_PATH).build()
2016                         + DEBUG_REPORT_WINNING_BID_RESPONSE;
2017         String buyerReportLossUrl =
2018                 mLocalhostBuyerDomain.buildUpon().path(BUYER_DEBUG_REPORT_LOSS_PATH).build()
2019                         + DEBUG_REPORT_WINNING_BID_RESPONSE;
2020         String sellerReportWinUrl =
2021                 mLocalhostBuyerDomain.buildUpon().path(SELLER_DEBUG_REPORT_WIN_PATH).build()
2022                         + DEBUG_REPORT_WINNING_BID_RESPONSE;
2023         String sellerReportLossUrl =
2024                 mLocalhostBuyerDomain.buildUpon().path(SELLER_DEBUG_REPORT_LOSS_PATH).build()
2025                         + DEBUG_REPORT_WINNING_BID_RESPONSE;
2026         Set<String> expectedDebugUris =
2027                 ImmutableSet.of(
2028                         buyerReportWinUrl,
2029                         buyerReportLossUrl,
2030                         sellerReportWinUrl,
2031                         sellerReportLossUrl);
2032         Set<String> actualDebugUris =
2033                 debugReports.stream()
2034                         .map(
2035                                 debugReport -> {
2036                                     return debugReport.getDebugReportUri().toString();
2037                                 })
2038                         .collect(Collectors.toSet());
2039         assertEquals(expectedDebugUris, actualDebugUris);
2040         verify(
2041                 () -> DebugReportSenderJobService.scheduleIfNeeded(any(Context.class), eq(false)),
2042                 times(1));
2043     }
2044 
2045     @Test
testFledgeFlowSuccessWithDebugReportingDisabledWhenLatEnabled()2046     public void testFledgeFlowSuccessWithDebugReportingDisabledWhenLatEnabled() throws Exception {
2047         initClients(
2048                 false, false, true, true, false, false, true, false, false, false, false, false);
2049         doReturn(AdServicesApiConsent.GIVEN)
2050                 .when(mConsentManagerMock)
2051                 .getConsent(AdServicesApiType.FLEDGE);
2052         setupAdSelectionConfig();
2053         joinCustomAudienceAndAssertSuccess(
2054                 createCustomAudience(
2055                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1));
2056         joinCustomAudienceAndAssertSuccess(
2057                 createCustomAudience(
2058                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, BIDS_FOR_BUYER_2));
2059         MockWebServer server =
2060                 getMockWebServer(
2061                         getDecisionLogicJsWithDebugReporting(
2062                                 mLocalhostBuyerDomain
2063                                                 .buildUpon()
2064                                                 .path(SELLER_DEBUG_REPORT_WIN_PATH)
2065                                                 .build()
2066                                         + DEBUG_REPORT_WINNING_BID_PARAM,
2067                                 mLocalhostBuyerDomain
2068                                                 .buildUpon()
2069                                                 .path(SELLER_DEBUG_REPORT_LOSS_PATH)
2070                                                 .build()
2071                                         + DEBUG_REPORT_WINNING_BID_PARAM),
2072                         getBiddingLogicWithDebugReporting(
2073                                 mLocalhostBuyerDomain
2074                                                 .buildUpon()
2075                                                 .path(BUYER_DEBUG_REPORT_WIN_PATH)
2076                                                 .build()
2077                                         + DEBUG_REPORT_WINNING_BID_PARAM,
2078                                 mLocalhostBuyerDomain
2079                                                 .buildUpon()
2080                                                 .path(BUYER_DEBUG_REPORT_LOSS_PATH)
2081                                                 .build()
2082                                         + DEBUG_REPORT_WINNING_BID_PARAM),
2083                         /* debugReportingLatch= */ null);
2084 
2085         doNothing().when(() -> DebugReportSenderJobService.scheduleIfNeeded(any(), anyBoolean()));
2086         mMockAdIdWorker.setResult(MockAdIdWorker.MOCK_AD_ID, true);
2087 
2088         AdSelectionTestCallback resultsCallback =
2089                 invokeRunAdSelectionAndWaitForFullCallback(
2090                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
2091 
2092         assertTrue(resultsCallback.mIsSuccess);
2093         mockWebServerRule.verifyMockServerRequests(
2094                 server,
2095                 5,
2096                 ImmutableList.of(
2097                         SELLER_DECISION_LOGIC_URI_PATH,
2098                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1,
2099                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_2,
2100                         BUYER_TRUSTED_SIGNAL_URI_PATH,
2101                         SELLER_TRUSTED_SIGNAL_URI_PATH + SELLER_TRUSTED_SIGNAL_PARAMS),
2102                 mRequestMatcherPrefixMatch);
2103         List<DBAdSelectionDebugReport> debugReports =
2104                 mAdSelectionDebugReportDao.getDebugReportsBeforeTime(
2105                         CommonFixture.FIXED_NEXT_ONE_DAY, 1000);
2106         assertNotNull(debugReports);
2107         assertTrue(debugReports.isEmpty());
2108         verify(
2109                 () -> DebugReportSenderJobService.scheduleIfNeeded(any(Context.class), eq(false)),
2110                 never());
2111     }
2112 
2113     @Test
testFledgeFlowSuccessWithDebugReportingDisabledWhenAdIdServiceDisabled()2114     public void testFledgeFlowSuccessWithDebugReportingDisabledWhenAdIdServiceDisabled()
2115             throws Exception {
2116         initClients(false, false, true, true, false, false, true, false, false, true, false, false);
2117         doReturn(AdServicesApiConsent.GIVEN)
2118                 .when(mConsentManagerMock)
2119                 .getConsent(AdServicesApiType.FLEDGE);
2120         setupAdSelectionConfig();
2121         joinCustomAudienceAndAssertSuccess(
2122                 createCustomAudience(
2123                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1));
2124         joinCustomAudienceAndAssertSuccess(
2125                 createCustomAudience(
2126                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, BIDS_FOR_BUYER_2));
2127         MockWebServer server =
2128                 getMockWebServer(
2129                         getDecisionLogicJsWithDebugReporting(
2130                                 mLocalhostBuyerDomain
2131                                                 .buildUpon()
2132                                                 .path(SELLER_DEBUG_REPORT_WIN_PATH)
2133                                                 .build()
2134                                         + DEBUG_REPORT_WINNING_BID_PARAM,
2135                                 mLocalhostBuyerDomain
2136                                                 .buildUpon()
2137                                                 .path(SELLER_DEBUG_REPORT_LOSS_PATH)
2138                                                 .build()
2139                                         + DEBUG_REPORT_WINNING_BID_PARAM),
2140                         getBiddingLogicWithDebugReporting(
2141                                 mLocalhostBuyerDomain
2142                                                 .buildUpon()
2143                                                 .path(BUYER_DEBUG_REPORT_WIN_PATH)
2144                                                 .build()
2145                                         + DEBUG_REPORT_WINNING_BID_PARAM,
2146                                 mLocalhostBuyerDomain
2147                                                 .buildUpon()
2148                                                 .path(BUYER_DEBUG_REPORT_LOSS_PATH)
2149                                                 .build()
2150                                         + DEBUG_REPORT_WINNING_BID_PARAM),
2151                         /* debugReportingLatch= */ null);
2152 
2153         doNothing().when(() -> DebugReportSenderJobService.scheduleIfNeeded(any(), anyBoolean()));
2154         mMockAdIdWorker.setResult(MockAdIdWorker.MOCK_AD_ID, false);
2155 
2156         AdSelectionTestCallback resultsCallback =
2157                 invokeRunAdSelectionAndWaitForFullCallback(
2158                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
2159 
2160         assertTrue(resultsCallback.mIsSuccess);
2161         mockWebServerRule.verifyMockServerRequests(
2162                 server,
2163                 5,
2164                 ImmutableList.of(
2165                         SELLER_DECISION_LOGIC_URI_PATH,
2166                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1,
2167                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_2,
2168                         BUYER_TRUSTED_SIGNAL_URI_PATH,
2169                         SELLER_TRUSTED_SIGNAL_URI_PATH + SELLER_TRUSTED_SIGNAL_PARAMS),
2170                 mRequestMatcherPrefixMatch);
2171         List<DBAdSelectionDebugReport> debugReports =
2172                 mAdSelectionDebugReportDao.getDebugReportsBeforeTime(
2173                         CommonFixture.FIXED_NEXT_ONE_DAY, 1000);
2174         assertNotNull(debugReports);
2175         assertTrue(debugReports.isEmpty());
2176         verify(
2177                 () -> DebugReportSenderJobService.scheduleIfNeeded(any(Context.class), eq(false)),
2178                 never());
2179     }
2180 
2181     @Test
testFledgeFlowSuccessWithMockServer_DoesNotReportToBuyerWhenEnrollmentFails()2182     public void testFledgeFlowSuccessWithMockServer_DoesNotReportToBuyerWhenEnrollmentFails()
2183             throws Exception {
2184         initClients(
2185                 false, true, true, true, false, false, false, false, false, false, false, false);
2186         doReturn(AdServicesApiConsent.GIVEN)
2187                 .when(mConsentManagerMock)
2188                 .getConsent(AdServicesApiType.FLEDGE);
2189         doReturn(false)
2190                 .when(mConsentManagerMock)
2191                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
2192 
2193         setupAdSelectionConfig();
2194 
2195         CustomAudience customAudience1 =
2196                 createCustomAudience(
2197                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
2198 
2199         CustomAudience customAudience2 =
2200                 createCustomAudience(
2201                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, BIDS_FOR_BUYER_2);
2202 
2203         // We add permits to the semaphores when the MWS is called and remove them in the asserts
2204         Semaphore impressionReportingSemaphore = new Semaphore(0);
2205         Semaphore interactionReportingSemaphore = new Semaphore(0);
2206 
2207         MockWebServer server =
2208                 getMockWebServer(
2209                         getDecisionLogicWithBeacons(),
2210                         getV3BiddingLogicJs(),
2211                         impressionReportingSemaphore,
2212                         interactionReportingSemaphore,
2213                         true);
2214 
2215         // Make buyer impression reporting fail enrollment check
2216         doThrow(new FledgeAuthorizationFilter.AdTechNotAllowedException())
2217                 .when(mFledgeAuthorizationFilterMock)
2218                 .assertAdTechEnrolled(
2219                         AdTechIdentifier.fromString(
2220                                 mockWebServerRule.uriForPath(BUYER_REPORTING_PATH).getHost()),
2221                         AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION);
2222 
2223         doThrow(new FledgeAuthorizationFilter.AdTechNotAllowedException())
2224                 .when(mFledgeAuthorizationFilterMock)
2225                 .assertAdTechEnrolled(
2226                         AdTechIdentifier.fromString(
2227                                 mockWebServerRule.uriForPath(BUYER_REPORTING_PATH).getHost()),
2228                         AD_SERVICES_API_CALLED__API_NAME__REPORT_INTERACTION);
2229 
2230         joinCustomAudienceAndAssertSuccess(customAudience1);
2231         joinCustomAudienceAndAssertSuccess(customAudience2);
2232 
2233         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
2234 
2235         // Run Ad Selection
2236         AdSelectionTestCallback resultsCallback =
2237                 invokeRunAdSelection(
2238                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
2239 
2240         assertTrue(resultsCallback.mIsSuccess);
2241         long resultSelectionId = resultsCallback.mAdSelectionResponse.getAdSelectionId();
2242         assertTrue(mAdSelectionEntryDao.doesAdSelectionIdExist(resultSelectionId));
2243         assertEquals(
2244                 CommonFixture.getUri(
2245                         mLocalhostBuyerDomain.getAuthority(),
2246                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad3"),
2247                 resultsCallback.mAdSelectionResponse.getRenderUri());
2248 
2249         reportImpressionAndAssertSuccess(resultSelectionId);
2250         reportOnlyBuyerInteractionAndAssertSuccess(resultsCallback);
2251 
2252         // Assert only seller impression reporting happened since buyer enrollment check fails
2253         assertTrue(impressionReportingSemaphore.tryAcquire(1, 10, TimeUnit.SECONDS));
2254 
2255         // Assert buyer interaction reporting did not happen
2256         assertTrue(interactionReportingSemaphore.tryAcquire(0, 10, TimeUnit.SECONDS));
2257 
2258         assertEquals(
2259                 "Extra calls made to MockWebServer",
2260                 0,
2261                 impressionReportingSemaphore.availablePermits());
2262         assertEquals(
2263                 "Extra calls made to MockWebServer",
2264                 0,
2265                 interactionReportingSemaphore.availablePermits());
2266 
2267         // Verify 3 less requests than normal since only seller impression reporting happens
2268         mockWebServerRule.verifyMockServerRequests(
2269                 server,
2270                 7,
2271                 ImmutableList.of(
2272                         SELLER_DECISION_LOGIC_URI_PATH,
2273                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1,
2274                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_2,
2275                         BUYER_TRUSTED_SIGNAL_URI_PATH,
2276                         SELLER_TRUSTED_SIGNAL_URI_PATH + SELLER_TRUSTED_SIGNAL_PARAMS),
2277                 mRequestMatcherPrefixMatch);
2278     }
2279 
2280     @Test
testFledgeFlowSuccessWithMockServer_allFilters()2281     public void testFledgeFlowSuccessWithMockServer_allFilters() throws Exception {
2282         testFledgeFlowSuccessAllFilters(false, false);
2283     }
2284 
2285     @Test
2286     public void
testFledgeFlowSuccessWithMockServer_allFiltersWithUnifiedTablesAuctionServerDisabled()2287             testFledgeFlowSuccessWithMockServer_allFiltersWithUnifiedTablesAuctionServerDisabled()
2288                     throws Exception {
2289         testFledgeFlowSuccessAllFilters(true, false);
2290     }
2291 
2292     @Test
2293     public void
testFledgeFlowSuccessWithMockServer_allFiltersWithUnifiedTablesAuctionServerEnabled()2294             testFledgeFlowSuccessWithMockServer_allFiltersWithUnifiedTablesAuctionServerEnabled()
2295                     throws Exception {
2296         testFledgeFlowSuccessAllFilters(true, true);
2297     }
2298 
2299     @Test
testFledgeFlowSuccessWithMockServer_fetchAndJoinCustomAudienceFlow_noFilters()2300     public void testFledgeFlowSuccessWithMockServer_fetchAndJoinCustomAudienceFlow_noFilters()
2301             throws Exception {
2302         initClients(true, true, false, false, false, false);
2303         doReturn(LOCALHOST_BUYER)
2304                 .when(mFledgeAuthorizationFilterMock)
2305                 .getAndAssertAdTechFromUriAllowed(any(), any(), any(), anyInt(), anyInt());
2306         doReturn(AdServicesApiConsent.GIVEN)
2307                 .when(mConsentManagerMock)
2308                 .getConsent(AdServicesApiType.FLEDGE);
2309         doReturn(false)
2310                 .when(mConsentManagerMock)
2311                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
2312 
2313         setupAdSelectionConfig();
2314         CustomAudience customAudience1 =
2315                 createCustomAudience(
2316                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
2317 
2318         // Using the same generic key across all ads in the CA
2319         List<Set<Integer>> adCounterKeysForCa2 =
2320                 Arrays.asList(
2321                         Collections.singleton(KeyedFrequencyCapFixture.KEY1),
2322                         Collections.singleton(KeyedFrequencyCapFixture.KEY1),
2323                         Collections.singleton(KeyedFrequencyCapFixture.KEY1));
2324         /* The final ad with the highest bid has both fcap and app install filters, the second ad
2325          * with the middle bid has only an app install filter and the first ad with the lowest bid
2326          * in this ca has only a fcap filter.
2327          */
2328         List<AdFilters> adFiltersForCa2 =
2329                 Arrays.asList(
2330                         new AdFilters.Builder()
2331                                 .setFrequencyCapFilters(CLICK_ONCE_PER_DAY_KEY1)
2332                                 .build(),
2333                         new AdFilters.Builder().setAppInstallFilters(CURRENT_APP_FILTER).build(),
2334                         new AdFilters.Builder()
2335                                 .setAppInstallFilters(CURRENT_APP_FILTER)
2336                                 .setFrequencyCapFilters(CLICK_ONCE_PER_DAY_KEY1)
2337                                 .build());
2338         CustomAudience customAudience2 =
2339                 createCustomAudience(
2340                         mLocalhostBuyerDomain,
2341                         CUSTOM_AUDIENCE_SEQ_2,
2342                         BIDS_FOR_BUYER_2,
2343                         adCounterKeysForCa2,
2344                         adFiltersForCa2,
2345                         false);
2346 
2347         // We add permits to the semaphores when the MWS is called and remove them in the asserts
2348         Semaphore impressionReportingSemaphore = new Semaphore(0);
2349         Semaphore interactionReportingSemaphore = new Semaphore(0);
2350 
2351         // Prepare the custom audiences as json responses we expect from the server.
2352         AdDataConversionStrategy adDataConversionStrategy =
2353                 AdDataConversionStrategyFactory.getAdDataConversionStrategy(false, false, true);
2354         List<DBAdData> ads1 = new ArrayList<>();
2355         for (AdData ad : customAudience1.getAds()) {
2356             ads1.add(
2357                     new DBAdData.Builder()
2358                             .setRenderUri(ad.getRenderUri())
2359                             .setMetadata(ad.getMetadata())
2360                             .setAdCounterKeys(ad.getAdCounterKeys())
2361                             .setAdFilters(ad.getAdFilters())
2362                             .build());
2363         }
2364         String customAudience1JsonString =
2365                 CustomAudienceBlobFixture.asJSONObjectString(
2366                         null,
2367                         null,
2368                         customAudience1.getName(),
2369                         customAudience1.getActivationTime(),
2370                         customAudience1.getExpirationTime(),
2371                         customAudience1.getDailyUpdateUri(),
2372                         customAudience1.getBiddingLogicUri(),
2373                         customAudience1.getUserBiddingSignals().toString(),
2374                         DBTrustedBiddingData.fromServiceObject(
2375                                 customAudience1.getTrustedBiddingData()),
2376                         ads1);
2377         List<DBAdData> ads2 = new ArrayList<>();
2378         for (AdData ad : customAudience2.getAds()) {
2379             ads2.add(
2380                     new DBAdData.Builder()
2381                             .setRenderUri(ad.getRenderUri())
2382                             .setMetadata(ad.getMetadata())
2383                             .setAdCounterKeys(ad.getAdCounterKeys())
2384                             .setAdFilters(ad.getAdFilters())
2385                             .build());
2386         }
2387         String customAudience2JsonString =
2388                 CustomAudienceBlobFixture.asJSONObjectString(
2389                         null,
2390                         null,
2391                         customAudience2.getName(),
2392                         customAudience2.getActivationTime(),
2393                         customAudience2.getExpirationTime(),
2394                         customAudience2.getDailyUpdateUri(),
2395                         customAudience2.getBiddingLogicUri(),
2396                         customAudience2.getUserBiddingSignals().toString(),
2397                         DBTrustedBiddingData.fromServiceObject(
2398                                 customAudience2.getTrustedBiddingData()),
2399                         ads2);
2400         HashMap<String, String> remoteCustomAudiencesMap = new HashMap<>();
2401         String customAudience1Id = String.valueOf(customAudience1.hashCode());
2402         String customAudience2Id = String.valueOf(customAudience2.hashCode());
2403         remoteCustomAudiencesMap.put(customAudience1Id, customAudience1JsonString);
2404         remoteCustomAudiencesMap.put(customAudience2Id, customAudience2JsonString);
2405 
2406         MockWebServer server =
2407                 getMockWebServer(
2408                         remoteCustomAudiencesMap,
2409                         getDecisionLogicWithBeacons(),
2410                         getV3BiddingLogicJs(),
2411                         impressionReportingSemaphore,
2412                         interactionReportingSemaphore,
2413                         /* debugReportingLatch= */ null,
2414                         true);
2415 
2416         // TODO(b/289276159): Schedule background fetch if needed once added to fetchCA.
2417         // doNothing()
2418         //      .when(() -> BackgroundFetchJobService.scheduleIfNeeded(any(), any(), anyBoolean()));
2419 
2420         fetchAndJoinCustomAudienceAndAssertSuccess(
2421                 new FetchAndJoinCustomAudienceInput.Builder(
2422                                 CommonFixture.getUri(
2423                                         mLocalhostBuyerDomain.getAuthority(),
2424                                         FETCH_CA_PATH + "/" + customAudience1Id),
2425                                 VALID_OWNER)
2426                         .build());
2427         fetchAndJoinCustomAudienceAndAssertSuccess(
2428                 new FetchAndJoinCustomAudienceInput.Builder(
2429                                 CommonFixture.getUri(
2430                                         mLocalhostBuyerDomain.getAuthority(),
2431                                         FETCH_CA_PATH + "/" + customAudience2Id),
2432                                 VALID_OWNER)
2433                         .build());
2434 
2435         // TODO(b/289276159): Verify background fetch is scheduled if needed once added to fetchCA.
2436         // verify(() -> BackgroundFetchJobService.scheduleIfNeeded(any(), any(), eq(false)))
2437 
2438         // Run Ad Selection no filters active
2439         selectAdsAndReport(
2440                 CommonFixture.getUri(
2441                         mLocalhostBuyerDomain.getAuthority(),
2442                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad3"),
2443                 impressionReportingSemaphore,
2444                 interactionReportingSemaphore);
2445 
2446         // 2 fetch CA requests and 10 requests for the auction with both CAs
2447         mockWebServerRule.verifyMockServerRequests(
2448                 server,
2449                 12,
2450                 ImmutableList.of(
2451                         FETCH_CA_PATH + "/" + customAudience1Id,
2452                         FETCH_CA_PATH + "/" + customAudience2Id,
2453                         SELLER_DECISION_LOGIC_URI_PATH,
2454                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1,
2455                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_2,
2456                         BUYER_TRUSTED_SIGNAL_URI_PATH,
2457                         SELLER_TRUSTED_SIGNAL_URI_PATH + SELLER_TRUSTED_SIGNAL_PARAMS),
2458                 mRequestMatcherPrefixMatch);
2459     }
2460 
2461     @Test
testFledgeFlowSuccessWithMockServer_fetchAndJoinCustomAudience_appInstallFilters()2462     public void testFledgeFlowSuccessWithMockServer_fetchAndJoinCustomAudience_appInstallFilters()
2463             throws Exception {
2464         initClients(true, true, false, false, false, false);
2465         doReturn(LOCALHOST_BUYER)
2466                 .when(mFledgeAuthorizationFilterMock)
2467                 .getAndAssertAdTechFromUriAllowed(any(), any(), any(), anyInt(), anyInt());
2468         doReturn(AdServicesApiConsent.GIVEN)
2469                 .when(mConsentManagerMock)
2470                 .getConsent(AdServicesApiType.FLEDGE);
2471         doReturn(false)
2472                 .when(mConsentManagerMock)
2473                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
2474 
2475         setupAdSelectionConfig();
2476         CustomAudience customAudience1 =
2477                 createCustomAudience(
2478                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
2479 
2480         // Using the same generic key across all ads in the CA
2481         List<Set<Integer>> adCounterKeysForCa2 =
2482                 Arrays.asList(
2483                         Collections.singleton(KeyedFrequencyCapFixture.KEY1),
2484                         Collections.singleton(KeyedFrequencyCapFixture.KEY1),
2485                         Collections.singleton(KeyedFrequencyCapFixture.KEY1));
2486         /* The final ad with the highest bid has both fcap and app install filters, the second ad
2487          * with the middle bid has only an app install filter and the first ad with the lowest bid
2488          * in this ca has only a fcap filter.
2489          */
2490         List<AdFilters> adFiltersForCa2 =
2491                 Arrays.asList(
2492                         new AdFilters.Builder()
2493                                 .setFrequencyCapFilters(CLICK_ONCE_PER_DAY_KEY1)
2494                                 .build(),
2495                         new AdFilters.Builder().setAppInstallFilters(CURRENT_APP_FILTER).build(),
2496                         new AdFilters.Builder()
2497                                 .setAppInstallFilters(CURRENT_APP_FILTER)
2498                                 .setFrequencyCapFilters(CLICK_ONCE_PER_DAY_KEY1)
2499                                 .build());
2500         CustomAudience customAudience2 =
2501                 createCustomAudience(
2502                         mLocalhostBuyerDomain,
2503                         CUSTOM_AUDIENCE_SEQ_2,
2504                         BIDS_FOR_BUYER_2,
2505                         adCounterKeysForCa2,
2506                         adFiltersForCa2,
2507                         false);
2508 
2509         // We add permits to the semaphores when the MWS is called and remove them in the asserts
2510         Semaphore impressionReportingSemaphore = new Semaphore(0);
2511         Semaphore interactionReportingSemaphore = new Semaphore(0);
2512 
2513         // Prepare the custom audiences as json responses we expect from the server.
2514         AdDataConversionStrategy adDataConversionStrategy =
2515                 AdDataConversionStrategyFactory.getAdDataConversionStrategy(true, true, true);
2516         List<DBAdData> ads1 = new ArrayList<>();
2517         for (AdData ad : customAudience1.getAds()) {
2518             ads1.add(
2519                     new DBAdData.Builder()
2520                             .setRenderUri(ad.getRenderUri())
2521                             .setMetadata(ad.getMetadata())
2522                             .setAdCounterKeys(ad.getAdCounterKeys())
2523                             .setAdFilters(ad.getAdFilters())
2524                             .build());
2525         }
2526         String customAudience1JsonString =
2527                 CustomAudienceBlobFixture.asJSONObjectString(
2528                         null,
2529                         null,
2530                         customAudience1.getName(),
2531                         customAudience1.getActivationTime(),
2532                         customAudience1.getExpirationTime(),
2533                         customAudience1.getDailyUpdateUri(),
2534                         customAudience1.getBiddingLogicUri(),
2535                         customAudience1.getUserBiddingSignals().toString(),
2536                         DBTrustedBiddingData.fromServiceObject(
2537                                 customAudience1.getTrustedBiddingData()),
2538                         ads1);
2539         List<DBAdData> ads2 = new ArrayList<>();
2540         for (AdData ad : customAudience2.getAds()) {
2541             ads2.add(
2542                     new DBAdData.Builder()
2543                             .setRenderUri(ad.getRenderUri())
2544                             .setMetadata(ad.getMetadata())
2545                             .setAdCounterKeys(ad.getAdCounterKeys())
2546                             .setAdFilters(ad.getAdFilters())
2547                             .build());
2548         }
2549         String customAudience2JsonString =
2550                 CustomAudienceBlobFixture.asJSONObjectString(
2551                         null,
2552                         null,
2553                         customAudience2.getName(),
2554                         customAudience2.getActivationTime(),
2555                         customAudience2.getExpirationTime(),
2556                         customAudience2.getDailyUpdateUri(),
2557                         customAudience2.getBiddingLogicUri(),
2558                         customAudience2.getUserBiddingSignals().toString(),
2559                         DBTrustedBiddingData.fromServiceObject(
2560                                 customAudience2.getTrustedBiddingData()),
2561                         ads2);
2562         HashMap<String, String> remoteCustomAudiencesMap = new HashMap<>();
2563         String customAudience1Id = String.valueOf(customAudience1.hashCode());
2564         String customAudience2Id = String.valueOf(customAudience2.hashCode());
2565         remoteCustomAudiencesMap.put(customAudience1Id, customAudience1JsonString);
2566         remoteCustomAudiencesMap.put(customAudience2Id, customAudience2JsonString);
2567 
2568         MockWebServer server =
2569                 getMockWebServer(
2570                         remoteCustomAudiencesMap,
2571                         getDecisionLogicWithBeacons(),
2572                         getV3BiddingLogicJs(),
2573                         impressionReportingSemaphore,
2574                         interactionReportingSemaphore,
2575                         /* debugReportingLatch= */ null,
2576                         true);
2577 
2578         // TODO(b/289276159): Schedule background fetch if needed once added to fetchCA.
2579         // doNothing()
2580         //      .when(() -> BackgroundFetchJobService.scheduleIfNeeded(any(), any(), anyBoolean()));
2581 
2582         fetchAndJoinCustomAudienceAndAssertSuccess(
2583                 new FetchAndJoinCustomAudienceInput.Builder(
2584                                 CommonFixture.getUri(
2585                                         mLocalhostBuyerDomain.getAuthority(),
2586                                         FETCH_CA_PATH + "/" + customAudience1Id),
2587                                 VALID_OWNER)
2588                         .build());
2589         fetchAndJoinCustomAudienceAndAssertSuccess(
2590                 new FetchAndJoinCustomAudienceInput.Builder(
2591                                 CommonFixture.getUri(
2592                                         mLocalhostBuyerDomain.getAuthority(),
2593                                         FETCH_CA_PATH + "/" + customAudience2Id),
2594                                 VALID_OWNER)
2595                         .build());
2596 
2597         // TODO(b/289276159): Verify background fetch is scheduled if needed once added to fetchCA.
2598         // verify(() -> BackgroundFetchJobService.scheduleIfNeeded(any(), any(), eq(false)))
2599 
2600         // Run Ad Selection with app install filtering
2601         registerForAppInstallFiltering();
2602         long adSelectionId =
2603                 selectAdsAndReport(
2604                         CommonFixture.getUri(
2605                                 mLocalhostBuyerDomain.getAuthority(),
2606                                 AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad1"),
2607                         impressionReportingSemaphore,
2608                         interactionReportingSemaphore);
2609 
2610         // 2 fetch CA requests and 10 requests for the auctions with both CAs.
2611         mockWebServerRule.verifyMockServerRequests(
2612                 server,
2613                 12,
2614                 ImmutableList.of(
2615                         FETCH_CA_PATH + "/" + customAudience1Id,
2616                         FETCH_CA_PATH + "/" + customAudience2Id,
2617                         SELLER_DECISION_LOGIC_URI_PATH,
2618                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1,
2619                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_2,
2620                         BUYER_TRUSTED_SIGNAL_URI_PATH,
2621                         SELLER_TRUSTED_SIGNAL_URI_PATH + SELLER_TRUSTED_SIGNAL_PARAMS),
2622                 mRequestMatcherPrefixMatch);
2623     }
2624 
2625     @Test
testFledgeFlowSuccessWithMockServer_fetchAndJoinCustomAudienceFlow_bothFilters()2626     public void testFledgeFlowSuccessWithMockServer_fetchAndJoinCustomAudienceFlow_bothFilters()
2627             throws Exception {
2628         initClients(true, true, false, false, false, false);
2629         doReturn(LOCALHOST_BUYER)
2630                 .when(mFledgeAuthorizationFilterMock)
2631                 .getAndAssertAdTechFromUriAllowed(any(), any(), any(), anyInt(), anyInt());
2632         doReturn(AdServicesApiConsent.GIVEN)
2633                 .when(mConsentManagerMock)
2634                 .getConsent(AdServicesApiType.FLEDGE);
2635         doReturn(false)
2636                 .when(mConsentManagerMock)
2637                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
2638 
2639         setupAdSelectionConfig();
2640         CustomAudience customAudience1 =
2641                 createCustomAudience(
2642                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
2643 
2644         // Using the same generic key across all ads in the CA
2645         List<Set<Integer>> adCounterKeysForCa2 =
2646                 Arrays.asList(
2647                         Collections.singleton(KeyedFrequencyCapFixture.KEY1),
2648                         Collections.singleton(KeyedFrequencyCapFixture.KEY1),
2649                         Collections.singleton(KeyedFrequencyCapFixture.KEY1));
2650         /* The final ad with the highest bid has both fcap and app install filters, the second ad
2651          * with the middle bid has only an app install filter and the first ad with the lowest bid
2652          * in this ca has only a fcap filter.
2653          */
2654         List<AdFilters> adFiltersForCa2 =
2655                 Arrays.asList(
2656                         new AdFilters.Builder()
2657                                 .setFrequencyCapFilters(CLICK_ONCE_PER_DAY_KEY1)
2658                                 .build(),
2659                         new AdFilters.Builder().setAppInstallFilters(CURRENT_APP_FILTER).build(),
2660                         new AdFilters.Builder()
2661                                 .setAppInstallFilters(CURRENT_APP_FILTER)
2662                                 .setFrequencyCapFilters(CLICK_ONCE_PER_DAY_KEY1)
2663                                 .build());
2664         CustomAudience customAudience2 =
2665                 createCustomAudience(
2666                         mLocalhostBuyerDomain,
2667                         CUSTOM_AUDIENCE_SEQ_2,
2668                         BIDS_FOR_BUYER_2,
2669                         adCounterKeysForCa2,
2670                         adFiltersForCa2,
2671                         false);
2672 
2673         // We add permits to the semaphores when the MWS is called and remove them in the asserts
2674         Semaphore impressionReportingSemaphore = new Semaphore(0);
2675         Semaphore interactionReportingSemaphore = new Semaphore(0);
2676 
2677         // Prepare the custom audiences as json responses we expect from the server.
2678         AdDataConversionStrategy adDataConversionStrategy =
2679                 AdDataConversionStrategyFactory.getAdDataConversionStrategy(true, true, true);
2680         List<DBAdData> ads1 = new ArrayList<>();
2681         for (AdData ad : customAudience1.getAds()) {
2682             ads1.add(
2683                     new DBAdData.Builder()
2684                             .setRenderUri(ad.getRenderUri())
2685                             .setMetadata(ad.getMetadata())
2686                             .setAdCounterKeys(ad.getAdCounterKeys())
2687                             .setAdFilters(ad.getAdFilters())
2688                             .build());
2689         }
2690         String customAudience1JsonString =
2691                 CustomAudienceBlobFixture.asJSONObjectString(
2692                         null,
2693                         null,
2694                         customAudience1.getName(),
2695                         customAudience1.getActivationTime(),
2696                         customAudience1.getExpirationTime(),
2697                         customAudience1.getDailyUpdateUri(),
2698                         customAudience1.getBiddingLogicUri(),
2699                         customAudience1.getUserBiddingSignals().toString(),
2700                         DBTrustedBiddingData.fromServiceObject(
2701                                 customAudience1.getTrustedBiddingData()),
2702                         ads1);
2703         List<DBAdData> ads2 = new ArrayList<>();
2704         for (AdData ad : customAudience2.getAds()) {
2705             ads2.add(
2706                     new DBAdData.Builder()
2707                             .setRenderUri(ad.getRenderUri())
2708                             .setMetadata(ad.getMetadata())
2709                             .setAdCounterKeys(ad.getAdCounterKeys())
2710                             .setAdFilters(ad.getAdFilters())
2711                             .build());
2712         }
2713         String customAudience2JsonString =
2714                 CustomAudienceBlobFixture.asJSONObjectString(
2715                         null,
2716                         null,
2717                         customAudience2.getName(),
2718                         customAudience2.getActivationTime(),
2719                         customAudience2.getExpirationTime(),
2720                         customAudience2.getDailyUpdateUri(),
2721                         customAudience2.getBiddingLogicUri(),
2722                         customAudience2.getUserBiddingSignals().toString(),
2723                         DBTrustedBiddingData.fromServiceObject(
2724                                 customAudience2.getTrustedBiddingData()),
2725                         ads2);
2726         HashMap<String, String> remoteCustomAudiencesMap = new HashMap<>();
2727         String customAudience1Id = String.valueOf(customAudience1.hashCode());
2728         String customAudience2Id = String.valueOf(customAudience2.hashCode());
2729         remoteCustomAudiencesMap.put(customAudience1Id, customAudience1JsonString);
2730         remoteCustomAudiencesMap.put(customAudience2Id, customAudience2JsonString);
2731 
2732         MockWebServer server =
2733                 getMockWebServer(
2734                         remoteCustomAudiencesMap,
2735                         getDecisionLogicWithBeacons(),
2736                         getV3BiddingLogicJs(),
2737                         impressionReportingSemaphore,
2738                         interactionReportingSemaphore,
2739                         /* debugReportingLatch= */ null,
2740                         true);
2741 
2742         // TODO(b/289276159): Schedule background fetch if needed once added to fetchCA.
2743         // doNothing()
2744         //      .when(() -> BackgroundFetchJobService.scheduleIfNeeded(any(), any(), anyBoolean()));
2745 
2746         fetchAndJoinCustomAudienceAndAssertSuccess(
2747                 new FetchAndJoinCustomAudienceInput.Builder(
2748                                 CommonFixture.getUri(
2749                                         mLocalhostBuyerDomain.getAuthority(),
2750                                         FETCH_CA_PATH + "/" + customAudience1Id),
2751                                 VALID_OWNER)
2752                         .build());
2753         fetchAndJoinCustomAudienceAndAssertSuccess(
2754                 new FetchAndJoinCustomAudienceInput.Builder(
2755                                 CommonFixture.getUri(
2756                                         mLocalhostBuyerDomain.getAuthority(),
2757                                         FETCH_CA_PATH + "/" + customAudience2Id),
2758                                 VALID_OWNER)
2759                         .build());
2760 
2761         // TODO(b/289276159): Verify background fetch is scheduled if needed once added to fetchCA.
2762         // verify(() -> BackgroundFetchJobService.scheduleIfNeeded(any(), any(), eq(false)))
2763 
2764         // Run Ad Selection with app install filtering
2765         registerForAppInstallFiltering();
2766         long adSelectionId =
2767                 selectAdsAndReport(
2768                         CommonFixture.getUri(
2769                                 mLocalhostBuyerDomain.getAuthority(),
2770                                 AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad1"),
2771                         impressionReportingSemaphore,
2772                         interactionReportingSemaphore);
2773 
2774         // Run Ad Selection with both filters
2775         updateHistogramAndAssertSuccess(adSelectionId, FrequencyCapFilters.AD_EVENT_TYPE_CLICK);
2776         selectAdsAndReport(
2777                 CommonFixture.getUri(
2778                         mLocalhostBuyerDomain.getAuthority(),
2779                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_1 + "/ad2"),
2780                 impressionReportingSemaphore,
2781                 interactionReportingSemaphore);
2782 
2783         // 2 fetch CA requests, 10 requests for the auction with both CAs and 9 requests for the
2784         // auctions with one CA.
2785         mockWebServerRule.verifyMockServerRequests(
2786                 server,
2787                 21,
2788                 ImmutableList.of(
2789                         FETCH_CA_PATH + "/" + customAudience1Id,
2790                         FETCH_CA_PATH + "/" + customAudience2Id,
2791                         SELLER_DECISION_LOGIC_URI_PATH,
2792                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1,
2793                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_2,
2794                         BUYER_TRUSTED_SIGNAL_URI_PATH,
2795                         SELLER_TRUSTED_SIGNAL_URI_PATH + SELLER_TRUSTED_SIGNAL_PARAMS),
2796                 mRequestMatcherPrefixMatch);
2797     }
2798 
2799     @Test
2800     public void
testFledgeFlowSuccessWithMockServer_fetchAndJoinCustomAudienceFlow_FCapEnabled_AppInstallDisabled()2801             testFledgeFlowSuccessWithMockServer_fetchAndJoinCustomAudienceFlow_FCapEnabled_AppInstallDisabled()
2802                     throws Exception {
2803         initClients(
2804                 false,
2805                 true,
2806                 /* frequencyCapFilteringEnabled= */ true,
2807                 /* appInstallFilteringEnabled= */ false,
2808                 true,
2809                 false,
2810                 false,
2811                 false,
2812                 false,
2813                 false,
2814                 false,
2815                 false);
2816         doReturn(LOCALHOST_BUYER)
2817                 .when(mFledgeAuthorizationFilterMock)
2818                 .getAndAssertAdTechFromUriAllowed(any(), any(), any(), anyInt(), anyInt());
2819         doReturn(AdServicesApiConsent.GIVEN)
2820                 .when(mConsentManagerMock)
2821                 .getConsent(AdServicesApiType.FLEDGE);
2822         doReturn(false)
2823                 .when(mConsentManagerMock)
2824                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
2825 
2826         setupAdSelectionConfig();
2827         CustomAudience customAudience1 =
2828                 createCustomAudience(
2829                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
2830 
2831         // Using the same generic key across all ads in the CA
2832         List<Set<Integer>> adCounterKeysForCa2 =
2833                 Arrays.asList(
2834                         Collections.singleton(KeyedFrequencyCapFixture.KEY1),
2835                         Collections.singleton(KeyedFrequencyCapFixture.KEY1),
2836                         Collections.singleton(KeyedFrequencyCapFixture.KEY1));
2837         /* The final ad with the highest bid has only fcap filters, the second ad
2838          * with the middle bid has both filters and the first ad with the lowest bid
2839          * in this ca has only an app install filter.
2840          */
2841         List<AdFilters> adFiltersForCa2 =
2842                 Arrays.asList(
2843                         new AdFilters.Builder().setAppInstallFilters(CURRENT_APP_FILTER).build(),
2844                         new AdFilters.Builder()
2845                                 .setAppInstallFilters(CURRENT_APP_FILTER)
2846                                 .setFrequencyCapFilters(CLICK_ONCE_PER_DAY_KEY1)
2847                                 .build(),
2848                         new AdFilters.Builder()
2849                                 .setFrequencyCapFilters(CLICK_ONCE_PER_DAY_KEY1)
2850                                 .build());
2851         CustomAudience customAudience2 =
2852                 createCustomAudience(
2853                         mLocalhostBuyerDomain,
2854                         CUSTOM_AUDIENCE_SEQ_2,
2855                         BIDS_FOR_BUYER_2,
2856                         adCounterKeysForCa2,
2857                         adFiltersForCa2,
2858                         false);
2859 
2860         // We add permits to the semaphores when the MWS is called and remove them in the asserts
2861         Semaphore impressionReportingSemaphore = new Semaphore(0);
2862         Semaphore interactionReportingSemaphore = new Semaphore(0);
2863 
2864         List<DBAdData> ads1 = new ArrayList<>();
2865         for (AdData ad : customAudience1.getAds()) {
2866             ads1.add(
2867                     new DBAdData.Builder()
2868                             .setRenderUri(ad.getRenderUri())
2869                             .setMetadata(ad.getMetadata())
2870                             .setAdCounterKeys(ad.getAdCounterKeys())
2871                             .setAdFilters(ad.getAdFilters())
2872                             .build());
2873         }
2874         String customAudience1JsonString =
2875                 CustomAudienceBlobFixture.asJSONObjectString(
2876                         null,
2877                         null,
2878                         customAudience1.getName(),
2879                         customAudience1.getActivationTime(),
2880                         customAudience1.getExpirationTime(),
2881                         customAudience1.getDailyUpdateUri(),
2882                         customAudience1.getBiddingLogicUri(),
2883                         customAudience1.getUserBiddingSignals().toString(),
2884                         DBTrustedBiddingData.fromServiceObject(
2885                                 customAudience1.getTrustedBiddingData()),
2886                         ads1);
2887         List<DBAdData> ads2 = new ArrayList<>();
2888         for (AdData ad : customAudience2.getAds()) {
2889             ads2.add(
2890                     new DBAdData.Builder()
2891                             .setRenderUri(ad.getRenderUri())
2892                             .setMetadata(ad.getMetadata())
2893                             .setAdCounterKeys(ad.getAdCounterKeys())
2894                             .setAdFilters(ad.getAdFilters())
2895                             .build());
2896         }
2897         String customAudience2JsonString =
2898                 CustomAudienceBlobFixture.asJSONObjectString(
2899                         null,
2900                         null,
2901                         customAudience2.getName(),
2902                         customAudience2.getActivationTime(),
2903                         customAudience2.getExpirationTime(),
2904                         customAudience2.getDailyUpdateUri(),
2905                         customAudience2.getBiddingLogicUri(),
2906                         customAudience2.getUserBiddingSignals().toString(),
2907                         DBTrustedBiddingData.fromServiceObject(
2908                                 customAudience2.getTrustedBiddingData()),
2909                         ads2);
2910         HashMap<String, String> remoteCustomAudiencesMap = new HashMap<>();
2911         String customAudience1Id = String.valueOf(customAudience1.hashCode());
2912         String customAudience2Id = String.valueOf(customAudience2.hashCode());
2913         remoteCustomAudiencesMap.put(customAudience1Id, customAudience1JsonString);
2914         remoteCustomAudiencesMap.put(customAudience2Id, customAudience2JsonString);
2915 
2916         MockWebServer server =
2917                 getMockWebServer(
2918                         remoteCustomAudiencesMap,
2919                         getDecisionLogicWithBeacons(),
2920                         getV3BiddingLogicJs(),
2921                         impressionReportingSemaphore,
2922                         interactionReportingSemaphore,
2923                         /* debugReportingLatch= */ null,
2924                         true);
2925 
2926         // TODO(b/289276159): Schedule background fetch if needed once added to fetchCA.
2927         // doNothing()
2928         //      .when(() -> BackgroundFetchJobService.scheduleIfNeeded(any(), any(), anyBoolean()));
2929 
2930         fetchAndJoinCustomAudienceAndAssertSuccess(
2931                 new FetchAndJoinCustomAudienceInput.Builder(
2932                                 CommonFixture.getUri(
2933                                         mLocalhostBuyerDomain.getAuthority(),
2934                                         FETCH_CA_PATH + "/" + customAudience1Id),
2935                                 VALID_OWNER)
2936                         .build());
2937         fetchAndJoinCustomAudienceAndAssertSuccess(
2938                 new FetchAndJoinCustomAudienceInput.Builder(
2939                                 CommonFixture.getUri(
2940                                         mLocalhostBuyerDomain.getAuthority(),
2941                                         FETCH_CA_PATH + "/" + customAudience2Id),
2942                                 VALID_OWNER)
2943                         .build());
2944 
2945         // TODO(b/289276159): Verify background fetch is scheduled if needed once added to fetchCA.
2946         // verify(() -> BackgroundFetchJobService.scheduleIfNeeded(any(), any(), eq(false)))
2947 
2948         long adSelectionId =
2949                 selectAdsAndReport(
2950                         CommonFixture.getUri(
2951                                 mLocalhostBuyerDomain.getAuthority(),
2952                                 AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad3"),
2953                         impressionReportingSemaphore,
2954                         interactionReportingSemaphore);
2955 
2956         // Run Ad Selection, app install ad should now win as it is not filtered and fcap is
2957         // filtered
2958         updateHistogramAndAssertSuccess(adSelectionId, FrequencyCapFilters.AD_EVENT_TYPE_CLICK);
2959         selectAdsAndReport(
2960                 CommonFixture.getUri(
2961                         mLocalhostBuyerDomain.getAuthority(),
2962                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad1"),
2963                 impressionReportingSemaphore,
2964                 interactionReportingSemaphore);
2965 
2966         // 2 fetch CA requests, 10 requests for the auction with both CAs and 9 requests for the
2967         // auctions with one CA.
2968         mockWebServerRule.verifyMockServerRequests(
2969                 server,
2970                 22,
2971                 ImmutableList.of(
2972                         FETCH_CA_PATH + "/" + customAudience1Id,
2973                         FETCH_CA_PATH + "/" + customAudience2Id,
2974                         SELLER_DECISION_LOGIC_URI_PATH,
2975                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1,
2976                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_2,
2977                         BUYER_TRUSTED_SIGNAL_URI_PATH,
2978                         SELLER_TRUSTED_SIGNAL_URI_PATH + SELLER_TRUSTED_SIGNAL_PARAMS),
2979                 mRequestMatcherPrefixMatch);
2980     }
2981 
2982     @Test
2983     public void
testFledgeFlowSuccessWithMockServer_fetchAndJoinCustomAudienceFlow_AppInstallEnabled_FCapDisabled()2984             testFledgeFlowSuccessWithMockServer_fetchAndJoinCustomAudienceFlow_AppInstallEnabled_FCapDisabled()
2985                     throws Exception {
2986         // Only app install is enabled
2987         initClients(
2988                 false,
2989                 true,
2990                 /* frequencyCapFilteringEnabled= */ false,
2991                 /* appInstallFilteringEnabled= */ true,
2992                 true,
2993                 false,
2994                 false,
2995                 false,
2996                 false,
2997                 false,
2998                 false,
2999                 false);
3000         doReturn(LOCALHOST_BUYER)
3001                 .when(mFledgeAuthorizationFilterMock)
3002                 .getAndAssertAdTechFromUriAllowed(any(), any(), any(), anyInt(), anyInt());
3003         doReturn(AdServicesApiConsent.GIVEN)
3004                 .when(mConsentManagerMock)
3005                 .getConsent(AdServicesApiType.FLEDGE);
3006         doReturn(false)
3007                 .when(mConsentManagerMock)
3008                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
3009 
3010         setupAdSelectionConfig();
3011         CustomAudience customAudience1 =
3012                 createCustomAudience(
3013                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
3014 
3015         // Using the same generic key across all ads in the CA
3016         List<Set<Integer>> adCounterKeysForCa2 =
3017                 Arrays.asList(
3018                         Collections.singleton(KeyedFrequencyCapFixture.KEY1),
3019                         Collections.singleton(KeyedFrequencyCapFixture.KEY1),
3020                         Collections.singleton(KeyedFrequencyCapFixture.KEY1));
3021         /* The final ad with the highest bid has only app install filters, the second ad
3022          * with the middle bid has both filters and the first ad with the lowest bid
3023          * in this ca has only an fcap filter.
3024          */
3025         List<AdFilters> adFiltersForCa2 =
3026                 Arrays.asList(
3027                         new AdFilters.Builder()
3028                                 .setFrequencyCapFilters(WIN_ONCE_PER_DAY_KEY1)
3029                                 .build(),
3030                         new AdFilters.Builder()
3031                                 .setAppInstallFilters(CURRENT_APP_FILTER)
3032                                 .setFrequencyCapFilters(WIN_ONCE_PER_DAY_KEY1)
3033                                 .build(),
3034                         new AdFilters.Builder().setAppInstallFilters(CURRENT_APP_FILTER).build());
3035         CustomAudience customAudience2 =
3036                 createCustomAudience(
3037                         mLocalhostBuyerDomain,
3038                         CUSTOM_AUDIENCE_SEQ_2,
3039                         BIDS_FOR_BUYER_2,
3040                         adCounterKeysForCa2,
3041                         adFiltersForCa2,
3042                         false);
3043 
3044         // We add permits to the semaphores when the MWS is called and remove them in the asserts
3045         Semaphore impressionReportingSemaphore = new Semaphore(0);
3046         Semaphore interactionReportingSemaphore = new Semaphore(0);
3047 
3048         // Prepare the custom audiences as json responses we expect from the server.
3049         List<DBAdData> ads1 = new ArrayList<>();
3050         for (AdData ad : customAudience1.getAds()) {
3051             ads1.add(
3052                     new DBAdData.Builder()
3053                             .setRenderUri(ad.getRenderUri())
3054                             .setMetadata(ad.getMetadata())
3055                             .setAdCounterKeys(ad.getAdCounterKeys())
3056                             .setAdFilters(ad.getAdFilters())
3057                             .build());
3058         }
3059         String customAudience1JsonString =
3060                 CustomAudienceBlobFixture.asJSONObjectString(
3061                         null,
3062                         null,
3063                         customAudience1.getName(),
3064                         customAudience1.getActivationTime(),
3065                         customAudience1.getExpirationTime(),
3066                         customAudience1.getDailyUpdateUri(),
3067                         customAudience1.getBiddingLogicUri(),
3068                         customAudience1.getUserBiddingSignals().toString(),
3069                         DBTrustedBiddingData.fromServiceObject(
3070                                 customAudience1.getTrustedBiddingData()),
3071                         ads1);
3072         List<DBAdData> ads2 = new ArrayList<>();
3073         for (AdData ad : customAudience2.getAds()) {
3074             ads2.add(
3075                     new DBAdData.Builder()
3076                             .setRenderUri(ad.getRenderUri())
3077                             .setMetadata(ad.getMetadata())
3078                             .setAdCounterKeys(ad.getAdCounterKeys())
3079                             .setAdFilters(ad.getAdFilters())
3080                             .build());
3081         }
3082         String customAudience2JsonString =
3083                 CustomAudienceBlobFixture.asJSONObjectString(
3084                         null,
3085                         null,
3086                         customAudience2.getName(),
3087                         customAudience2.getActivationTime(),
3088                         customAudience2.getExpirationTime(),
3089                         customAudience2.getDailyUpdateUri(),
3090                         customAudience2.getBiddingLogicUri(),
3091                         customAudience2.getUserBiddingSignals().toString(),
3092                         DBTrustedBiddingData.fromServiceObject(
3093                                 customAudience2.getTrustedBiddingData()),
3094                         ads2);
3095         HashMap<String, String> remoteCustomAudiencesMap = new HashMap<>();
3096         String customAudience1Id = String.valueOf(customAudience1.hashCode());
3097         String customAudience2Id = String.valueOf(customAudience2.hashCode());
3098         remoteCustomAudiencesMap.put(customAudience1Id, customAudience1JsonString);
3099         remoteCustomAudiencesMap.put(customAudience2Id, customAudience2JsonString);
3100 
3101         MockWebServer server =
3102                 getMockWebServer(
3103                         remoteCustomAudiencesMap,
3104                         getDecisionLogicWithBeacons(),
3105                         getV3BiddingLogicJs(),
3106                         impressionReportingSemaphore,
3107                         interactionReportingSemaphore,
3108                         /* debugReportingLatch= */ null,
3109                         true);
3110 
3111         // TODO(b/289276159): Schedule background fetch if needed once added to fetchCA.
3112         // doNothing()
3113         //      .when(() -> BackgroundFetchJobService.scheduleIfNeeded(any(), any(), anyBoolean()));
3114 
3115         fetchAndJoinCustomAudienceAndAssertSuccess(
3116                 new FetchAndJoinCustomAudienceInput.Builder(
3117                                 CommonFixture.getUri(
3118                                         mLocalhostBuyerDomain.getAuthority(),
3119                                         FETCH_CA_PATH + "/" + customAudience1Id),
3120                                 VALID_OWNER)
3121                         .build());
3122         fetchAndJoinCustomAudienceAndAssertSuccess(
3123                 new FetchAndJoinCustomAudienceInput.Builder(
3124                                 CommonFixture.getUri(
3125                                         mLocalhostBuyerDomain.getAuthority(),
3126                                         FETCH_CA_PATH + "/" + customAudience2Id),
3127                                 VALID_OWNER)
3128                         .build());
3129 
3130         // TODO(b/289276159): Verify background fetch is scheduled if needed once added to fetchCA.
3131         // verify(() -> BackgroundFetchJobService.scheduleIfNeeded(any(), any(), eq(false)))
3132 
3133         selectAdsAndReport(
3134                 CommonFixture.getUri(
3135                         mLocalhostBuyerDomain.getAuthority(),
3136                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad3"),
3137                 impressionReportingSemaphore,
3138                 interactionReportingSemaphore);
3139 
3140         registerForAppInstallFiltering();
3141 
3142         // All lowest bid fcap wins since app install is enabled and fcap is disabled
3143         selectAdsAndReport(
3144                 CommonFixture.getUri(
3145                         mLocalhostBuyerDomain.getAuthority(),
3146                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad1"),
3147                 impressionReportingSemaphore,
3148                 interactionReportingSemaphore);
3149 
3150         // 2 fetch CA requests, 10 requests for the auction with both CAs and 9 requests for the
3151         // auctions with one CA.
3152         mockWebServerRule.verifyMockServerRequests(
3153                 server,
3154                 22,
3155                 ImmutableList.of(
3156                         FETCH_CA_PATH + "/" + customAudience1Id,
3157                         FETCH_CA_PATH + "/" + customAudience2Id,
3158                         SELLER_DECISION_LOGIC_URI_PATH,
3159                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1,
3160                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_2,
3161                         BUYER_TRUSTED_SIGNAL_URI_PATH,
3162                         SELLER_TRUSTED_SIGNAL_URI_PATH + SELLER_TRUSTED_SIGNAL_PARAMS),
3163                 mRequestMatcherPrefixMatch);
3164     }
3165 
3166     @Test
testFledgeFlowSuccessWithMockServer_fetchAndJoinCustomAudienceFlow_fcapFilters()3167     public void testFledgeFlowSuccessWithMockServer_fetchAndJoinCustomAudienceFlow_fcapFilters()
3168             throws Exception {
3169         initClients(true, true, false, false, false, false);
3170         doReturn(LOCALHOST_BUYER)
3171                 .when(mFledgeAuthorizationFilterMock)
3172                 .getAndAssertAdTechFromUriAllowed(any(), any(), any(), anyInt(), anyInt());
3173         doReturn(AdServicesApiConsent.GIVEN)
3174                 .when(mConsentManagerMock)
3175                 .getConsent(AdServicesApiType.FLEDGE);
3176         doReturn(false)
3177                 .when(mConsentManagerMock)
3178                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
3179 
3180         setupAdSelectionConfig();
3181         CustomAudience customAudience1 =
3182                 createCustomAudience(
3183                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
3184 
3185         // Using the same generic key across all ads in the CA
3186         List<Set<Integer>> adCounterKeysForCa2 =
3187                 Arrays.asList(
3188                         Collections.singleton(KeyedFrequencyCapFixture.KEY1),
3189                         Collections.singleton(KeyedFrequencyCapFixture.KEY1),
3190                         Collections.singleton(KeyedFrequencyCapFixture.KEY1));
3191         /* The final ad with the highest bid has both fcap and app install filters, the second ad
3192          * with the middle bid has only an app install filter and the first ad with the lowest bid
3193          * in this ca has only a fcap filter.
3194          */
3195         List<AdFilters> adFiltersForCa2 =
3196                 Arrays.asList(
3197                         new AdFilters.Builder()
3198                                 .setFrequencyCapFilters(CLICK_ONCE_PER_DAY_KEY1)
3199                                 .build(),
3200                         new AdFilters.Builder().setAppInstallFilters(CURRENT_APP_FILTER).build(),
3201                         new AdFilters.Builder()
3202                                 .setAppInstallFilters(CURRENT_APP_FILTER)
3203                                 .setFrequencyCapFilters(CLICK_ONCE_PER_DAY_KEY1)
3204                                 .build());
3205         CustomAudience customAudience2 =
3206                 createCustomAudience(
3207                         mLocalhostBuyerDomain,
3208                         CUSTOM_AUDIENCE_SEQ_2,
3209                         BIDS_FOR_BUYER_2,
3210                         adCounterKeysForCa2,
3211                         adFiltersForCa2,
3212                         false);
3213 
3214         // We add permits to the semaphores when the MWS is called and remove them in the asserts
3215         Semaphore impressionReportingSemaphore = new Semaphore(0);
3216         Semaphore interactionReportingSemaphore = new Semaphore(0);
3217 
3218         // Prepare the custom audiences as json responses we expect from the server.
3219         AdDataConversionStrategy adDataConversionStrategy =
3220                 AdDataConversionStrategyFactory.getAdDataConversionStrategy(true, true, true);
3221         List<DBAdData> ads1 = new ArrayList<>();
3222         for (AdData ad : customAudience1.getAds()) {
3223             ads1.add(
3224                     new DBAdData.Builder()
3225                             .setRenderUri(ad.getRenderUri())
3226                             .setMetadata(ad.getMetadata())
3227                             .setAdCounterKeys(ad.getAdCounterKeys())
3228                             .setAdFilters(ad.getAdFilters())
3229                             .build());
3230         }
3231         String customAudience1JsonString =
3232                 CustomAudienceBlobFixture.asJSONObjectString(
3233                         null,
3234                         null,
3235                         customAudience1.getName(),
3236                         customAudience1.getActivationTime(),
3237                         customAudience1.getExpirationTime(),
3238                         customAudience1.getDailyUpdateUri(),
3239                         customAudience1.getBiddingLogicUri(),
3240                         customAudience1.getUserBiddingSignals().toString(),
3241                         DBTrustedBiddingData.fromServiceObject(
3242                                 customAudience1.getTrustedBiddingData()),
3243                         ads1);
3244         List<DBAdData> ads2 = new ArrayList<>();
3245         for (AdData ad : customAudience2.getAds()) {
3246             ads2.add(
3247                     new DBAdData.Builder()
3248                             .setRenderUri(ad.getRenderUri())
3249                             .setMetadata(ad.getMetadata())
3250                             .setAdCounterKeys(ad.getAdCounterKeys())
3251                             .setAdFilters(ad.getAdFilters())
3252                             .build());
3253         }
3254         String customAudience2JsonString =
3255                 CustomAudienceBlobFixture.asJSONObjectString(
3256                         null,
3257                         null,
3258                         customAudience2.getName(),
3259                         customAudience2.getActivationTime(),
3260                         customAudience2.getExpirationTime(),
3261                         customAudience2.getDailyUpdateUri(),
3262                         customAudience2.getBiddingLogicUri(),
3263                         customAudience2.getUserBiddingSignals().toString(),
3264                         DBTrustedBiddingData.fromServiceObject(
3265                                 customAudience2.getTrustedBiddingData()),
3266                         ads2);
3267         HashMap<String, String> remoteCustomAudiencesMap = new HashMap<>();
3268         String customAudience1Id = String.valueOf(customAudience1.hashCode());
3269         String customAudience2Id = String.valueOf(customAudience2.hashCode());
3270         remoteCustomAudiencesMap.put(customAudience1Id, customAudience1JsonString);
3271         remoteCustomAudiencesMap.put(customAudience2Id, customAudience2JsonString);
3272 
3273         MockWebServer server =
3274                 getMockWebServer(
3275                         remoteCustomAudiencesMap,
3276                         getDecisionLogicWithBeacons(),
3277                         getV3BiddingLogicJs(),
3278                         impressionReportingSemaphore,
3279                         interactionReportingSemaphore,
3280                         /* debugReportingLatch= */ null,
3281                         true);
3282 
3283         // TODO(b/289276159): Schedule background fetch if needed once added to fetchCA.
3284         // doNothing()
3285         //      .when(() -> BackgroundFetchJobService.scheduleIfNeeded(any(), any(), anyBoolean()));
3286 
3287         fetchAndJoinCustomAudienceAndAssertSuccess(
3288                 new FetchAndJoinCustomAudienceInput.Builder(
3289                                 CommonFixture.getUri(
3290                                         mLocalhostBuyerDomain.getAuthority(),
3291                                         FETCH_CA_PATH + "/" + customAudience1Id),
3292                                 VALID_OWNER)
3293                         .build());
3294         fetchAndJoinCustomAudienceAndAssertSuccess(
3295                 new FetchAndJoinCustomAudienceInput.Builder(
3296                                 CommonFixture.getUri(
3297                                         mLocalhostBuyerDomain.getAuthority(),
3298                                         FETCH_CA_PATH + "/" + customAudience2Id),
3299                                 VALID_OWNER)
3300                         .build());
3301 
3302         // TODO(b/289276159): Verify background fetch is scheduled if needed once added to fetchCA.
3303         // verify(() -> BackgroundFetchJobService.scheduleIfNeeded(any(), any(), eq(false)))
3304 
3305         // Run Ad Selection no filters active
3306         long adSelectionId =
3307                 selectAdsAndReport(
3308                         CommonFixture.getUri(
3309                                 mLocalhostBuyerDomain.getAuthority(),
3310                                 AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad3"),
3311                         impressionReportingSemaphore,
3312                         interactionReportingSemaphore);
3313 
3314         // Run Ad Selection with just fcap filtering
3315         updateHistogramAndAssertSuccess(adSelectionId, FrequencyCapFilters.AD_EVENT_TYPE_CLICK);
3316         selectAdsAndReport(
3317                 CommonFixture.getUri(
3318                         mLocalhostBuyerDomain.getAuthority(),
3319                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad2"),
3320                 impressionReportingSemaphore,
3321                 interactionReportingSemaphore);
3322 
3323         // 2 fetch CA requests and 20 requests for the 2 auctions with both CAs.
3324         mockWebServerRule.verifyMockServerRequests(
3325                 server,
3326                 22,
3327                 ImmutableList.of(
3328                         FETCH_CA_PATH + "/" + customAudience1Id,
3329                         FETCH_CA_PATH + "/" + customAudience2Id,
3330                         SELLER_DECISION_LOGIC_URI_PATH,
3331                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1,
3332                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_2,
3333                         BUYER_TRUSTED_SIGNAL_URI_PATH,
3334                         SELLER_TRUSTED_SIGNAL_URI_PATH + SELLER_TRUSTED_SIGNAL_PARAMS),
3335                 mRequestMatcherPrefixMatch);
3336     }
3337 
3338     @Test
testFledgeFlowSuccessWithMockServer_crossAppFcapFiltering()3339     public void testFledgeFlowSuccessWithMockServer_crossAppFcapFiltering() throws Exception {
3340         testFledgeFlowSuccessWithCrossAppFcapFiltering(/* shouldUseUnifiedTables= */ false);
3341     }
3342 
3343     @Test
testFledgeFlowSuccessWithMockServer_crossAppFcapFiltering_useUnifiedTables()3344     public void testFledgeFlowSuccessWithMockServer_crossAppFcapFiltering_useUnifiedTables()
3345             throws Exception {
3346         testFledgeFlowSuccessWithCrossAppFcapFiltering(/* shouldUseUnifiedTables= */ true);
3347     }
3348 
testFledgeFlowSuccessWithCrossAppFcapFiltering(boolean shouldUseUnifiedTables)3349     public void testFledgeFlowSuccessWithCrossAppFcapFiltering(boolean shouldUseUnifiedTables)
3350             throws Exception {
3351         doNothing()
3352                 .when(mFledgeAllowListsFilterSpy)
3353                 .assertAppInAllowlist(any(), anyInt(), anyInt());
3354         doReturn(AdServicesApiConsent.GIVEN)
3355                 .when(mConsentManagerMock)
3356                 .getConsent(AdServicesApiType.FLEDGE);
3357         doReturn(false)
3358                 .when(mConsentManagerMock)
3359                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
3360         initClients(
3361                 /* gaUXEnabled= */ true,
3362                 /* registerAdBeaconEnabled= */ true,
3363                 /* cpcBillingEnabled= */ false,
3364                 /* dataVersionHeaderEnabled= */ false,
3365                 shouldUseUnifiedTables,
3366                 /* auctionServerEnabledReportImpression= */ false);
3367 
3368         setupAdSelectionConfig();
3369 
3370         /* Create common CAs for App #1 and App #2 */
3371         // Create CA_1 without filters
3372         CustomAudience customAudience1 =
3373                 createCustomAudience(
3374                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
3375 
3376         // Create CA_2 with 1 non-win filter
3377         List<Set<Integer>> adCounterKeysForCa2 =
3378                 Arrays.asList(Collections.singleton(KeyedFrequencyCapFixture.KEY1));
3379         List<AdFilters> adFiltersForCa2 =
3380                 Arrays.asList(
3381                         new AdFilters.Builder()
3382                                 .setFrequencyCapFilters(CLICK_ONCE_PER_DAY_KEY1)
3383                                 .build());
3384         CustomAudience customAudience2 =
3385                 createCustomAudience(
3386                         mLocalhostBuyerDomain,
3387                         CUSTOM_AUDIENCE_SEQ_2,
3388                         BIDS_FOR_BUYER_2.subList(
3389                                 BIDS_FOR_BUYER_2.size() - 1, BIDS_FOR_BUYER_2.size()),
3390                         adCounterKeysForCa2,
3391                         adFiltersForCa2,
3392                         false);
3393 
3394         // We add permits to the semaphores when the MWS is called and remove them in the asserts
3395         Semaphore impressionReportingSemaphore = new Semaphore(0);
3396         Semaphore interactionReportingSemaphore = new Semaphore(0);
3397 
3398         MockWebServer server =
3399                 getMockWebServer(
3400                         getDecisionLogicWithBeacons(),
3401                         getV3BiddingLogicJs(),
3402                         impressionReportingSemaphore,
3403                         interactionReportingSemaphore,
3404                         true);
3405 
3406         /*
3407          * App #1
3408          * - Join CA_1 and CA_2
3409          * - Run ad selection
3410          * - Update ad counter histogram
3411          * - Leave CA_1 and CA_2
3412          */
3413         String app1PackageName = CommonFixture.TEST_PACKAGE_NAME;
3414 
3415         // Join CA_1 and CA_2
3416         joinCustomAudienceAndAssertSuccess(customAudience1, app1PackageName);
3417         joinCustomAudienceAndAssertSuccess(customAudience2, app1PackageName);
3418 
3419         // Run Ad Selection
3420         long adSelectionId =
3421                 selectAdsAndReport(
3422                         CommonFixture.getUri(
3423                                 mLocalhostBuyerDomain.getAuthority(),
3424                                 AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad1"),
3425                         impressionReportingSemaphore,
3426                         interactionReportingSemaphore,
3427                         app1PackageName);
3428 
3429         // Update ad counter histogram
3430         updateHistogramAndAssertSuccess(
3431                 adSelectionId, FrequencyCapFilters.AD_EVENT_TYPE_CLICK, app1PackageName);
3432 
3433         // Leave CA_1 and CA_2
3434         leaveCustomAudienceAndAssertSuccess(
3435                 app1PackageName,
3436                 AdTechIdentifier.fromString(mLocalhostBuyerDomain.getHost()),
3437                 customAudience1.getName());
3438         leaveCustomAudienceAndAssertSuccess(
3439                 app1PackageName,
3440                 AdTechIdentifier.fromString(mLocalhostBuyerDomain.getHost()),
3441                 customAudience2.getName());
3442 
3443         /*
3444          * App #2
3445          * - Join CA_1 and CA_2
3446          * - Run ad selection
3447          */
3448         String app2PackageName = CommonFixture.TEST_PACKAGE_NAME_1;
3449 
3450         // Join CA_1 and CA_2
3451         joinCustomAudienceAndAssertSuccess(customAudience1, app2PackageName);
3452         joinCustomAudienceAndAssertSuccess(customAudience2, app2PackageName);
3453 
3454         // Run Ad Selection
3455         selectAdsAndReport(
3456                 CommonFixture.getUri(
3457                         mLocalhostBuyerDomain.getAuthority(),
3458                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_1 + "/ad2"),
3459                 impressionReportingSemaphore,
3460                 interactionReportingSemaphore,
3461                 CommonFixture.TEST_PACKAGE_NAME_1);
3462 
3463         /*
3464          * 20 requests for:
3465          * - 10 requests for auction #1 with both CA_1 and CA_2
3466          * - 9 requests for auction #2 with only CA_1 since CA_2 is filtered out
3467          */
3468         mockWebServerRule.verifyMockServerRequests(
3469                 server,
3470                 19,
3471                 ImmutableList.of(
3472                         SELLER_DECISION_LOGIC_URI_PATH,
3473                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1,
3474                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_2,
3475                         BUYER_TRUSTED_SIGNAL_URI_PATH,
3476                         SELLER_TRUSTED_SIGNAL_URI_PATH + SELLER_TRUSTED_SIGNAL_PARAMS),
3477                 mRequestMatcherPrefixMatch);
3478     }
3479 
3480     @Test
testFledgeFlowSuccessWithMockServer_ContextualAdsFlow()3481     public void testFledgeFlowSuccessWithMockServer_ContextualAdsFlow() throws Exception {
3482         // Reinitializing service so default flags are used
3483         // Create an instance of AdSelection Service with real dependencies
3484         mAdSelectionService =
3485                 new AdSelectionServiceImpl(
3486                         mAdSelectionEntryDao,
3487                         mAppInstallDao,
3488                         mCustomAudienceDao,
3489                         mEncodedPayloadDao,
3490                         mFrequencyCapDao,
3491                         mEncryptionKeyDao,
3492                         mEnrollmentDao,
3493                         mAdServicesHttpsClient,
3494                         mDevContextFilterMock,
3495                         mLightweightExecutorService,
3496                         mBackgroundExecutorService,
3497                         mScheduledExecutor,
3498                         mSpyContext,
3499                         mAdServicesLoggerMock,
3500                         DEFAULT_FLAGS,
3501                         CallingAppUidSupplierProcessImpl.create(),
3502                         mFledgeAuthorizationFilterMock,
3503                         mAdSelectionServiceFilterMock,
3504                         mAdFilteringFeatureFactory,
3505                         mConsentManagerMock,
3506                         mMultiCloudSupportStrategy,
3507                         mAdSelectionDebugReportDao,
3508                         mAdIdFetcher,
3509                         mUnusedKAnonSignJoinFactory,
3510                         false,
3511                         mRetryStrategyFactory,
3512                         mConsentedDebugConfigurationGeneratorFactory,
3513                         mEgressConfigurationGenerator,
3514                         CONSOLE_MESSAGE_IN_LOGS_ENABLED);
3515 
3516         doReturn(AdServicesApiConsent.GIVEN)
3517                 .when(mConsentManagerMock)
3518                 .getConsent(AdServicesApiType.FLEDGE);
3519         doReturn(false)
3520                 .when(mConsentManagerMock)
3521                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
3522 
3523         Uri sellerReportingUri = mockWebServerRule.uriForPath(SELLER_REPORTING_PATH);
3524         Uri buyerReportingUri = mockWebServerRule.uriForPath(BUYER_REPORTING_PATH);
3525 
3526         mAdSelectionConfig =
3527                 AdSelectionConfigFixture.anAdSelectionConfigBuilder()
3528                         // Setting empty buyers
3529                         .setCustomAudienceBuyers(ImmutableList.of())
3530                         .setSeller(
3531                                 AdTechIdentifier.fromString(
3532                                         mockWebServerRule
3533                                                 .uriForPath(SELLER_DECISION_LOGIC_URI_PATH)
3534                                                 .getHost()))
3535                         .setDecisionLogicUri(
3536                                 mockWebServerRule.uriForPath(SELLER_DECISION_LOGIC_URI_PATH))
3537                         .setTrustedScoringSignalsUri(
3538                                 mockWebServerRule.uriForPath(SELLER_TRUSTED_SIGNAL_URI_PATH))
3539                         .setPerBuyerSignals(
3540                                 ImmutableMap.of(
3541                                         AdTechIdentifier.fromString(
3542                                                 mLocalhostBuyerDomain.getHost()),
3543                                         AdSelectionSignals.fromString("{\"buyer_signals\":0}")))
3544                         .setPerBuyerSignedContextualAds(createContextualAds())
3545                         .build();
3546 
3547         String decisionLogicJs =
3548                 "function scoreAd(ad, bid, auction_config, seller_signals,"
3549                         + " trusted_scoring_signals, contextual_signal, user_signal,"
3550                         + " custom_audience_signal) { \n"
3551                         + "  return {'status': 0, 'score': bid };\n"
3552                         + "}\n"
3553                         + "function reportResult(ad_selection_config, render_uri, bid,"
3554                         + " contextual_signals) { \n"
3555                         + " return {'status': 0, 'results': {'signals_for_buyer':"
3556                         + " '{\"signals_for_buyer\":1}', 'reporting_uri': '"
3557                         + sellerReportingUri
3558                         + "' } };\n"
3559                         + "}";
3560 
3561         String buyerDecisionLogic =
3562                 "function reportWin(ad_selection_signals, per_buyer_signals,"
3563                         + " signals_for_buyer, contextual_signals, custom_audience_signals) { \n"
3564                         + " return {'status': 0, 'results': {'reporting_uri': '"
3565                         + buyerReportingUri
3566                         + "' } };\n"
3567                         + "}";
3568 
3569         CountDownLatch reportingResponseLatch = new CountDownLatch(2);
3570 
3571         MockWebServer server =
3572                 mockWebServerRule.startMockWebServer(
3573                         request -> {
3574                             String versionHeaderName =
3575                                     JsVersionHelper.getVersionHeaderName(
3576                                             JsVersionHelper.JS_PAYLOAD_TYPE_BUYER_BIDDING_LOGIC_JS);
3577                             long jsVersion =
3578                                     JsVersionRegister.BUYER_BIDDING_LOGIC_VERSION_VERSION_3;
3579                             switch (request.getPath()) {
3580                                 case SELLER_DECISION_LOGIC_URI_PATH:
3581                                     return new MockResponse().setBody(decisionLogicJs);
3582                                 case BUYER_BIDDING_LOGIC_URI_PATH:
3583                                     return new MockResponse().setBody(buyerDecisionLogic);
3584                                 case SELLER_REPORTING_PATH: // Intentional fallthrough
3585                                 case BUYER_REPORTING_PATH:
3586                                     reportingResponseLatch.countDown();
3587                                     return new MockResponse().setResponseCode(200);
3588                             }
3589 
3590                             // The seller params vary based on runtime, so we are returning trusted
3591                             // signals based on correct path prefix
3592                             if (request.getPath()
3593                                     .startsWith(
3594                                             SELLER_TRUSTED_SIGNAL_URI_PATH
3595                                                     + SELLER_TRUSTED_SIGNAL_PARAMS)) {
3596                                 return new MockResponse()
3597                                         .setBody(TRUSTED_SCORING_SIGNALS.toString());
3598                             }
3599                             if (request.getPath().startsWith(BUYER_TRUSTED_SIGNAL_URI_PATH)) {
3600                                 return new MockResponse()
3601                                         .setBody(TRUSTED_BIDDING_SIGNALS.toString());
3602                             }
3603                             return new MockResponse().setResponseCode(404);
3604                         });
3605 
3606         // Run Ad Selection
3607         AdSelectionTestCallback resultsCallback =
3608                 invokeRunAdSelection(
3609                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
3610 
3611         assertTrue(resultsCallback.mIsSuccess);
3612         long resultSelectionId = resultsCallback.mAdSelectionResponse.getAdSelectionId();
3613         assertTrue(mAdSelectionEntryDao.doesAdSelectionIdExist(resultSelectionId));
3614         assertEquals(
3615                 AdDataFixture.getValidRenderUriByBuyer(
3616                         AdTechIdentifier.fromString(
3617                                 mockWebServerRule
3618                                         .uriForPath(
3619                                                 BUYER_BIDDING_LOGIC_URI_PATH
3620                                                         + CommonFixture.VALID_BUYER_1)
3621                                         .getHost()),
3622                         500),
3623                 resultsCallback.mAdSelectionResponse.getRenderUri());
3624 
3625         // Run Report Impression
3626         ReportImpressionInput reportImpressioninput =
3627                 new ReportImpressionInput.Builder()
3628                         .setAdSelectionConfig(mAdSelectionConfig)
3629                         .setAdSelectionId(resultSelectionId)
3630                         .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME)
3631                         .build();
3632 
3633         ReportImpressionTestCallback reportImpressionTestCallback =
3634                 callReportImpression(mAdSelectionService, reportImpressioninput);
3635 
3636         assertTrue(reportImpressionTestCallback.mIsSuccess);
3637         reportingResponseLatch.await();
3638         mockWebServerRule.verifyMockServerRequests(
3639                 server,
3640                 6,
3641                 ImmutableList.of(
3642                         SELLER_DECISION_LOGIC_URI_PATH,
3643                         BUYER_BIDDING_LOGIC_URI_PATH,
3644                         BUYER_REPORTING_PATH,
3645                         SELLER_REPORTING_PATH,
3646                         SELLER_TRUSTED_SIGNAL_URI_PATH + SELLER_TRUSTED_SIGNAL_PARAMS),
3647                 mRequestMatcherPrefixMatch);
3648     }
3649 
3650     @Test
testFledgeFlowSuccessWithAppInstallWithMockServer()3651     public void testFledgeFlowSuccessWithAppInstallWithMockServer() throws Exception {
3652         initClients(true, true, false, false, false, false);
3653         doReturn(AdServicesApiConsent.GIVEN)
3654                 .when(mConsentManagerMock)
3655                 .getConsent(AdServicesApiType.FLEDGE);
3656         doReturn(false)
3657                 .when(mConsentManagerMock)
3658                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
3659 
3660         setupAdSelectionConfig();
3661         String decisionLogicJs = getDecisionLogicWithBeacons();
3662         String biddingLogicJs =
3663                 "function generateBid(ad, auction_signals, per_buyer_signals,"
3664                         + " trusted_bidding_signals, contextual_signals, custom_audience_signals) "
3665                         + "{ \n"
3666                         + "  return {'status': 0, 'ad': ad, 'bid': ad.metadata.result };\n"
3667                         + "}\n"
3668                         + "function reportWin(ad_selection_signals, per_buyer_signals,"
3669                         + " signals_for_buyer ,contextual_signals, custom_audience_signals) {\n"
3670                         + "const beacons = {'click': '"
3671                         + mockWebServerRule.uriForPath(CLICK_BUYER_PATH)
3672                         + "', 'hover': '"
3673                         + mockWebServerRule.uriForPath(HOVER_BUYER_PATH)
3674                         + "'};\n"
3675                         + "registerAdBeacon(beacons);"
3676                         + " return {'status': 0, 'results': {'reporting_uri': '"
3677                         + mockWebServerRule.uriForPath(BUYER_REPORTING_PATH)
3678                         + "' } };\n"
3679                         + "}";
3680 
3681         CustomAudience customAudience1 =
3682                 createCustomAudience(
3683                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
3684 
3685         List<AdFilters> adFiltersForCa2 =
3686                 Arrays.asList(
3687                         null,
3688                         null,
3689                         new AdFilters.Builder().setAppInstallFilters(CURRENT_APP_FILTER).build());
3690         CustomAudience customAudience2 =
3691                 createCustomAudience(
3692                         mLocalhostBuyerDomain,
3693                         CUSTOM_AUDIENCE_SEQ_2,
3694                         BIDS_FOR_BUYER_2,
3695                         EMPTY_AD_COUNTER_KEYS_FOR_BUYER_2,
3696                         adFiltersForCa2,
3697                         false);
3698 
3699         // We add permits to the semaphores when the MWS is called and remove them in the asserts
3700         Semaphore impressionReportingSemaphore = new Semaphore(0);
3701         Semaphore interactionReportingSemaphore = new Semaphore(0);
3702 
3703         MockWebServer server =
3704                 getMockWebServer(
3705                         decisionLogicJs,
3706                         biddingLogicJs,
3707                         impressionReportingSemaphore,
3708                         interactionReportingSemaphore,
3709                         false);
3710 
3711         registerForAppInstallFiltering();
3712 
3713         joinCustomAudienceAndAssertSuccess(customAudience1);
3714         joinCustomAudienceAndAssertSuccess(customAudience2);
3715 
3716         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
3717 
3718         // Run Ad Selection
3719         selectAdsAndReport(
3720                 CommonFixture.getUri(
3721                         mLocalhostBuyerDomain.getAuthority(),
3722                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad2"),
3723                 impressionReportingSemaphore,
3724                 interactionReportingSemaphore);
3725         verifyStandardServerRequests(server);
3726     }
3727 
3728     @Test
testFledgeFlowSuccessWithAppInstallFlagOffWithMockServer()3729     public void testFledgeFlowSuccessWithAppInstallFlagOffWithMockServer() throws Exception {
3730         initClients(
3731                 false, true, false, false, true, false, false, false, false, false, false, false);
3732         doReturn(AdServicesApiConsent.GIVEN)
3733                 .when(mConsentManagerMock)
3734                 .getConsent(AdServicesApiType.FLEDGE);
3735         doReturn(false)
3736                 .when(mConsentManagerMock)
3737                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
3738 
3739         setupAdSelectionConfig();
3740         String decisionLogicJs = getDecisionLogicWithBeacons();
3741         String biddingLogicJs =
3742                 "function generateBid(ad, auction_signals, per_buyer_signals,"
3743                         + " trusted_bidding_signals, contextual_signals, custom_audience_signals) "
3744                         + "{ \n"
3745                         + "  return {'status': 0, 'ad': ad, 'bid': ad.metadata.result };\n"
3746                         + "}\n"
3747                         + "function reportWin(ad_selection_signals, per_buyer_signals,"
3748                         + " signals_for_buyer ,contextual_signals, custom_audience_signals) {\n"
3749                         + "const beacons = {'click': '"
3750                         + mockWebServerRule.uriForPath(CLICK_BUYER_PATH)
3751                         + "', 'hover': '"
3752                         + mockWebServerRule.uriForPath(HOVER_BUYER_PATH)
3753                         + "'};\n"
3754                         + "registerAdBeacon(beacons);"
3755                         + " return {'status': 0, 'results': {'reporting_uri': '"
3756                         + mockWebServerRule.uriForPath(BUYER_REPORTING_PATH)
3757                         + "' } };\n"
3758                         + "}";
3759 
3760         CustomAudience customAudience1 =
3761                 createCustomAudience(
3762                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
3763 
3764         List<AdFilters> filtersForCa2 =
3765                 Arrays.asList(
3766                         null,
3767                         null,
3768                         new AdFilters.Builder().setAppInstallFilters(CURRENT_APP_FILTER).build());
3769         CustomAudience customAudience2 =
3770                 createCustomAudience(
3771                         mLocalhostBuyerDomain,
3772                         CUSTOM_AUDIENCE_SEQ_2,
3773                         BIDS_FOR_BUYER_2,
3774                         EMPTY_AD_COUNTER_KEYS_FOR_BUYER_2,
3775                         filtersForCa2,
3776                         false);
3777 
3778         // We add permits to the semaphores when the MWS is called and remove them in the asserts
3779         Semaphore impressionReportingSemaphore = new Semaphore(0);
3780         Semaphore interactionReportingSemaphore = new Semaphore(0);
3781 
3782         MockWebServer server =
3783                 getMockWebServer(
3784                         decisionLogicJs,
3785                         biddingLogicJs,
3786                         impressionReportingSemaphore,
3787                         interactionReportingSemaphore,
3788                         false);
3789 
3790         // Registers the test app for app install filtering
3791         // Should fail since flag is turned off
3792         // Everything else should pass
3793         AppInstallResultCapturingCallback callback = invokeSetAppInstallAdvertisers();
3794         assertFalse(callback.isSuccess());
3795         assertTrue(callback.getException() instanceof IllegalStateException);
3796 
3797         joinCustomAudienceAndAssertSuccess(customAudience1);
3798         joinCustomAudienceAndAssertSuccess(customAudience2);
3799 
3800         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
3801 
3802         // CA 2's ad3 should win even though it tried to filter itself
3803         selectAdsAndReport(
3804                 CommonFixture.getUri(
3805                         mLocalhostBuyerDomain.getAuthority(),
3806                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad3"),
3807                 impressionReportingSemaphore,
3808                 interactionReportingSemaphore);
3809         verifyStandardServerRequests(server);
3810     }
3811 
3812     @Test
testFledgeFlowSuccessWithRevokedUserConsentForApp()3813     public void testFledgeFlowSuccessWithRevokedUserConsentForApp() throws Exception {
3814         doReturn(AdServicesApiConsent.GIVEN)
3815                 .when(mConsentManagerMock)
3816                 .getConsent(AdServicesApiType.FLEDGE);
3817         // Allow the first join call to succeed so that we can verify the rest of the flow works
3818         when(mConsentManagerMock.isFledgeConsentRevokedForAppAfterSettingFledgeUse(any()))
3819                 .thenReturn(false)
3820                 .thenReturn(true);
3821 
3822         setupAdSelectionConfig();
3823         String decisionLogicJs = getDecisionLogicWithBeacons();
3824         String biddingLogicJs = getBiddingLogicWithBeacons();
3825 
3826         CustomAudience customAudience1 =
3827                 createCustomAudience(
3828                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
3829 
3830         CustomAudience customAudience2 =
3831                 createCustomAudience(
3832                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, BIDS_FOR_BUYER_2);
3833 
3834         // We add permits to the semaphores when the MWS is called and remove them in the asserts
3835         Semaphore impressionReportingSemaphore = new Semaphore(0);
3836         Semaphore interactionReportingSemaphore = new Semaphore(0);
3837 
3838         MockWebServer server =
3839                 mockWebServerRule.startMockWebServer(
3840                         request -> {
3841                             switch (request.getPath()) {
3842                                 case SELLER_DECISION_LOGIC_URI_PATH:
3843                                     return new MockResponse().setBody(decisionLogicJs);
3844                                 case BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1:
3845                                     return new MockResponse().setBody(biddingLogicJs);
3846                                 case BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_2:
3847                                     throw new IllegalStateException(
3848                                             "This should not be called without user consent");
3849                                 case CLICK_SELLER_PATH: // Intentional fallthrough
3850                                 case CLICK_BUYER_PATH:
3851                                     interactionReportingSemaphore.release();
3852                                     return new MockResponse().setResponseCode(200);
3853                                 case SELLER_REPORTING_PATH: // Intentional fallthrough
3854                                 case BUYER_REPORTING_PATH:
3855                                     impressionReportingSemaphore.release();
3856                                     return new MockResponse().setResponseCode(200);
3857                             }
3858 
3859                             // The seller params vary based on runtime, so we are returning trusted
3860                             // signals based on correct path prefix
3861                             if (request.getPath()
3862                                     .startsWith(
3863                                             SELLER_TRUSTED_SIGNAL_URI_PATH
3864                                                     + SELLER_TRUSTED_SIGNAL_PARAMS)) {
3865                                 return new MockResponse()
3866                                         .setBody(TRUSTED_SCORING_SIGNALS.toString());
3867                             }
3868                             if (request.getPath().startsWith(BUYER_TRUSTED_SIGNAL_URI_PATH)) {
3869                                 return new MockResponse()
3870                                         .setBody(TRUSTED_BIDDING_SIGNALS.toString());
3871                             }
3872                             return new MockResponse().setResponseCode(404);
3873                         });
3874 
3875         joinCustomAudienceAndAssertSuccess(customAudience1);
3876         joinCustomAudienceAndAssertSuccess(customAudience2);
3877 
3878         // Run Ad Selection
3879         selectAdsAndReport(
3880                 CommonFixture.getUri(
3881                         mLocalhostBuyerDomain.getAuthority(),
3882                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_1 + "/ad2"),
3883                 impressionReportingSemaphore,
3884                 interactionReportingSemaphore);
3885         mockWebServerRule.verifyMockServerRequests(
3886                 server,
3887                 9,
3888                 ImmutableList.of(
3889                         SELLER_DECISION_LOGIC_URI_PATH,
3890                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1,
3891                         BUYER_TRUSTED_SIGNAL_URI_PATH,
3892                         SELLER_TRUSTED_SIGNAL_URI_PATH + SELLER_TRUSTED_SIGNAL_PARAMS),
3893                 mRequestMatcherPrefixMatch);
3894     }
3895 
3896     @Test
testFledgeFlowSuccessWithRevokedUserConsentForFledge()3897     public void testFledgeFlowSuccessWithRevokedUserConsentForFledge() throws Exception {
3898         doReturn(AdServicesApiConsent.REVOKED).when(mConsentManagerMock).getConsent();
3899         doReturn(true)
3900                 .when(mConsentManagerMock)
3901                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
3902         doThrow(new FilterException(new ConsentManager.RevokedConsentException()))
3903                 .when(mAdSelectionServiceFilterMock)
3904                 .filterRequest(
3905                         any(),
3906                         anyString(),
3907                         anyBoolean(),
3908                         anyBoolean(),
3909                         anyInt(),
3910                         anyInt(),
3911                         any(),
3912                         any());
3913 
3914         setupAdSelectionConfig();
3915 
3916         CustomAudience customAudience1 =
3917                 createCustomAudience(
3918                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
3919 
3920         CustomAudience customAudience2 =
3921                 createCustomAudience(
3922                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, BIDS_FOR_BUYER_2);
3923 
3924         MockWebServer server =
3925                 mockWebServerRule.startMockWebServer(
3926                         request -> {
3927                             throw new IllegalStateException(
3928                                     "No calls should be made without user consent");
3929                         });
3930 
3931         joinCustomAudienceAndAssertSuccess(customAudience1);
3932         joinCustomAudienceAndAssertSuccess(customAudience2);
3933 
3934         // Run Ad Selection
3935         AdSelectionTestCallback resultsCallback =
3936                 invokeRunAdSelection(
3937                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
3938 
3939         assertTrue(resultsCallback.mIsSuccess);
3940         long resultSelectionId = resultsCallback.mAdSelectionResponse.getAdSelectionId();
3941         assertFalse(mAdSelectionEntryDao.doesAdSelectionIdExist(resultSelectionId));
3942         assertEquals(Uri.EMPTY, resultsCallback.mAdSelectionResponse.getRenderUri());
3943 
3944         reportImpressionAndAssertSuccess(resultSelectionId);
3945         reportInteractionAndAssertSuccess(resultsCallback);
3946 
3947         mockWebServerRule.verifyMockServerRequests(
3948                 server, 0, ImmutableList.of(), mRequestMatcherPrefixMatch);
3949     }
3950 
3951     @Test
testFledgeFlowSuccessWithOneCAWithNegativeBidsWithMockServer()3952     public void testFledgeFlowSuccessWithOneCAWithNegativeBidsWithMockServer() throws Exception {
3953         doReturn(AdServicesApiConsent.GIVEN)
3954                 .when(mConsentManagerMock)
3955                 .getConsent(AdServicesApiType.FLEDGE);
3956         doReturn(false)
3957                 .when(mConsentManagerMock)
3958                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
3959 
3960         setupAdSelectionConfig();
3961         String decisionLogicJs = getDecisionLogicWithBeacons();
3962         String biddingLogicJs = getBiddingLogicWithBeacons();
3963 
3964         CustomAudience customAudience1 =
3965                 createCustomAudience(
3966                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
3967 
3968         CustomAudience customAudience2 =
3969                 createCustomAudience(mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_2, INVALID_BIDS);
3970 
3971         // We add permits to the semaphores when the MWS is called and remove them in the asserts
3972         Semaphore impressionReportingSemaphore = new Semaphore(0);
3973         Semaphore interactionReportingSemaphore = new Semaphore(0);
3974 
3975         MockWebServer server =
3976                 getMockWebServer(
3977                         decisionLogicJs,
3978                         biddingLogicJs,
3979                         impressionReportingSemaphore,
3980                         interactionReportingSemaphore,
3981                         false);
3982 
3983         joinCustomAudienceAndAssertSuccess(customAudience1);
3984         joinCustomAudienceAndAssertSuccess(customAudience2);
3985 
3986         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
3987 
3988         // Run Ad Selection
3989         AdSelectionTestCallback resultsCallback =
3990                 invokeRunAdSelection(
3991                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
3992 
3993         assertTrue(resultsCallback.mIsSuccess);
3994         long resultSelectionId = resultsCallback.mAdSelectionResponse.getAdSelectionId();
3995         assertTrue(mAdSelectionEntryDao.doesAdSelectionIdExist(resultSelectionId));
3996 
3997         // Expect that ad from buyer 1 won since buyer 2 had negative bids
3998         assertEquals(
3999                 CommonFixture.getUri(
4000                         mLocalhostBuyerDomain.getAuthority(),
4001                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_1 + "/ad2"),
4002                 resultsCallback.mAdSelectionResponse.getRenderUri());
4003 
4004         reportImpressionAndAssertSuccess(resultsCallback.mAdSelectionResponse.getAdSelectionId());
4005 
4006         reportInteractionAndAssertSuccess(resultsCallback);
4007 
4008         /* We add a permit on every call received by the MockWebServer and remove them in the
4009          * tryAcquires below. If there are any left over it means that there were extra calls to the
4010          * mockserver.
4011          */
4012         assertTrue(impressionReportingSemaphore.tryAcquire(2, 10, TimeUnit.SECONDS));
4013         assertTrue(interactionReportingSemaphore.tryAcquire(2, 10, TimeUnit.SECONDS));
4014         assertEquals(
4015                 "Extra calls made to MockWebServer",
4016                 0,
4017                 impressionReportingSemaphore.availablePermits());
4018         assertEquals(
4019                 "Extra calls made to MockWebServer",
4020                 0,
4021                 interactionReportingSemaphore.availablePermits());
4022 
4023         mockWebServerRule.verifyMockServerRequests(
4024                 server,
4025                 10,
4026                 ImmutableList.of(
4027                         SELLER_DECISION_LOGIC_URI_PATH,
4028                         BUYER_BIDDING_LOGIC_URI_PATH,
4029                         BUYER_TRUSTED_SIGNAL_URI_PATH,
4030                         SELLER_TRUSTED_SIGNAL_URI_PATH + SELLER_TRUSTED_SIGNAL_PARAMS),
4031                 mRequestMatcherPrefixMatch);
4032     }
4033 
4034     @Test
testFledgeFlowFailsWithOnlyCANegativeBidsWithMockServer()4035     public void testFledgeFlowFailsWithOnlyCANegativeBidsWithMockServer() throws Exception {
4036         doReturn(AdServicesApiConsent.GIVEN)
4037                 .when(mConsentManagerMock)
4038                 .getConsent(AdServicesApiType.FLEDGE);
4039         doReturn(false)
4040                 .when(mConsentManagerMock)
4041                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
4042 
4043         setupAdSelectionConfig();
4044         String decisionLogicJs = getDecisionLogicWithBeacons();
4045         String biddingLogicJs = getBiddingLogicWithBeacons();
4046 
4047         CustomAudience customAudience1 = createCustomAudience(mLocalhostBuyerDomain, INVALID_BIDS);
4048 
4049         MockWebServer server =
4050                 mockWebServerRule.startMockWebServer(
4051                         request -> {
4052                             switch (request.getPath()) {
4053                                 case SELLER_DECISION_LOGIC_URI_PATH:
4054                                     return new MockResponse().setBody(decisionLogicJs);
4055                                 case BUYER_BIDDING_LOGIC_URI_PATH:
4056                                     return new MockResponse().setBody(biddingLogicJs);
4057                             }
4058 
4059                             // The seller params vary based on runtime, so we are returning trusted
4060                             // signals based on correct path prefix
4061                             if (request.getPath()
4062                                     .startsWith(
4063                                             SELLER_TRUSTED_SIGNAL_URI_PATH
4064                                                     + SELLER_TRUSTED_SIGNAL_PARAMS)) {
4065                                 return new MockResponse()
4066                                         .setBody(TRUSTED_SCORING_SIGNALS.toString());
4067                             }
4068                             if (request.getPath().startsWith(BUYER_TRUSTED_SIGNAL_URI_PATH)) {
4069                                 return new MockResponse()
4070                                         .setBody(TRUSTED_BIDDING_SIGNALS.toString());
4071                             }
4072                             return new MockResponse().setResponseCode(404);
4073                         });
4074 
4075         // Join custom audience
4076         joinCustomAudienceAndAssertSuccess(customAudience1);
4077 
4078         // Run Ad Selection
4079         AdSelectionTestCallback resultsCallback =
4080                 invokeRunAdSelection(
4081                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
4082 
4083         assertFalse(resultsCallback.mIsSuccess);
4084         assertNull(resultsCallback.mAdSelectionResponse);
4085 
4086         // Run Report Impression with random ad selection id
4087         ReportImpressionInput input =
4088                 new ReportImpressionInput.Builder()
4089                         .setAdSelectionConfig(mAdSelectionConfig)
4090                         .setAdSelectionId(1)
4091                         .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME)
4092                         .build();
4093 
4094         ReportImpressionTestCallback reportImpressionTestCallback =
4095                 callReportImpression(mAdSelectionService, input);
4096 
4097         assertFalse(reportImpressionTestCallback.mIsSuccess);
4098 
4099         // Run Report Interaction with random ad selection id
4100         ReportInteractionInput reportInteractionInput =
4101                 new ReportInteractionInput.Builder()
4102                         .setAdSelectionId(1)
4103                         .setInteractionKey(CLICK_INTERACTION)
4104                         .setInteractionData(INTERACTION_DATA)
4105                         .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME)
4106                         .setReportingDestinations(BUYER_DESTINATION | SELLER_DESTINATION)
4107                         .build();
4108 
4109         ReportInteractionTestCallback reportInteractionTestCallback =
4110                 callReportInteraction(mAdSelectionService, reportInteractionInput);
4111         assertFalse(reportInteractionTestCallback.mIsSuccess);
4112 
4113         mockWebServerRule.verifyMockServerRequests(
4114                 server,
4115                 2,
4116                 ImmutableList.of(BUYER_BIDDING_LOGIC_URI_PATH, BUYER_TRUSTED_SIGNAL_URI_PATH),
4117                 mRequestMatcherPrefixMatch);
4118     }
4119 
4120     @Test
testSelectAdsWithFilterExceptionFromNullPointerExceptionDoesNotCrash()4121     public void testSelectAdsWithFilterExceptionFromNullPointerExceptionDoesNotCrash()
4122             throws Exception {
4123         initClients(false, false, false, false, false, false);
4124         setupConsentGivenStubs();
4125         setupAdSelectionConfig();
4126 
4127         doThrow(new FilterException(new NullPointerException("Intentional test failure")))
4128                 .when(mAdSelectionServiceFilterMock)
4129                 .filterRequest(
4130                         any(),
4131                         anyString(),
4132                         anyBoolean(),
4133                         anyBoolean(),
4134                         anyInt(),
4135                         anyInt(),
4136                         any(),
4137                         any());
4138 
4139         // Run Ad Selection
4140         AdSelectionTestCallback resultsCallback =
4141                 invokeRunAdSelection(
4142                         mAdSelectionService, mAdSelectionConfig, CommonFixture.TEST_PACKAGE_NAME);
4143 
4144         assertWithMessage("Callback success").that(resultsCallback.mIsSuccess).isFalse();
4145         assertWithMessage("Callback AdSelectionResponse")
4146                 .that(resultsCallback.mAdSelectionResponse)
4147                 .isNull();
4148         assertWithMessage("Callback FledgeErrorResponse")
4149                 .that(resultsCallback.mFledgeErrorResponse)
4150                 .isNotNull();
4151         assertWithMessage("Callback FledgeErrorResponse")
4152                 .that(resultsCallback.mFledgeErrorResponse.getStatusCode())
4153                 .isEqualTo(AdServicesStatusUtils.STATUS_INTERNAL_ERROR);
4154     }
4155 
updateHistogramAndAssertSuccess(long adSelectionId, int adEventType)4156     private void updateHistogramAndAssertSuccess(long adSelectionId, int adEventType)
4157             throws InterruptedException {
4158         updateHistogramAndAssertSuccess(
4159                 adSelectionId, adEventType, CommonFixture.TEST_PACKAGE_NAME);
4160     }
4161 
updateHistogramAndAssertSuccess( long adSelectionId, int adEventType, String callerAppPackageName)4162     private void updateHistogramAndAssertSuccess(
4163             long adSelectionId, int adEventType, String callerAppPackageName)
4164             throws InterruptedException {
4165         UpdateAdCounterHistogramInput inputParams =
4166                 new UpdateAdCounterHistogramInput.Builder(
4167                                 adSelectionId,
4168                                 adEventType,
4169                                 AdTechIdentifier.fromString(mLocalhostBuyerDomain.getHost()),
4170                                 callerAppPackageName)
4171                         .build();
4172         CountDownLatch callbackLatch = new CountDownLatch(1);
4173         UpdateAdCounterHistogramWorkerTest.UpdateAdCounterHistogramTestCallback callback =
4174                 new UpdateAdCounterHistogramWorkerTest.UpdateAdCounterHistogramTestCallback(
4175                         callbackLatch);
4176 
4177         mAdSelectionService.updateAdCounterHistogram(inputParams, callback);
4178 
4179         assertThat(callbackLatch.await(5, TimeUnit.SECONDS)).isTrue();
4180 
4181         assertWithMessage("Callback failed, was: %s", callback).that(callback.isSuccess()).isTrue();
4182     }
4183 
selectAdsAndReport( Uri winningRenderUri, Semaphore impressionReportingSemaphore, Semaphore interactionReportingSemaphore)4184     private long selectAdsAndReport(
4185             Uri winningRenderUri,
4186             Semaphore impressionReportingSemaphore,
4187             Semaphore interactionReportingSemaphore)
4188             throws Exception {
4189         return selectAdsAndReport(
4190                 winningRenderUri,
4191                 impressionReportingSemaphore,
4192                 interactionReportingSemaphore,
4193                 CommonFixture.TEST_PACKAGE_NAME);
4194     }
4195 
selectAdsAndReport( Uri winningRenderUri, Semaphore impressionReportingSemaphore, Semaphore interactionReportingSemaphore, String callerAppPackageName)4196     private long selectAdsAndReport(
4197             Uri winningRenderUri,
4198             Semaphore impressionReportingSemaphore,
4199             Semaphore interactionReportingSemaphore,
4200             String callerAppPackageName)
4201             throws Exception {
4202         AdSelectionTestCallback resultsCallback =
4203                 invokeRunAdSelection(mAdSelectionService, mAdSelectionConfig, callerAppPackageName);
4204 
4205         assertTrue(resultsCallback.mIsSuccess);
4206         long resultSelectionId = resultsCallback.mAdSelectionResponse.getAdSelectionId();
4207         assertTrue(mAdSelectionEntryDao.doesAdSelectionIdExist(resultSelectionId));
4208         assertEquals(winningRenderUri, resultsCallback.mAdSelectionResponse.getRenderUri());
4209 
4210         reportImpressionAndAssertSuccess(resultSelectionId, callerAppPackageName);
4211         reportInteractionAndAssertSuccess(resultsCallback, callerAppPackageName);
4212 
4213         /* We add a permit on every call received by the MockWebServer and remove them in the
4214          * tryAcquires below. If there are any left over it means that there were extra calls to the
4215          * mockserver.
4216          */
4217         assertTrue(impressionReportingSemaphore.tryAcquire(2, 10, TimeUnit.SECONDS));
4218         assertTrue(interactionReportingSemaphore.tryAcquire(2, 10, TimeUnit.SECONDS));
4219         assertEquals(
4220                 "Extra calls made to MockWebServer",
4221                 0,
4222                 impressionReportingSemaphore.availablePermits());
4223         assertEquals(
4224                 "Extra calls made to MockWebServer",
4225                 0,
4226                 interactionReportingSemaphore.availablePermits());
4227         return resultSelectionId;
4228     }
4229 
verifyStandardServerRequests(MockWebServer server)4230     void verifyStandardServerRequests(MockWebServer server) {
4231         /*
4232          * We expect ten requests:
4233          * 2 bidding logic requests (one for each CA)
4234          * 2 decision logic requests (scoring and reporting)
4235          * 1 trusted bidding signals requests
4236          * 1 trusted seller signals request
4237          * 1 reportWin
4238          * 1 reportResult
4239          * 1 buyer click interaction report
4240          * 1 seller click interaction report
4241          */
4242         mockWebServerRule.verifyMockServerRequests(
4243                 server,
4244                 10,
4245                 ImmutableList.of(
4246                         SELLER_DECISION_LOGIC_URI_PATH,
4247                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1,
4248                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_2,
4249                         BUYER_TRUSTED_SIGNAL_URI_PATH,
4250                         SELLER_TRUSTED_SIGNAL_URI_PATH + SELLER_TRUSTED_SIGNAL_PARAMS),
4251                 mRequestMatcherPrefixMatch);
4252     }
4253 
registerForAppInstallFiltering()4254     private void registerForAppInstallFiltering() throws RemoteException, InterruptedException {
4255         setAppInstallAdvertisers(
4256                 Collections.singleton(
4257                         AdTechIdentifier.fromString(mLocalhostBuyerDomain.getHost())));
4258     }
4259 
deregisterForAppInstallFiltering()4260     private void deregisterForAppInstallFiltering() throws RemoteException, InterruptedException {
4261         setAppInstallAdvertisers(Collections.EMPTY_SET);
4262     }
4263 
setAppInstallAdvertisers(Set<AdTechIdentifier> advertisers)4264     private void setAppInstallAdvertisers(Set<AdTechIdentifier> advertisers)
4265             throws RemoteException, InterruptedException {
4266         SetAppInstallAdvertisersInput setAppInstallAdvertisersInput =
4267                 new SetAppInstallAdvertisersInput.Builder()
4268                         .setAdvertisers(advertisers)
4269                         .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME)
4270                         .build();
4271         AppInstallResultCapturingCallback appInstallCallback =
4272                 invokeSetAppInstallAdvertisers(setAppInstallAdvertisersInput);
4273         assertTrue(
4274                 "App Install call failed with: " + appInstallCallback.getException(),
4275                 appInstallCallback.isSuccess());
4276     }
4277 
invokeSetAppInstallAdvertisers()4278     private AppInstallResultCapturingCallback invokeSetAppInstallAdvertisers()
4279             throws RemoteException, InterruptedException {
4280         Set<AdTechIdentifier> advertisers =
4281                 Collections.singleton(AdTechIdentifier.fromString(mLocalhostBuyerDomain.getHost()));
4282         SetAppInstallAdvertisersInput setAppInstallAdvertisersInput =
4283                 new SetAppInstallAdvertisersInput.Builder()
4284                         .setAdvertisers(advertisers)
4285                         .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME)
4286                         .build();
4287         return invokeSetAppInstallAdvertisers(setAppInstallAdvertisersInput);
4288     }
4289 
invokeSetAppInstallAdvertisers( SetAppInstallAdvertisersInput input)4290     private AppInstallResultCapturingCallback invokeSetAppInstallAdvertisers(
4291             SetAppInstallAdvertisersInput input) throws RemoteException, InterruptedException {
4292         CountDownLatch appInstallDone = new CountDownLatch(1);
4293         AppInstallResultCapturingCallback appInstallCallback =
4294                 new AppInstallResultCapturingCallback(appInstallDone);
4295         mAdSelectionService.setAppInstallAdvertisers(input, appInstallCallback);
4296         assertTrue(appInstallDone.await(5, TimeUnit.SECONDS));
4297         return appInstallCallback;
4298     }
4299 
getV3BiddingLogicJs()4300     private String getV3BiddingLogicJs() {
4301         return "function generateBid(custom_audience, auction_signals, per_buyer_signals,\n"
4302                 + "    trusted_bidding_signals, contextual_signals) {\n"
4303                 + "    const ads = custom_audience.ads;\n"
4304                 + "    let result = null;\n"
4305                 + "    for (const ad of ads) {\n"
4306                 + "        if (!result || ad.metadata.result > result.metadata.result) {\n"
4307                 + "            result = ad;\n"
4308                 + "        }\n"
4309                 + "    }\n"
4310                 + "    return { 'status': 0, 'ad': result, 'bid': result.metadata.result, "
4311                 + "'render': result.render_uri };\n"
4312                 + "}\n"
4313                 + "function reportWin(ad_selection_signals, per_buyer_signals,"
4314                 + " signals_for_buyer ,contextual_signals, custom_audience_signals) {\n"
4315                 + "const beacons = {'click': '"
4316                 + mockWebServerRule.uriForPath(CLICK_BUYER_PATH)
4317                 + "', 'hover': '"
4318                 + mockWebServerRule.uriForPath(HOVER_BUYER_PATH)
4319                 + "'};\n"
4320                 + "registerAdBeacon(beacons);"
4321                 + " return {'status': 0, 'results': {'reporting_uri': '"
4322                 + mockWebServerRule.uriForPath(BUYER_REPORTING_PATH)
4323                 + "' } };\n"
4324                 + "}";
4325     }
4326 
getBiddingLogicJs()4327     private String getBiddingLogicJs() {
4328         return "function generateBid(ad, auction_signals, per_buyer_signals,"
4329                 + " trusted_bidding_signals, contextual_signals, custom_audience_signals) { \n"
4330                 + "  return {'status': 0, 'ad': ad, 'bid': ad.metadata.result };\n"
4331                 + "}\n"
4332                 + "function reportWin(ad_selection_signals, per_buyer_signals,"
4333                 + " signals_for_buyer, contextual_signals, custom_audience_signals) { \n"
4334                 + " return {'status': 0, 'results': {'reporting_uri': '"
4335                 + mockWebServerRule.uriForPath(BUYER_REPORTING_PATH)
4336                 + "' } };\n"
4337                 + "}";
4338     }
4339 
getBiddingLogicJsWithAdCost()4340     private String getBiddingLogicJsWithAdCost() {
4341         return "function generateBid(ad, auction_signals, per_buyer_signals,"
4342                 + " trusted_bidding_signals, contextual_signals, custom_audience_signals) { \n"
4343                 + "  return {'status': 0, 'ad': ad, 'bid': ad.metadata.result, 'adCost':"
4344                 + " ad.metadata.adCost };\n"
4345                 + "}\n"
4346                 + "\n"
4347                 + "function reportWin(ad_selection_signals, per_buyer_signals,"
4348                 + " signals_for_buyer,\n"
4349                 + "    contextual_signals, custom_audience_reporting_signals) {\n"
4350                 + "    let reporting_address = '"
4351                 + mockWebServerRule.uriForPath(BUYER_REPORTING_PATH)
4352                 + "';\n"
4353                 + "    return {'status': 0, 'results': {'reporting_uri':\n"
4354                 + "                reporting_address + '?adCost=' + contextual_signals.adCost} };\n"
4355                 + "}";
4356     }
4357 
getDecisionLogicJs()4358     private String getDecisionLogicJs() {
4359         return "function scoreAd(ad, bid, auction_config, seller_signals,"
4360                 + " trusted_scoring_signals, contextual_signal, user_signal,"
4361                 + " custom_audience_signal) { \n"
4362                 + "  return {'status': 0, 'score': bid };\n"
4363                 + "}\n"
4364                 + "function reportResult(ad_selection_config, render_uri, bid,"
4365                 + " contextual_signals) { \n"
4366                 + " return {'status': 0, 'results': {'signals_for_buyer':"
4367                 + " '{\"signals_for_buyer\":1}', 'reporting_uri': '"
4368                 + mockWebServerRule.uriForPath(SELLER_REPORTING_PATH)
4369                 + "' } };\n"
4370                 + "}";
4371     }
4372 
getDecisionLogicJsWithDebugReporting(String reportWinUrl, String reportLossUrl)4373     private String getDecisionLogicJsWithDebugReporting(String reportWinUrl, String reportLossUrl) {
4374         return "function scoreAd(ad, bid, auction_config, seller_signals,"
4375                 + " trusted_scoring_signals, contextual_signal, user_signal,"
4376                 + " custom_audience_signal) { \n"
4377                 + "  forDebuggingOnly.reportAdAuctionWin('"
4378                 + reportWinUrl
4379                 + "');"
4380                 + "  forDebuggingOnly.reportAdAuctionLoss('"
4381                 + reportLossUrl
4382                 + "');"
4383                 + "  return {'status': 0, 'score': bid };\n"
4384                 + "}";
4385     }
4386 
getBiddingLogicWithBeacons()4387     private String getBiddingLogicWithBeacons() {
4388         return "function generateBid(ad, auction_signals, per_buyer_signals,"
4389                 + " trusted_bidding_signals, contextual_signals, custom_audience_signals) { \n"
4390                 + "  return {'status': 0, 'ad': ad, 'bid': ad.metadata.result };\n"
4391                 + "}\n"
4392                 + "function reportWin(ad_selection_signals, per_buyer_signals,"
4393                 + " signals_for_buyer ,contextual_signals, custom_audience_signals) {\n"
4394                 + "const beacons = {'click': '"
4395                 + mockWebServerRule.uriForPath(CLICK_BUYER_PATH)
4396                 + "', 'hover': '"
4397                 + mockWebServerRule.uriForPath(HOVER_BUYER_PATH)
4398                 + "'};\n"
4399                 + "registerAdBeacon(beacons);"
4400                 + " return {'status': 0, 'results': {'reporting_uri': '"
4401                 + mockWebServerRule.uriForPath(BUYER_REPORTING_PATH)
4402                 + "' } };\n"
4403                 + "}";
4404     }
4405 
getBiddingLogicWithDebugReporting(String reportWinUrl, String reportLossUrl)4406     private String getBiddingLogicWithDebugReporting(String reportWinUrl, String reportLossUrl) {
4407         return "function generateBid(custom_audience, auction_signals, per_buyer_signals,\n"
4408                 + "    trusted_bidding_signals, contextual_signals) {\n"
4409                 + "    const ads = custom_audience.ads;\n"
4410                 + "    let result = null;\n"
4411                 + "    for (const ad of ads) {\n"
4412                 + "        if (!result || ad.metadata.result > result.metadata.result) {\n"
4413                 + "            result = ad;\n"
4414                 + "            forDebuggingOnly.reportAdAuctionWin('"
4415                 + reportWinUrl
4416                 + "');"
4417                 + "            forDebuggingOnly.reportAdAuctionLoss('"
4418                 + reportLossUrl
4419                 + "');"
4420                 + "        }\n"
4421                 + "    }\n"
4422                 + "    return { 'status': 0, 'ad': result, 'bid': result.metadata.result, "
4423                 + "'render': result.render_uri };\n"
4424                 + "}";
4425     }
4426 
getDecisionLogicWithBeacons()4427     private String getDecisionLogicWithBeacons() {
4428         return "function scoreAd(ad, bid, auction_config, seller_signals,"
4429                 + " trusted_scoring_signals, contextual_signal, user_signal,"
4430                 + " custom_audience_signal) { \n"
4431                 + "  return {'status': 0, 'score': bid };\n"
4432                 + "}\n"
4433                 + "function reportResult(ad_selection_config, render_uri, bid,"
4434                 + " contextual_signals) {\n"
4435                 + "const beacons = {'click': '"
4436                 + mockWebServerRule.uriForPath(CLICK_SELLER_PATH)
4437                 + "', 'hover': '"
4438                 + mockWebServerRule.uriForPath(HOVER_SELLER_PATH)
4439                 + "'};\n"
4440                 + "registerAdBeacon(beacons);"
4441                 + " return {'status': 0, 'results': {'signals_for_buyer':"
4442                 + " '{\"signals_for_buyer\":1}', 'reporting_uri': '"
4443                 + mockWebServerRule.uriForPath(SELLER_REPORTING_PATH)
4444                 + "' } };\n"
4445                 + "}";
4446     }
4447 
getBiddingLogicWithBeaconsWithAdCost()4448     private String getBiddingLogicWithBeaconsWithAdCost() {
4449         return "function generateBid(ad, auction_signals, per_buyer_signals,"
4450                 + " trusted_bidding_signals, contextual_signals, custom_audience_signals) { \n"
4451                 + "  return {'status': 0, 'ad': ad, 'bid': ad.metadata.result, 'adCost':"
4452                 + " ad.metadata.adCost };\n"
4453                 + "}\n"
4454                 + "function reportWin(ad_selection_signals, per_buyer_signals,"
4455                 + " signals_for_buyer, contextual_signals, custom_audience_signals) {\n"
4456                 + "const beacons = {'click': '"
4457                 + mockWebServerRule.uriForPath(CLICK_BUYER_PATH)
4458                 + "', 'hover': '"
4459                 + mockWebServerRule.uriForPath(HOVER_BUYER_PATH)
4460                 + "'};\n"
4461                 + "registerAdBeacon(beacons);"
4462                 + "    let reporting_address = '"
4463                 + mockWebServerRule.uriForPath(BUYER_REPORTING_PATH)
4464                 + "';\n"
4465                 + "    return {'status': 0, 'results': {'reporting_uri':\n"
4466                 + "                reporting_address + '?adCost=' + contextual_signals.adCost} };\n"
4467                 + "}";
4468     }
4469 
getBiddingLogicWithDataVersion()4470     private String getBiddingLogicWithDataVersion() {
4471         return "function generateBid(ad, auction_signals, per_buyer_signals,"
4472                 + " trusted_bidding_signals, contextual_signals, custom_audience_signals) { \n"
4473                 + "  return {'status': 0, 'ad': ad, 'bid': ad.metadata.result, 'adCost':"
4474                 + " ad.metadata.adCost };\n"
4475                 + "}\n"
4476                 + "function reportWin(ad_selection_signals, per_buyer_signals,"
4477                 + " signals_for_buyer, contextual_signals, custom_audience_signals) {\n"
4478                 + "    let reporting_address = '"
4479                 + mockWebServerRule.uriForPath(BUYER_REPORTING_PATH)
4480                 + "';\n"
4481                 + "    return {'status': 0, 'results': {'reporting_uri':\n"
4482                 + "                reporting_address + '?dataVersion=' +"
4483                 + " contextual_signals.dataVersion} };\n"
4484                 + "}";
4485     }
4486 
getDecisionLogicWithDataVersion()4487     private String getDecisionLogicWithDataVersion() {
4488         return "function scoreAd(ad, bid, auction_config, seller_signals,"
4489                 + " trusted_scoring_signals, contextual_signal, user_signal,"
4490                 + " custom_audience_signal) { \n"
4491                 + "  return {'status': 0, 'score': bid };\n"
4492                 + "}\n"
4493                 + "function reportResult(ad_selection_config, render_uri, bid,"
4494                 + " contextual_signals) {\n"
4495                 + "    let reporting_address = '"
4496                 + mockWebServerRule.uriForPath(SELLER_REPORTING_PATH)
4497                 + "';\n"
4498                 + " return {'status': 0, 'results': {'signals_for_buyer':"
4499                 + " '{\"signals_for_buyer\":1}', 'reporting_uri':\n"
4500                 + "                reporting_address + '?dataVersion=' +"
4501                 + " contextual_signals.dataVersion} };\n"
4502                 + "}";
4503     }
4504 
getMockWebServer( String decisionLogicJs, String biddingLogicJs, Semaphore impressionReportingSemaphore, Semaphore interactionReportingSemaphore, boolean jsVersioning)4505     private MockWebServer getMockWebServer(
4506             String decisionLogicJs,
4507             String biddingLogicJs,
4508             Semaphore impressionReportingSemaphore,
4509             Semaphore interactionReportingSemaphore,
4510             boolean jsVersioning)
4511             throws Exception {
4512         return getMockWebServer(
4513                 new HashMap<>(),
4514                 decisionLogicJs,
4515                 biddingLogicJs,
4516                 impressionReportingSemaphore,
4517                 interactionReportingSemaphore,
4518                 null,
4519                 jsVersioning);
4520     }
4521 
getMockWebServer( String decisionLogicJs, String biddingLogicJs, CountDownLatch debugReportingLatch)4522     private MockWebServer getMockWebServer(
4523             String decisionLogicJs, String biddingLogicJs, CountDownLatch debugReportingLatch)
4524             throws Exception {
4525         return getMockWebServer(
4526                 new HashMap<>(),
4527                 decisionLogicJs,
4528                 biddingLogicJs,
4529                 null,
4530                 null,
4531                 debugReportingLatch,
4532                 true);
4533     }
4534 
getMockWebServer( HashMap<String, String> remoteCustomAudiencesMap, String decisionLogicJs, String biddingLogicJs, Semaphore impressionReportingSemaphore, Semaphore interactionReportingSemaphore, CountDownLatch debugReportingLatch, boolean jsVersioning)4535     private MockWebServer getMockWebServer(
4536             HashMap<String, String> remoteCustomAudiencesMap,
4537             String decisionLogicJs,
4538             String biddingLogicJs,
4539             Semaphore impressionReportingSemaphore,
4540             Semaphore interactionReportingSemaphore,
4541             CountDownLatch debugReportingLatch,
4542             boolean jsVersioning)
4543             throws Exception {
4544         String versionHeaderName =
4545                 JsVersionHelper.getVersionHeaderName(
4546                         JsVersionHelper.JS_PAYLOAD_TYPE_BUYER_BIDDING_LOGIC_JS);
4547         long jsVersion = JsVersionRegister.BUYER_BIDDING_LOGIC_VERSION_VERSION_3;
4548         return mockWebServerRule.startMockWebServer(
4549                 request -> {
4550                     String requestPath = request.getPath();
4551                     switch (requestPath) {
4552                         case SELLER_DECISION_LOGIC_URI_PATH:
4553                             return new MockResponse().setBody(decisionLogicJs);
4554                         case BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1:
4555                         case BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_2:
4556                             if (jsVersioning) {
4557                                 if (Objects.equals(
4558                                         request.getHeader(versionHeaderName),
4559                                         Long.toString(jsVersion))) {
4560                                     return new MockResponse()
4561                                             .setBody(biddingLogicJs)
4562                                             .setHeader(versionHeaderName, jsVersion);
4563                                 }
4564                                 break;
4565                             } else {
4566                                 return new MockResponse().setBody(biddingLogicJs);
4567                             }
4568                         case BUYER_DEBUG_REPORT_WIN_PATH + DEBUG_REPORT_WINNING_BID_RESPONSE:
4569                         case BUYER_DEBUG_REPORT_LOSS_PATH + DEBUG_REPORT_WINNING_BID_RESPONSE:
4570                         case SELLER_DEBUG_REPORT_WIN_PATH + DEBUG_REPORT_WINNING_BID_RESPONSE:
4571                         case SELLER_DEBUG_REPORT_LOSS_PATH + DEBUG_REPORT_WINNING_BID_RESPONSE:
4572                             if (Objects.nonNull(debugReportingLatch)) {
4573                                 debugReportingLatch.countDown();
4574                             }
4575                             return new MockResponse().setResponseCode(200);
4576                         case CLICK_SELLER_PATH: // Intentional fallthrough
4577                         case CLICK_BUYER_PATH:
4578                             interactionReportingSemaphore.release();
4579                             return new MockResponse().setResponseCode(200);
4580                         case SELLER_REPORTING_PATH: // Intentional fallthrough
4581                         case BUYER_REPORTING_PATH:
4582                             impressionReportingSemaphore.release();
4583                             return new MockResponse().setResponseCode(200);
4584                     }
4585 
4586                     if (requestPath.contains(FETCH_CA_PATH)) {
4587                         String[] pathSegments = requestPath.split("/");
4588                         String customAudienceId = pathSegments[pathSegments.length - 1];
4589                         if (remoteCustomAudiencesMap.containsKey(customAudienceId)) {
4590                             return new MockResponse()
4591                                     .setBody(remoteCustomAudiencesMap.get(customAudienceId));
4592                         } else {
4593                             return new MockResponse().setResponseCode(404);
4594                         }
4595                     }
4596 
4597                     // Case where adCost / data version is reported in the Uri
4598                     if (request.getPath().startsWith(BUYER_REPORTING_PATH)) {
4599                         impressionReportingSemaphore.release();
4600                         return new MockResponse().setResponseCode(200);
4601                     }
4602 
4603                     // Case where data version is reported in the Uri
4604                     if (request.getPath().startsWith(SELLER_REPORTING_PATH)) {
4605                         impressionReportingSemaphore.release();
4606                         return new MockResponse().setResponseCode(200);
4607                     }
4608 
4609                     // The seller params vary based on runtime, so we are returning trusted
4610                     // signals based on correct path prefix
4611                     if (request.getPath()
4612                             .startsWith(
4613                                     SELLER_TRUSTED_SIGNAL_URI_PATH
4614                                             + SELLER_TRUSTED_SIGNAL_PARAMS)) {
4615                         return new MockResponse().setBody(TRUSTED_SCORING_SIGNALS.toString());
4616                     }
4617 
4618                     // Add seller trusted scoring uri path with data version header
4619                     if (request.getPath()
4620                             .startsWith(
4621                                     SELLER_TRUSTED_SIGNAL_URI_PATH_WITH_DATA_VERSION
4622                                             + SELLER_TRUSTED_SIGNAL_PARAMS)) {
4623                         return new MockResponse()
4624                                 .setBody(TRUSTED_SCORING_SIGNALS.toString())
4625                                 .addHeader(DATA_VERSION_HEADER_SCORING_KEY, DATA_VERSION_2);
4626                     }
4627 
4628                     if (request.getPath().startsWith(BUYER_TRUSTED_SIGNAL_URI_PATH)) {
4629                         return new MockResponse().setBody(TRUSTED_BIDDING_SIGNALS.toString());
4630                     }
4631 
4632                     // Add seller trusted scoring uri path with data version header
4633                     if (request.getPath()
4634                             .startsWith(BUYER_TRUSTED_SIGNAL_URI_PATH_WITH_DATA_VERSION)) {
4635                         return new MockResponse()
4636                                 .setBody(TRUSTED_BIDDING_SIGNALS.toString())
4637                                 .addHeader(DATA_VERSION_HEADER_BIDDING_KEY, DATA_VERSION_1);
4638                     }
4639                     return new MockResponse().setResponseCode(404);
4640                 });
4641     }
4642 
reportInteractionAndAssertSuccess(AdSelectionTestCallback resultsCallback)4643     private void reportInteractionAndAssertSuccess(AdSelectionTestCallback resultsCallback)
4644             throws Exception {
4645         reportInteractionAndAssertSuccess(resultsCallback, CommonFixture.TEST_PACKAGE_NAME);
4646     }
4647 
reportInteractionAndAssertSuccess( AdSelectionTestCallback resultsCallback, String callerAppPackageName)4648     private void reportInteractionAndAssertSuccess(
4649             AdSelectionTestCallback resultsCallback, String callerAppPackageName) throws Exception {
4650         ReportInteractionInput reportInteractionInput =
4651                 new ReportInteractionInput.Builder()
4652                         .setAdSelectionId(resultsCallback.mAdSelectionResponse.getAdSelectionId())
4653                         .setInteractionKey(CLICK_INTERACTION)
4654                         .setInteractionData(INTERACTION_DATA)
4655                         .setCallerPackageName(callerAppPackageName)
4656                         .setReportingDestinations(BUYER_DESTINATION | SELLER_DESTINATION)
4657                         .build();
4658 
4659         ReportInteractionTestCallback reportInteractionTestCallback =
4660                 callReportInteraction(mAdSelectionService, reportInteractionInput);
4661         assertTrue(reportInteractionTestCallback.mIsSuccess);
4662     }
4663 
reportOnlyBuyerInteractionAndAssertSuccess(AdSelectionTestCallback resultsCallback)4664     private void reportOnlyBuyerInteractionAndAssertSuccess(AdSelectionTestCallback resultsCallback)
4665             throws Exception {
4666         ReportInteractionInput reportInteractionInput =
4667                 new ReportInteractionInput.Builder()
4668                         .setAdSelectionId(resultsCallback.mAdSelectionResponse.getAdSelectionId())
4669                         .setInteractionKey(CLICK_INTERACTION)
4670                         .setInteractionData(INTERACTION_DATA)
4671                         .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME)
4672                         .setReportingDestinations(BUYER_DESTINATION)
4673                         .build();
4674 
4675         ReportInteractionTestCallback reportInteractionTestCallback =
4676                 callReportInteraction(mAdSelectionService, reportInteractionInput);
4677         assertTrue(reportInteractionTestCallback.mIsSuccess);
4678     }
4679 
reportImpressionAndAssertSuccess(long adSelectionId)4680     private void reportImpressionAndAssertSuccess(long adSelectionId) throws Exception {
4681         reportImpressionAndAssertSuccess(adSelectionId, CommonFixture.TEST_PACKAGE_NAME);
4682     }
4683 
reportImpressionAndAssertSuccess(long adSelectionId, String callerAppPackageName)4684     private void reportImpressionAndAssertSuccess(long adSelectionId, String callerAppPackageName)
4685             throws Exception {
4686         ReportImpressionInput input =
4687                 new ReportImpressionInput.Builder()
4688                         .setAdSelectionConfig(mAdSelectionConfig)
4689                         .setAdSelectionId(adSelectionId)
4690                         .setCallerPackageName(callerAppPackageName)
4691                         .build();
4692 
4693         ReportImpressionTestCallback reportImpressionTestCallback =
4694                 callReportImpression(mAdSelectionService, input);
4695 
4696         assertTrue(reportImpressionTestCallback.mIsSuccess);
4697     }
4698 
setupOverridesAndAssertSuccess( CustomAudience customAudience1, CustomAudience customAudience2, String biddingLogicJs, String decisionLogicJs)4699     private void setupOverridesAndAssertSuccess(
4700             CustomAudience customAudience1,
4701             CustomAudience customAudience2,
4702             String biddingLogicJs,
4703             String decisionLogicJs)
4704             throws Exception {
4705         // Add AdSelection Override
4706         AdSelectionOverrideTestCallback adSelectionOverrideTestCallback =
4707                 callAddAdSelectionOverride(
4708                         mAdSelectionService,
4709                         mAdSelectionConfig,
4710                         decisionLogicJs,
4711                         TRUSTED_SCORING_SIGNALS,
4712                         BUYERS_DECISION_LOGIC);
4713 
4714         assertTrue(adSelectionOverrideTestCallback.mIsSuccess);
4715 
4716         // Add Custom Audience Overrides
4717         CustomAudienceOverrideTestCallback customAudienceOverrideTestCallback1 =
4718                 callAddCustomAudienceOverride(
4719                         CommonFixture.TEST_PACKAGE_NAME,
4720                         customAudience1.getBuyer(),
4721                         customAudience1.getName(),
4722                         biddingLogicJs,
4723                         null,
4724                         TRUSTED_BIDDING_SIGNALS,
4725                         mCustomAudienceService);
4726 
4727         assertTrue(customAudienceOverrideTestCallback1.mIsSuccess);
4728 
4729         CustomAudienceOverrideTestCallback customAudienceOverrideTestCallback2 =
4730                 callAddCustomAudienceOverride(
4731                         CommonFixture.TEST_PACKAGE_NAME,
4732                         customAudience2.getBuyer(),
4733                         customAudience2.getName(),
4734                         biddingLogicJs,
4735                         null,
4736                         TRUSTED_BIDDING_SIGNALS,
4737                         mCustomAudienceService);
4738 
4739         assertTrue(customAudienceOverrideTestCallback2.mIsSuccess);
4740     }
4741 
setupAdSelectionConfig()4742     private void setupAdSelectionConfig() {
4743         mAdSelectionConfig =
4744                 AdSelectionConfigFixture.anAdSelectionConfigBuilder()
4745                         .setCustomAudienceBuyers(
4746                                 ImmutableList.of(
4747                                         AdTechIdentifier.fromString(
4748                                                 mLocalhostBuyerDomain.getHost())))
4749                         .setSeller(
4750                                 AdTechIdentifier.fromString(
4751                                         mockWebServerRule
4752                                                 .uriForPath(SELLER_DECISION_LOGIC_URI_PATH)
4753                                                 .getHost()))
4754                         .setDecisionLogicUri(
4755                                 mockWebServerRule.uriForPath(SELLER_DECISION_LOGIC_URI_PATH))
4756                         .setTrustedScoringSignalsUri(
4757                                 mockWebServerRule.uriForPath(SELLER_TRUSTED_SIGNAL_URI_PATH))
4758                         .setPerBuyerSignals(
4759                                 ImmutableMap.of(
4760                                         AdTechIdentifier.fromString(
4761                                                 mLocalhostBuyerDomain.getHost()),
4762                                         AdSelectionSignals.fromString("{\"buyer_signals\":0}")))
4763                         .build();
4764     }
4765 
setupAdSelectionConfigWithDataVersionHeader()4766     private void setupAdSelectionConfigWithDataVersionHeader() {
4767         mAdSelectionConfig =
4768                 AdSelectionConfigFixture.anAdSelectionConfigBuilder()
4769                         .setCustomAudienceBuyers(
4770                                 ImmutableList.of(
4771                                         AdTechIdentifier.fromString(
4772                                                 mLocalhostBuyerDomain.getHost())))
4773                         .setSeller(
4774                                 AdTechIdentifier.fromString(
4775                                         mockWebServerRule
4776                                                 .uriForPath(SELLER_DECISION_LOGIC_URI_PATH)
4777                                                 .getHost()))
4778                         .setDecisionLogicUri(
4779                                 mockWebServerRule.uriForPath(SELLER_DECISION_LOGIC_URI_PATH))
4780                         .setTrustedScoringSignalsUri(
4781                                 mockWebServerRule.uriForPath(
4782                                         SELLER_TRUSTED_SIGNAL_URI_PATH_WITH_DATA_VERSION))
4783                         .setPerBuyerSignals(
4784                                 ImmutableMap.of(
4785                                         AdTechIdentifier.fromString(
4786                                                 mLocalhostBuyerDomain.getHost()),
4787                                         AdSelectionSignals.fromString("{\"buyer_signals\":0}")))
4788                         .build();
4789     }
4790 
setupConsentGivenStubs()4791     private void setupConsentGivenStubs() {
4792         doReturn(AdServicesApiConsent.GIVEN)
4793                 .when(mConsentManagerMock)
4794                 .getConsent(AdServicesApiType.FLEDGE);
4795         doReturn(false).when(mConsentManagerMock).isFledgeConsentRevokedForApp(any());
4796         doReturn(false)
4797                 .when(mConsentManagerMock)
4798                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
4799     }
4800 
joinCustomAudienceAndAssertSuccess(CustomAudience ca)4801     private void joinCustomAudienceAndAssertSuccess(CustomAudience ca) {
4802         joinCustomAudienceAndAssertSuccess(ca, CommonFixture.TEST_PACKAGE_NAME);
4803     }
4804 
joinCustomAudienceAndAssertSuccess( CustomAudience ca, String callerAppPackageName)4805     private void joinCustomAudienceAndAssertSuccess(
4806             CustomAudience ca, String callerAppPackageName) {
4807         ResultCapturingCallback joinCallback = new ResultCapturingCallback();
4808         mCustomAudienceService.joinCustomAudience(ca, callerAppPackageName, joinCallback);
4809         assertTrue(joinCallback.isSuccess());
4810     }
4811 
fetchAndJoinCustomAudienceAndAssertSuccess(FetchAndJoinCustomAudienceInput request)4812     private void fetchAndJoinCustomAudienceAndAssertSuccess(FetchAndJoinCustomAudienceInput request)
4813             throws InterruptedException {
4814         CountDownLatch resultLatch = new CountDownLatch(1);
4815         FetchCustomAudienceTestCallback callback = new FetchCustomAudienceTestCallback(resultLatch);
4816         mCustomAudienceService.fetchAndJoinCustomAudience(request, callback);
4817         resultLatch.await();
4818         assertTrue(callback.isSuccess());
4819     }
4820 
leaveCustomAudienceAndAssertSuccess( String callerAppPackageName, AdTechIdentifier buyer, String name)4821     private void leaveCustomAudienceAndAssertSuccess(
4822             String callerAppPackageName, AdTechIdentifier buyer, String name) {
4823         ResultCapturingCallback leaveCallback = new ResultCapturingCallback();
4824         mCustomAudienceService.leaveCustomAudience(
4825                 callerAppPackageName, buyer, name, leaveCallback);
4826         assertTrue(leaveCallback.isSuccess());
4827     }
4828 
initClients( boolean gaUXEnabled, boolean registerAdBeaconEnabled, boolean cpcBillingEnabled, boolean dataVersionHeaderEnabled, boolean shouldUseUnifiedTables, boolean auctionServerEnabledReportImpression)4829     private void initClients(
4830             boolean gaUXEnabled,
4831             boolean registerAdBeaconEnabled,
4832             boolean cpcBillingEnabled,
4833             boolean dataVersionHeaderEnabled,
4834             boolean shouldUseUnifiedTables,
4835             boolean auctionServerEnabledReportImpression) {
4836         initClients(
4837                 gaUXEnabled,
4838                 registerAdBeaconEnabled,
4839                 true,
4840                 true,
4841                 true,
4842                 cpcBillingEnabled,
4843                 false,
4844                 dataVersionHeaderEnabled,
4845                 false,
4846                 false,
4847                 shouldUseUnifiedTables,
4848                 auctionServerEnabledReportImpression);
4849     }
4850 
initClients( boolean gaUXEnabled, boolean registerAdBeaconEnabled, boolean frequencyCapFilteringEnabled, boolean appInstallFilteringEnabled, boolean enrollmentCheckDisabled, boolean cpcBillingEnabled, boolean debugReportingEnabled, boolean dataVersionHeaderEnabled, boolean debugReportSendImmediately, boolean adIdKillSwitch, boolean shouldUseUnifiedTables, boolean auctionServerEnabledReportImpression)4851     private void initClients(
4852             boolean gaUXEnabled,
4853             boolean registerAdBeaconEnabled,
4854             boolean frequencyCapFilteringEnabled,
4855             boolean appInstallFilteringEnabled,
4856             boolean enrollmentCheckDisabled,
4857             boolean cpcBillingEnabled,
4858             boolean debugReportingEnabled,
4859             boolean dataVersionHeaderEnabled,
4860             boolean debugReportSendImmediately,
4861             boolean adIdKillSwitch,
4862             boolean shouldUseUnifiedTables,
4863             boolean auctionServerEnabledReportImpression) {
4864         Flags flags =
4865                 new FledgeE2ETestFlags(
4866                         gaUXEnabled,
4867                         registerAdBeaconEnabled,
4868                         frequencyCapFilteringEnabled,
4869                         appInstallFilteringEnabled,
4870                         enrollmentCheckDisabled,
4871                         cpcBillingEnabled,
4872                         debugReportingEnabled,
4873                         dataVersionHeaderEnabled,
4874                         debugReportSendImmediately,
4875                         adIdKillSwitch,
4876                         shouldUseUnifiedTables,
4877                         false);
4878 
4879         mCustomAudienceService =
4880                 new CustomAudienceServiceImpl(
4881                         mSpyContext,
4882                         new CustomAudienceImpl(
4883                                 mCustomAudienceDao,
4884                                 new CustomAudienceQuantityChecker(mCustomAudienceDao, flags),
4885                                 new CustomAudienceValidator(
4886                                         CommonFixture.FIXED_CLOCK_TRUNCATED_TO_MILLI,
4887                                         flags,
4888                                         flags.getFledgeFrequencyCapFilteringEnabled()
4889                                                 ? new FrequencyCapAdDataValidatorImpl()
4890                                                 : new FrequencyCapAdDataValidatorNoOpImpl(),
4891                                         AdRenderIdValidator.createInstance(flags)),
4892                                 CommonFixture.FIXED_CLOCK_TRUNCATED_TO_MILLI,
4893                                 flags),
4894                         mFledgeAuthorizationFilterMock,
4895                         mConsentManagerMock,
4896                         mDevContextFilterMock,
4897                         MoreExecutors.newDirectExecutorService(),
4898                         mAdServicesLoggerMock,
4899                         mAppImportanceFilterMock,
4900                         flags,
4901                         CallingAppUidSupplierProcessImpl.create(),
4902                         new CustomAudienceServiceFilter(
4903                                 mSpyContext,
4904                                 mFledgeConsentFilterMock,
4905                                 flags,
4906                                 mAppImportanceFilterMock,
4907                                 mFledgeAuthorizationFilterMock,
4908                                 mFledgeAllowListsFilterSpy,
4909                                 mFledgeApiThrottleFilterMock),
4910                         new AdFilteringFeatureFactory(mAppInstallDao, mFrequencyCapDao, flags));
4911 
4912         when(mDevContextFilterMock.createDevContext())
4913                 .thenReturn(DevContext.createForDevOptionsDisabled());
4914         mAdFilteringFeatureFactory =
4915                 new AdFilteringFeatureFactory(mAppInstallDao, mFrequencyCapDao, flags);
4916         mAdIdFetcher =
4917                 new AdIdFetcher(
4918                         mSpyContext,
4919                         mMockAdIdWorker,
4920                         mLightweightExecutorService,
4921                         mScheduledExecutor);
4922         // Create an instance of AdSelection Service with real dependencies
4923         mAdSelectionService =
4924                 new AdSelectionServiceImpl(
4925                         mAdSelectionEntryDao,
4926                         mAppInstallDao,
4927                         mCustomAudienceDao,
4928                         mEncodedPayloadDao,
4929                         mFrequencyCapDao,
4930                         mEncryptionKeyDao,
4931                         mEnrollmentDao,
4932                         mAdServicesHttpsClient,
4933                         mDevContextFilterMock,
4934                         mLightweightExecutorService,
4935                         mBackgroundExecutorService,
4936                         mScheduledExecutor,
4937                         mSpyContext,
4938                         mAdServicesLoggerMock,
4939                         flags,
4940                         CallingAppUidSupplierProcessImpl.create(),
4941                         mFledgeAuthorizationFilterMock,
4942                         mAdSelectionServiceFilterMock,
4943                         mAdFilteringFeatureFactory,
4944                         mConsentManagerMock,
4945                         mMultiCloudSupportStrategy,
4946                         mAdSelectionDebugReportDao,
4947                         mAdIdFetcher,
4948                         mUnusedKAnonSignJoinFactory,
4949                         false,
4950                         mRetryStrategyFactory,
4951                         mConsentedDebugConfigurationGeneratorFactory,
4952                         mEgressConfigurationGenerator,
4953                         CONSOLE_MESSAGE_IN_LOGS_ENABLED);
4954     }
4955 
invokeRunAdSelection( AdSelectionServiceImpl adSelectionService, AdSelectionConfig adSelectionConfig, String callerPackageName)4956     private AdSelectionTestCallback invokeRunAdSelection(
4957             AdSelectionServiceImpl adSelectionService,
4958             AdSelectionConfig adSelectionConfig,
4959             String callerPackageName)
4960             throws InterruptedException {
4961 
4962         CountDownLatch countdownLatch = new CountDownLatch(1);
4963         AdSelectionTestCallback adSelectionTestCallback =
4964                 new AdSelectionTestCallback(countdownLatch);
4965 
4966         AdSelectionInput input =
4967                 new AdSelectionInput.Builder()
4968                         .setAdSelectionConfig(adSelectionConfig)
4969                         .setCallerPackageName(callerPackageName)
4970                         .build();
4971         CallerMetadata callerMetadata =
4972                 new CallerMetadata.Builder()
4973                         .setBinderElapsedTimestamp(BINDER_ELAPSED_TIMESTAMP)
4974                         .build();
4975         adSelectionService.selectAds(input, callerMetadata, adSelectionTestCallback);
4976         adSelectionTestCallback.mCountDownLatch.await();
4977         return adSelectionTestCallback;
4978     }
4979 
invokeRunAdSelectionAndWaitForFullCallback( AdSelectionServiceImpl adSelectionService, AdSelectionConfig adSelectionConfig, String callerPackageName)4980     private AdSelectionTestCallback invokeRunAdSelectionAndWaitForFullCallback(
4981             AdSelectionServiceImpl adSelectionService,
4982             AdSelectionConfig adSelectionConfig,
4983             String callerPackageName)
4984             throws InterruptedException {
4985 
4986         CountDownLatch countdownLatch = new CountDownLatch(1);
4987         AdSelectionTestCallback adSelectionTestCallback =
4988                 new AdSelectionTestCallback(countdownLatch);
4989         CountDownLatch countdownLatchForFullCallback = new CountDownLatch(1);
4990         AdSelectionTestCallback adSelectionTestFullCallback =
4991                 new AdSelectionTestCallback(countdownLatchForFullCallback);
4992 
4993         AdSelectionInput input =
4994                 new AdSelectionInput.Builder()
4995                         .setAdSelectionConfig(adSelectionConfig)
4996                         .setCallerPackageName(callerPackageName)
4997                         .build();
4998         CallerMetadata callerMetadata =
4999                 new CallerMetadata.Builder()
5000                         .setBinderElapsedTimestamp(BINDER_ELAPSED_TIMESTAMP)
5001                         .build();
5002         adSelectionService.selectAds(
5003                 input, callerMetadata, adSelectionTestCallback, adSelectionTestFullCallback);
5004         adSelectionTestCallback.mCountDownLatch.await();
5005         adSelectionTestFullCallback.mCountDownLatch.await();
5006         return adSelectionTestCallback;
5007     }
5008 
callAddAdSelectionOverride( AdSelectionServiceImpl adSelectionService, AdSelectionConfig adSelectionConfig, String decisionLogicJS, AdSelectionSignals trustedScoringSignals, PerBuyerDecisionLogic buyerDecisionLogicMap)5009     private AdSelectionOverrideTestCallback callAddAdSelectionOverride(
5010             AdSelectionServiceImpl adSelectionService,
5011             AdSelectionConfig adSelectionConfig,
5012             String decisionLogicJS,
5013             AdSelectionSignals trustedScoringSignals,
5014             PerBuyerDecisionLogic buyerDecisionLogicMap)
5015             throws Exception {
5016         // Counted down in 1) callback
5017         CountDownLatch resultLatch = new CountDownLatch(1);
5018         AdSelectionOverrideTestCallback callback = new AdSelectionOverrideTestCallback(resultLatch);
5019 
5020         adSelectionService.overrideAdSelectionConfigRemoteInfo(
5021                 adSelectionConfig,
5022                 decisionLogicJS,
5023                 trustedScoringSignals,
5024                 buyerDecisionLogicMap,
5025                 callback);
5026         resultLatch.await();
5027         return callback;
5028     }
5029 
callAddCustomAudienceOverride( String owner, AdTechIdentifier buyer, String name, String biddingLogicJs, Long biddingLogicJsVersion, AdSelectionSignals trustedBiddingData, CustomAudienceServiceImpl customAudienceService)5030     private CustomAudienceOverrideTestCallback callAddCustomAudienceOverride(
5031             String owner,
5032             AdTechIdentifier buyer,
5033             String name,
5034             String biddingLogicJs,
5035             Long biddingLogicJsVersion,
5036             AdSelectionSignals trustedBiddingData,
5037             CustomAudienceServiceImpl customAudienceService)
5038             throws Exception {
5039         CountDownLatch resultLatch = new CountDownLatch(1);
5040         CustomAudienceOverrideTestCallback callback =
5041                 new CustomAudienceOverrideTestCallback(resultLatch);
5042 
5043         customAudienceService.overrideCustomAudienceRemoteInfo(
5044                 owner,
5045                 buyer,
5046                 name,
5047                 biddingLogicJs,
5048                 Optional.ofNullable(biddingLogicJsVersion).orElse(0L),
5049                 trustedBiddingData,
5050                 callback);
5051         resultLatch.await();
5052         return callback;
5053     }
5054 
callReportImpression( AdSelectionServiceImpl adSelectionService, ReportImpressionInput requestParams)5055     private ReportImpressionTestCallback callReportImpression(
5056             AdSelectionServiceImpl adSelectionService, ReportImpressionInput requestParams)
5057             throws Exception {
5058         // Counted down in 1) callback
5059         CountDownLatch resultLatch = new CountDownLatch(1);
5060         ReportImpressionTestCallback callback = new ReportImpressionTestCallback(resultLatch);
5061 
5062         adSelectionService.reportImpression(requestParams, callback);
5063         resultLatch.await();
5064         return callback;
5065     }
5066 
callReportInteraction( AdSelectionServiceImpl adSelectionService, ReportInteractionInput inputParams)5067     private ReportInteractionTestCallback callReportInteraction(
5068             AdSelectionServiceImpl adSelectionService, ReportInteractionInput inputParams)
5069             throws Exception {
5070         // Counted down in 1) callback
5071         CountDownLatch resultLatch = new CountDownLatch(1);
5072         ReportInteractionTestCallback callback = new ReportInteractionTestCallback(resultLatch);
5073 
5074         adSelectionService.reportInteraction(inputParams, callback);
5075         resultLatch.await();
5076         return callback;
5077     }
5078 
5079     /** See {@link #createCustomAudience(Uri, String, List)}. */
createCustomAudience(final Uri buyerDomain, List<Double> bids)5080     private CustomAudience createCustomAudience(final Uri buyerDomain, List<Double> bids) {
5081         return createCustomAudience(buyerDomain, "", bids);
5082     }
5083 
createCustomAudience( final Uri buyerDomain, final String customAudienceSeq, List<Double> bids)5084     private CustomAudience createCustomAudience(
5085             final Uri buyerDomain, final String customAudienceSeq, List<Double> bids) {
5086         return createCustomAudience(buyerDomain, customAudienceSeq, bids, null, null, false);
5087     }
5088 
createCustomAudienceWithDataVersion( final Uri buyerDomain, final String customAudienceSeq, List<Double> bids)5089     private CustomAudience createCustomAudienceWithDataVersion(
5090             final Uri buyerDomain, final String customAudienceSeq, List<Double> bids) {
5091         return createCustomAudience(buyerDomain, customAudienceSeq, bids, null, null, true);
5092     }
5093 
createCustomAudienceWithAdCost( final Uri buyerDomain, final String customAudienceSeq, List<Double> bids, double adCost)5094     private CustomAudience createCustomAudienceWithAdCost(
5095             final Uri buyerDomain,
5096             final String customAudienceSeq,
5097             List<Double> bids,
5098             double adCost) {
5099         return createCustomAudienceWithAdCost(
5100                 buyerDomain, customAudienceSeq, bids, null, null, adCost);
5101     }
5102 
5103     /**
5104      * @param buyerDomain The name of the buyer for this Custom Audience
5105      * @param customAudienceSeq optional numbering for ca name. Should start with slash.
5106      * @param bids these bids, are added to its metadata. Our JS logic then picks this value and
5107      *     creates ad with the provided value as bid
5108      * @param filtersForBids A parallel list to bids with the filter that should be added to each
5109      *     Ad. Can be left null.
5110      * @param adCounterKeysForBids A parallel list to bids with the adCounterKeys that should be
5111      *     added to each Ad. Can be left null.
5112      * @param withDataVersion Whether or not to fetch data version in trusted bidding signals
5113      * @return a real Custom Audience object that can be persisted and used in bidding and scoring
5114      */
createCustomAudience( final Uri buyerDomain, final String customAudienceSeq, List<Double> bids, List<Set<Integer>> adCounterKeysForBids, List<AdFilters> filtersForBids, boolean withDataVersion)5115     private CustomAudience createCustomAudience(
5116             final Uri buyerDomain,
5117             final String customAudienceSeq,
5118             List<Double> bids,
5119             List<Set<Integer>> adCounterKeysForBids,
5120             List<AdFilters> filtersForBids,
5121             boolean withDataVersion) {
5122 
5123         // Generate ads for with bids provided
5124         List<AdData> ads = new ArrayList<>();
5125 
5126         // Create ads with the buyer name and bid number as the ad URI
5127         // Add the bid value to the metadata
5128         for (int i = 0; i < bids.size(); i++) {
5129             AdData.Builder builder =
5130                     new AdData.Builder()
5131                             .setRenderUri(
5132                                     CommonFixture.getUri(
5133                                             buyerDomain.getAuthority(),
5134                                             AD_URI_PREFIX + customAudienceSeq + "/ad" + (i + 1)))
5135                             .setMetadata("{\"result\":" + bids.get(i) + "}");
5136             if (adCounterKeysForBids != null && adCounterKeysForBids.get(i) != null) {
5137                 builder.setAdCounterKeys(adCounterKeysForBids.get(i));
5138             }
5139             if (filtersForBids != null) {
5140                 builder.setAdFilters(filtersForBids.get(i));
5141             }
5142             ads.add(builder.build());
5143         }
5144 
5145         String trustedBiddingUriPath;
5146         if (withDataVersion) {
5147             trustedBiddingUriPath = BUYER_TRUSTED_SIGNAL_URI_PATH_WITH_DATA_VERSION;
5148         } else {
5149             trustedBiddingUriPath = BUYER_TRUSTED_SIGNAL_URI_PATH;
5150         }
5151 
5152         return new CustomAudience.Builder()
5153                 .setBuyer(AdTechIdentifier.fromString(buyerDomain.getHost()))
5154                 .setName(
5155                         buyerDomain.getHost()
5156                                 + customAudienceSeq
5157                                 + CustomAudienceFixture.VALID_NAME)
5158                 .setActivationTime(CustomAudienceFixture.VALID_ACTIVATION_TIME)
5159                 .setExpirationTime(CustomAudienceFixture.VALID_EXPIRATION_TIME)
5160                 .setDailyUpdateUri(
5161                         CustomAudienceFixture.getValidDailyUpdateUriByBuyer(
5162                                 AdTechIdentifier.fromString(buyerDomain.getAuthority())))
5163                 .setUserBiddingSignals(CustomAudienceFixture.VALID_USER_BIDDING_SIGNALS)
5164                 .setTrustedBiddingData(
5165                         new TrustedBiddingData.Builder()
5166                                 .setTrustedBiddingUri(
5167                                         CommonFixture.getUri(
5168                                                 buyerDomain.getAuthority(), trustedBiddingUriPath))
5169                                 .setTrustedBiddingKeys(
5170                                         TrustedBiddingDataFixture.getValidTrustedBiddingKeys())
5171                                 .build())
5172                 .setBiddingLogicUri(
5173                         CommonFixture.getUri(
5174                                 buyerDomain.getAuthority(),
5175                                 BUYER_BIDDING_LOGIC_URI_PATH + customAudienceSeq))
5176                 .setAds(ads)
5177                 .build();
5178     }
5179 
5180     /**
5181      * @param buyerDomain The name of the buyer for this Custom Audience
5182      * @param customAudienceSeq optional numbering for ca name. Should start with slash.
5183      * @param bids these bids, are added to its metadata. Our JS logic then picks this value and
5184      *     creates ad with the provided value as bid
5185      * @param filtersForBids A parallel list to bids with the filter that should be added to each
5186      *     Ad. Can be left null.
5187      * @param adCounterKeysForBids A parallel list to bids with the adCounterKeys that should be
5188      *     added to each Ad. Can be left null.
5189      * @param adCost The cost to click on an ad
5190      * @return a real Custom Audience object that can be persisted and used in bidding and scoring
5191      */
createCustomAudienceWithAdCost( final Uri buyerDomain, final String customAudienceSeq, List<Double> bids, List<Set<Integer>> adCounterKeysForBids, List<AdFilters> filtersForBids, double adCost)5192     private CustomAudience createCustomAudienceWithAdCost(
5193             final Uri buyerDomain,
5194             final String customAudienceSeq,
5195             List<Double> bids,
5196             List<Set<Integer>> adCounterKeysForBids,
5197             List<AdFilters> filtersForBids,
5198             double adCost) {
5199 
5200         // Generate ads for with bids provided
5201         List<AdData> ads = new ArrayList<>();
5202 
5203         // Create ads with the buyer name and bid number as the ad URI
5204         // Add the bid value to the metadata
5205         for (int i = 0; i < bids.size(); i++) {
5206             AdData.Builder builder =
5207                     new AdData.Builder()
5208                             .setRenderUri(
5209                                     CommonFixture.getUri(
5210                                             buyerDomain.getAuthority(),
5211                                             AD_URI_PREFIX + customAudienceSeq + "/ad" + (i + 1)))
5212                             .setMetadata(
5213                                     "{\"result\":" + bids.get(i) + ",\"adCost\":" + adCost + "}");
5214             if (adCounterKeysForBids != null && adCounterKeysForBids.get(i) != null) {
5215                 builder.setAdCounterKeys(adCounterKeysForBids.get(i));
5216             }
5217             if (filtersForBids != null) {
5218                 builder.setAdFilters(filtersForBids.get(i));
5219             }
5220             ads.add(builder.build());
5221         }
5222 
5223         return new CustomAudience.Builder()
5224                 .setBuyer(AdTechIdentifier.fromString(buyerDomain.getHost()))
5225                 .setName(
5226                         buyerDomain.getHost()
5227                                 + customAudienceSeq
5228                                 + CustomAudienceFixture.VALID_NAME)
5229                 .setActivationTime(CustomAudienceFixture.VALID_ACTIVATION_TIME)
5230                 .setExpirationTime(CustomAudienceFixture.VALID_EXPIRATION_TIME)
5231                 .setDailyUpdateUri(
5232                         CustomAudienceFixture.getValidDailyUpdateUriByBuyer(
5233                                 AdTechIdentifier.fromString(buyerDomain.getAuthority())))
5234                 .setUserBiddingSignals(CustomAudienceFixture.VALID_USER_BIDDING_SIGNALS)
5235                 .setTrustedBiddingData(
5236                         new TrustedBiddingData.Builder()
5237                                 .setTrustedBiddingUri(
5238                                         CommonFixture.getUri(
5239                                                 buyerDomain.getAuthority(),
5240                                                 BUYER_TRUSTED_SIGNAL_URI_PATH))
5241                                 .setTrustedBiddingKeys(
5242                                         TrustedBiddingDataFixture.getValidTrustedBiddingKeys())
5243                                 .build())
5244                 .setBiddingLogicUri(
5245                         CommonFixture.getUri(
5246                                 buyerDomain.getAuthority(),
5247                                 BUYER_BIDDING_LOGIC_URI_PATH + customAudienceSeq))
5248                 .setAds(ads)
5249                 .build();
5250     }
5251 
testFledgeFlowSuccessAllFilters( boolean shouldUseUnifiedTables, boolean auctionServerEnabledReportImpression)5252     private void testFledgeFlowSuccessAllFilters(
5253             boolean shouldUseUnifiedTables, boolean auctionServerEnabledReportImpression)
5254             throws Exception {
5255         initClients(
5256                 true,
5257                 true,
5258                 false,
5259                 false,
5260                 shouldUseUnifiedTables,
5261                 auctionServerEnabledReportImpression);
5262         doReturn(AdServicesApiConsent.GIVEN)
5263                 .when(mConsentManagerMock)
5264                 .getConsent(AdServicesApiType.FLEDGE);
5265         doReturn(false)
5266                 .when(mConsentManagerMock)
5267                 .isFledgeConsentRevokedForAppAfterSettingFledgeUse(any());
5268 
5269         setupAdSelectionConfig();
5270         CustomAudience customAudience1 =
5271                 createCustomAudience(
5272                         mLocalhostBuyerDomain, CUSTOM_AUDIENCE_SEQ_1, BIDS_FOR_BUYER_1);
5273 
5274         // Using the same generic key across all ads in the CA
5275         List<Set<Integer>> adCounterKeysForCa2 =
5276                 Arrays.asList(
5277                         Collections.singleton(KeyedFrequencyCapFixture.KEY1),
5278                         Collections.singleton(KeyedFrequencyCapFixture.KEY1),
5279                         Collections.singleton(KeyedFrequencyCapFixture.KEY1));
5280         /* The final ad with the highest bid has both fcap and app install filters, the second ad
5281          * with the middle bid has only an app install filter and the first ad with the lowest bid
5282          * in this ca has only a fcap filter.
5283          */
5284         List<AdFilters> adFiltersForCa2 =
5285                 Arrays.asList(
5286                         new AdFilters.Builder()
5287                                 .setFrequencyCapFilters(CLICK_ONCE_PER_DAY_KEY1)
5288                                 .build(),
5289                         new AdFilters.Builder().setAppInstallFilters(CURRENT_APP_FILTER).build(),
5290                         new AdFilters.Builder()
5291                                 .setAppInstallFilters(CURRENT_APP_FILTER)
5292                                 .setFrequencyCapFilters(CLICK_ONCE_PER_DAY_KEY1)
5293                                 .build());
5294         CustomAudience customAudience2 =
5295                 createCustomAudience(
5296                         mLocalhostBuyerDomain,
5297                         CUSTOM_AUDIENCE_SEQ_2,
5298                         BIDS_FOR_BUYER_2,
5299                         adCounterKeysForCa2,
5300                         adFiltersForCa2,
5301                         false);
5302 
5303         // We add permits to the semaphores when the MWS is called and remove them in the asserts
5304         Semaphore impressionReportingSemaphore = new Semaphore(0);
5305         Semaphore interactionReportingSemaphore = new Semaphore(0);
5306 
5307         MockWebServer server =
5308                 getMockWebServer(
5309                         getDecisionLogicWithBeacons(),
5310                         getV3BiddingLogicJs(),
5311                         impressionReportingSemaphore,
5312                         interactionReportingSemaphore,
5313                         true);
5314 
5315         joinCustomAudienceAndAssertSuccess(customAudience1);
5316         joinCustomAudienceAndAssertSuccess(customAudience2);
5317 
5318         verifyBackgroundFetchJobInvocation(/* invocationTimes= */ 2);
5319 
5320         // Run Ad Selection no filters active
5321         selectAdsAndReport(
5322                 CommonFixture.getUri(
5323                         mLocalhostBuyerDomain.getAuthority(),
5324                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad3"),
5325                 impressionReportingSemaphore,
5326                 interactionReportingSemaphore);
5327 
5328         // Run Ad Selection with app install filtering
5329         registerForAppInstallFiltering();
5330         long adSelectionId =
5331                 selectAdsAndReport(
5332                         CommonFixture.getUri(
5333                                 mLocalhostBuyerDomain.getAuthority(),
5334                                 AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad1"),
5335                         impressionReportingSemaphore,
5336                         interactionReportingSemaphore);
5337 
5338         // Run Ad Selection with both filters
5339         updateHistogramAndAssertSuccess(adSelectionId, FrequencyCapFilters.AD_EVENT_TYPE_CLICK);
5340         selectAdsAndReport(
5341                 CommonFixture.getUri(
5342                         mLocalhostBuyerDomain.getAuthority(),
5343                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_1 + "/ad2"),
5344                 impressionReportingSemaphore,
5345                 interactionReportingSemaphore);
5346 
5347         // Run Ad Selection with just fcap filtering
5348         deregisterForAppInstallFiltering();
5349         selectAdsAndReport(
5350                 CommonFixture.getUri(
5351                         mLocalhostBuyerDomain.getAuthority(),
5352                         AD_URI_PREFIX + CUSTOM_AUDIENCE_SEQ_2 + "/ad2"),
5353                 impressionReportingSemaphore,
5354                 interactionReportingSemaphore);
5355 
5356         // 30 requests for the 3 auctions with both CAs and 9 requests for the auctions with one CA
5357         mockWebServerRule.verifyMockServerRequests(
5358                 server,
5359                 39,
5360                 ImmutableList.of(
5361                         SELLER_DECISION_LOGIC_URI_PATH,
5362                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_1,
5363                         BUYER_BIDDING_LOGIC_URI_PATH + CUSTOM_AUDIENCE_SEQ_2,
5364                         BUYER_TRUSTED_SIGNAL_URI_PATH,
5365                         SELLER_TRUSTED_SIGNAL_URI_PATH + SELLER_TRUSTED_SIGNAL_PARAMS),
5366                 mRequestMatcherPrefixMatch);
5367     }
5368 
5369     private static class ResultCapturingCallback implements ICustomAudienceCallback {
5370         private boolean mIsSuccess;
5371         private Exception mException;
5372 
isSuccess()5373         public boolean isSuccess() {
5374             return mIsSuccess;
5375         }
5376 
getException()5377         public Exception getException() {
5378             return mException;
5379         }
5380 
5381         @Override
onSuccess()5382         public void onSuccess() throws RemoteException {
5383             mIsSuccess = true;
5384         }
5385 
5386         @Override
onFailure(FledgeErrorResponse responseParcel)5387         public void onFailure(FledgeErrorResponse responseParcel) throws RemoteException {
5388             mIsSuccess = false;
5389             mException = AdServicesStatusUtils.asException(responseParcel);
5390         }
5391 
5392         @Override
asBinder()5393         public IBinder asBinder() {
5394             throw new RuntimeException("Should not be called.");
5395         }
5396     }
5397 
5398     private static class AppInstallResultCapturingCallback
5399             implements SetAppInstallAdvertisersCallback {
5400         private boolean mIsSuccess;
5401         private Exception mException;
5402         private final CountDownLatch mCountDownLatch;
5403 
isSuccess()5404         public boolean isSuccess() {
5405             return mIsSuccess;
5406         }
5407 
getException()5408         public Exception getException() {
5409             return mException;
5410         }
5411 
AppInstallResultCapturingCallback(CountDownLatch countDownLatch)5412         AppInstallResultCapturingCallback(CountDownLatch countDownLatch) {
5413             mCountDownLatch = countDownLatch;
5414         }
5415 
5416         @Override
onSuccess()5417         public void onSuccess() throws RemoteException {
5418             mIsSuccess = true;
5419             mCountDownLatch.countDown();
5420         }
5421 
5422         @Override
onFailure(FledgeErrorResponse responseParcel)5423         public void onFailure(FledgeErrorResponse responseParcel) throws RemoteException {
5424             mIsSuccess = false;
5425             mException = AdServicesStatusUtils.asException(responseParcel);
5426             mCountDownLatch.countDown();
5427         }
5428 
5429         @Override
asBinder()5430         public IBinder asBinder() {
5431             throw new RuntimeException("Should not be called.");
5432         }
5433     }
5434 
5435     static class AdSelectionTestCallback extends AdSelectionCallback.Stub {
5436 
5437         final CountDownLatch mCountDownLatch;
5438         boolean mIsSuccess = false;
5439         AdSelectionResponse mAdSelectionResponse;
5440         FledgeErrorResponse mFledgeErrorResponse;
5441 
AdSelectionTestCallback(CountDownLatch countDownLatch)5442         AdSelectionTestCallback(CountDownLatch countDownLatch) {
5443             mCountDownLatch = countDownLatch;
5444             mAdSelectionResponse = null;
5445             mFledgeErrorResponse = null;
5446         }
5447 
5448         @Override
onSuccess(AdSelectionResponse adSelectionResponse)5449         public void onSuccess(AdSelectionResponse adSelectionResponse) throws RemoteException {
5450             mIsSuccess = true;
5451             mAdSelectionResponse = adSelectionResponse;
5452             mCountDownLatch.countDown();
5453         }
5454 
5455         @Override
onFailure(FledgeErrorResponse fledgeErrorResponse)5456         public void onFailure(FledgeErrorResponse fledgeErrorResponse) throws RemoteException {
5457             mIsSuccess = false;
5458             mFledgeErrorResponse = fledgeErrorResponse;
5459             mCountDownLatch.countDown();
5460         }
5461     }
5462 
5463     public static class AdSelectionOverrideTestCallback extends AdSelectionOverrideCallback.Stub {
5464         private final CountDownLatch mCountDownLatch;
5465         boolean mIsSuccess = false;
5466         FledgeErrorResponse mFledgeErrorResponse;
5467 
AdSelectionOverrideTestCallback(CountDownLatch countDownLatch)5468         public AdSelectionOverrideTestCallback(CountDownLatch countDownLatch) {
5469             mCountDownLatch = countDownLatch;
5470         }
5471 
5472         @Override
onSuccess()5473         public void onSuccess() throws RemoteException {
5474             mIsSuccess = true;
5475             mCountDownLatch.countDown();
5476         }
5477 
5478         @Override
onFailure(FledgeErrorResponse fledgeErrorResponse)5479         public void onFailure(FledgeErrorResponse fledgeErrorResponse) throws RemoteException {
5480             mFledgeErrorResponse = fledgeErrorResponse;
5481             mCountDownLatch.countDown();
5482         }
5483     }
5484 
5485     public static class CustomAudienceOverrideTestCallback
5486             extends CustomAudienceOverrideCallback.Stub {
5487         private final CountDownLatch mCountDownLatch;
5488         boolean mIsSuccess = false;
5489         FledgeErrorResponse mFledgeErrorResponse;
5490 
CustomAudienceOverrideTestCallback(CountDownLatch countDownLatch)5491         public CustomAudienceOverrideTestCallback(CountDownLatch countDownLatch) {
5492             mCountDownLatch = countDownLatch;
5493         }
5494 
5495         @Override
onSuccess()5496         public void onSuccess() throws RemoteException {
5497             mIsSuccess = true;
5498             mCountDownLatch.countDown();
5499         }
5500 
5501         @Override
onFailure(FledgeErrorResponse fledgeErrorResponse)5502         public void onFailure(FledgeErrorResponse fledgeErrorResponse) throws RemoteException {
5503             mFledgeErrorResponse = fledgeErrorResponse;
5504             mCountDownLatch.countDown();
5505         }
5506     }
5507 
5508     public static class ReportImpressionTestCallback extends ReportImpressionCallback.Stub {
5509         private final CountDownLatch mCountDownLatch;
5510         boolean mIsSuccess = false;
5511         FledgeErrorResponse mFledgeErrorResponse;
5512 
ReportImpressionTestCallback(CountDownLatch countDownLatch)5513         public ReportImpressionTestCallback(CountDownLatch countDownLatch) {
5514             mCountDownLatch = countDownLatch;
5515         }
5516 
5517         @Override
onSuccess()5518         public void onSuccess() throws RemoteException {
5519             mIsSuccess = true;
5520             mCountDownLatch.countDown();
5521         }
5522 
5523         @Override
onFailure(FledgeErrorResponse fledgeErrorResponse)5524         public void onFailure(FledgeErrorResponse fledgeErrorResponse) throws RemoteException {
5525             mFledgeErrorResponse = fledgeErrorResponse;
5526             mCountDownLatch.countDown();
5527         }
5528     }
5529 
5530     static class ReportInteractionTestCallback extends ReportInteractionCallback.Stub {
5531         private final CountDownLatch mCountDownLatch;
5532         boolean mIsSuccess = false;
5533         FledgeErrorResponse mFledgeErrorResponse;
5534 
ReportInteractionTestCallback(CountDownLatch countDownLatch)5535         ReportInteractionTestCallback(CountDownLatch countDownLatch) {
5536             mCountDownLatch = countDownLatch;
5537         }
5538 
5539         @Override
onSuccess()5540         public void onSuccess() throws RemoteException {
5541             mIsSuccess = true;
5542             mCountDownLatch.countDown();
5543         }
5544 
5545         @Override
onFailure(FledgeErrorResponse fledgeErrorResponse)5546         public void onFailure(FledgeErrorResponse fledgeErrorResponse) throws RemoteException {
5547             mFledgeErrorResponse = fledgeErrorResponse;
5548             mCountDownLatch.countDown();
5549         }
5550     }
5551 
createContextualAds()5552     private Map<AdTechIdentifier, SignedContextualAds> createContextualAds() {
5553         Map<AdTechIdentifier, SignedContextualAds> buyerContextualAds = new HashMap<>();
5554 
5555         // In order to meet ETLd+1 requirements creating Contextual ads with MockWebserver's host
5556         AdTechIdentifier buyer =
5557                 AdTechIdentifier.fromString(
5558                         mockWebServerRule.uriForPath(BUYER_BIDDING_LOGIC_URI_PATH).getHost());
5559         SignedContextualAds contextualAds =
5560                 SignedContextualAdsFixture.signContextualAds(
5561                         SignedContextualAdsFixture.aContextualAdsWithEmptySignatureBuilder(
5562                                         buyer, ImmutableList.of(100.0, 200.0, 300.0, 400.0, 500.0))
5563                                 .setDecisionLogicUri(
5564                                         mockWebServerRule.uriForPath(
5565                                                 BUYER_BIDDING_LOGIC_URI_PATH)));
5566         buyerContextualAds.put(buyer, contextualAds);
5567         return buyerContextualAds;
5568     }
5569 
verifyBackgroundFetchJobInvocation(int invocationTimes)5570     private void verifyBackgroundFetchJobInvocation(int invocationTimes) {
5571         verify(() -> BackgroundFetchJob.schedule(any()), times(invocationTimes));
5572     }
5573 
5574     private static class FledgeE2ETestFlags implements Flags {
5575         private final boolean mIsGaUxEnabled;
5576         private final boolean mRegisterAdBeaconEnabled;
5577         private final boolean mFrequencyCapFilteringEnabled;
5578         private final boolean mAppInstallFilteringEnabled;
5579         private final boolean mEnrollmentCheckDisabled;
5580         private final boolean mCpcBillingEnabled;
5581         private final boolean mDebugReportingEnabled;
5582         private final boolean mDataVersionHeaderEnabled;
5583         private final boolean mDebugReportsSendImmediately;
5584         private final boolean mAdIdKillSwitch;
5585         private final boolean mShouldUseUnifiedTables;
5586         private final boolean mAuctionServerEnabledReportImpression;
5587 
FledgeE2ETestFlags( boolean isGaUxEnabled, boolean registerAdBeaconEnabled, boolean frequencyCapFilteringEnabled, boolean appInstallEnabled, boolean enrollmentCheckDisabled, boolean cpcBillingEnabled, boolean debugReportingEnabled, boolean dataVersionHeaderEnabled, boolean debugReportsSendImmediately, boolean adIdKillSwitch, boolean shouldUseUnifiedTables, boolean auctionServerEnabledReportImpression)5588         FledgeE2ETestFlags(
5589                 boolean isGaUxEnabled,
5590                 boolean registerAdBeaconEnabled,
5591                 boolean frequencyCapFilteringEnabled,
5592                 boolean appInstallEnabled,
5593                 boolean enrollmentCheckDisabled,
5594                 boolean cpcBillingEnabled,
5595                 boolean debugReportingEnabled,
5596                 boolean dataVersionHeaderEnabled,
5597                 boolean debugReportsSendImmediately,
5598                 boolean adIdKillSwitch,
5599                 boolean shouldUseUnifiedTables,
5600                 boolean auctionServerEnabledReportImpression) {
5601             mIsGaUxEnabled = isGaUxEnabled;
5602             mRegisterAdBeaconEnabled = registerAdBeaconEnabled;
5603             mFrequencyCapFilteringEnabled = frequencyCapFilteringEnabled;
5604             mAppInstallFilteringEnabled = appInstallEnabled;
5605             mEnrollmentCheckDisabled = enrollmentCheckDisabled;
5606             mCpcBillingEnabled = cpcBillingEnabled;
5607             mDebugReportingEnabled = debugReportingEnabled;
5608             mDataVersionHeaderEnabled = dataVersionHeaderEnabled;
5609             mDebugReportsSendImmediately = debugReportsSendImmediately;
5610             mAdIdKillSwitch = adIdKillSwitch;
5611             mShouldUseUnifiedTables = shouldUseUnifiedTables;
5612             mAuctionServerEnabledReportImpression = auctionServerEnabledReportImpression;
5613         }
5614 
5615         @Override
getAdSelectionBiddingTimeoutPerCaMs()5616         public long getAdSelectionBiddingTimeoutPerCaMs() {
5617             return 10000;
5618         }
5619 
5620         @Override
getAdSelectionScoringTimeoutMs()5621         public long getAdSelectionScoringTimeoutMs() {
5622             return 10000;
5623         }
5624 
5625         @Override
getAdSelectionOverallTimeoutMs()5626         public long getAdSelectionOverallTimeoutMs() {
5627             return 300000;
5628         }
5629 
5630         @Override
getEnforceIsolateMaxHeapSize()5631         public boolean getEnforceIsolateMaxHeapSize() {
5632             return false;
5633         }
5634 
5635         @Override
getGaUxFeatureEnabled()5636         public boolean getGaUxFeatureEnabled() {
5637             return mIsGaUxEnabled;
5638         }
5639 
5640         @Override
getSdkRequestPermitsPerSecond()5641         public float getSdkRequestPermitsPerSecond() {
5642             // Unlimited rate for unit tests to avoid flake in tests due to rate limiting
5643             return -1;
5644         }
5645 
5646         @Override
getDisableFledgeEnrollmentCheck()5647         public boolean getDisableFledgeEnrollmentCheck() {
5648             return mEnrollmentCheckDisabled;
5649         }
5650 
5651         @Override
getFledgeRegisterAdBeaconEnabled()5652         public boolean getFledgeRegisterAdBeaconEnabled() {
5653             return mRegisterAdBeaconEnabled;
5654         }
5655 
5656         @Override
getFledgeFrequencyCapFilteringEnabled()5657         public boolean getFledgeFrequencyCapFilteringEnabled() {
5658             return mFrequencyCapFilteringEnabled;
5659         }
5660 
5661         @Override
getFledgeAppInstallFilteringEnabled()5662         public boolean getFledgeAppInstallFilteringEnabled() {
5663             return mAppInstallFilteringEnabled;
5664         }
5665 
5666         @Override
getFledgeAdSelectionContextualAdsEnabled()5667         public boolean getFledgeAdSelectionContextualAdsEnabled() {
5668             return true;
5669         }
5670 
5671         @Override
getFledgeAdSelectionBiddingLogicJsVersion()5672         public long getFledgeAdSelectionBiddingLogicJsVersion() {
5673             return JsVersionRegister.BUYER_BIDDING_LOGIC_VERSION_VERSION_3;
5674         }
5675 
5676         @Override
getFledgeCpcBillingEnabled()5677         public boolean getFledgeCpcBillingEnabled() {
5678             return mCpcBillingEnabled;
5679         }
5680 
5681         @Override
getFledgeFetchCustomAudienceEnabled()5682         public boolean getFledgeFetchCustomAudienceEnabled() {
5683             return true;
5684         }
5685 
5686         @Override
getFledgeEventLevelDebugReportingEnabled()5687         public boolean getFledgeEventLevelDebugReportingEnabled() {
5688             return mDebugReportingEnabled;
5689         }
5690 
5691         @Override
getFledgeDataVersionHeaderEnabled()5692         public boolean getFledgeDataVersionHeaderEnabled() {
5693             return mDataVersionHeaderEnabled;
5694         }
5695 
5696         @Override
getFledgeOnDeviceAuctionKillSwitch()5697         public boolean getFledgeOnDeviceAuctionKillSwitch() {
5698             return false;
5699         }
5700 
5701         @Override
getFledgeEventLevelDebugReportSendImmediately()5702         public boolean getFledgeEventLevelDebugReportSendImmediately() {
5703             return mDebugReportsSendImmediately;
5704         }
5705 
5706         @Override
getAdIdKillSwitch()5707         public boolean getAdIdKillSwitch() {
5708             return mAdIdKillSwitch;
5709         }
5710 
5711         @Override
getFledgeOnDeviceAuctionShouldUseUnifiedTables()5712         public boolean getFledgeOnDeviceAuctionShouldUseUnifiedTables() {
5713             return mShouldUseUnifiedTables;
5714         }
5715 
5716         @Override
getFledgeAuctionServerEnabledForReportEvent()5717         public boolean getFledgeAuctionServerEnabledForReportEvent() {
5718             return false;
5719         }
5720 
5721         @Override
getFledgeAuctionServerEnabledForReportImpression()5722         public boolean getFledgeAuctionServerEnabledForReportImpression() {
5723             return mAuctionServerEnabledReportImpression;
5724         }
5725     }
5726 }
5727