• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.adselection;
18 
19 import static android.adservices.adselection.AdSelectionConfigFixture.BUYER_1;
20 import static android.adservices.adselection.AdSelectionConfigFixture.BUYER_2;
21 import static android.adservices.adselection.SellerConfigurationFixture.PER_BUYER_CONFIGURATION_1;
22 import static android.adservices.adselection.SellerConfigurationFixture.PER_BUYER_CONFIGURATION_2;
23 import static android.adservices.adselection.SellerConfigurationFixture.SELLER_CONFIGURATION;
24 import static android.adservices.common.AdServicesStatusUtils.STATUS_INVALID_ARGUMENT;
25 import static android.adservices.common.AdServicesStatusUtils.STATUS_SUCCESS;
26 import static android.adservices.common.CommonFixture.getAlphaNumericString;
27 import static android.adservices.common.KeyedFrequencyCapFixture.ONE_DAY_DURATION;
28 import static android.adservices.customaudience.CustomAudience.FLAG_AUCTION_SERVER_REQUEST_OMIT_ADS;
29 
30 import static com.android.adservices.common.DBAdDataFixture.getValidDbAdDataNoFiltersBuilder;
31 import static com.android.adservices.data.adselection.EncryptionKeyConstants.EncryptionKeyType.ENCRYPTION_KEY_TYPE_AUCTION;
32 import static com.android.adservices.service.Flags.FLEDGE_AUCTION_SERVER_OVERALL_TIMEOUT_MS;
33 import static com.android.adservices.service.FlagsConstants.KEY_ENABLE_CUSTOM_AUDIENCE_COMPONENT_ADS;
34 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_APP_INSTALL_FILTERING_ENABLED;
35 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_AUCTION_SERVER_AD_ID_FETCHER_TIMEOUT_MS;
36 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_AUCTION_SERVER_AUCTION_KEY_FETCH_URI;
37 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_AUCTION_SERVER_COORDINATOR_URL_ALLOWLIST;
38 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_AUCTION_SERVER_ENABLED_FOR_REPORT_EVENT;
39 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_AUCTION_SERVER_ENABLED_FOR_REPORT_IMPRESSION;
40 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_AUCTION_SERVER_ENABLED_FOR_SELECT_ADS_MEDIATION;
41 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_AUCTION_SERVER_ENABLED_FOR_UPDATE_HISTOGRAM;
42 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_AUCTION_SERVER_ENABLE_DEBUG_REPORTING;
43 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_AUCTION_SERVER_GET_AD_SELECTION_DATA_PAYLOAD_METRICS_ENABLED;
44 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_AUCTION_SERVER_KEY_FETCH_METRICS_ENABLED;
45 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_AUCTION_SERVER_KILL_SWITCH;
46 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_AUCTION_SERVER_MEDIA_TYPE_CHANGE_ENABLED;
47 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_AUCTION_SERVER_OMIT_ADS_ENABLED;
48 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_AUCTION_SERVER_OVERALL_TIMEOUT_MS;
49 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_AUCTION_SERVER_PAYLOAD_FORMAT_VERSION;
50 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_AUCTION_SERVER_REFRESH_EXPIRED_KEYS_DURING_AUCTION;
51 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_FREQUENCY_CAP_FILTERING_ENABLED;
52 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_GET_AD_SELECTION_DATA_BUYER_INPUT_CREATOR_VERSION;
53 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_GET_AD_SELECTION_DATA_SELLER_CONFIGURATION_ENABLED;
54 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_ON_DEVICE_AUCTION_SHOULD_USE_UNIFIED_TABLES;
55 import static com.android.adservices.service.FlagsConstants.KEY_FLEDGE_REGISTER_AD_BEACON_ENABLED;
56 import static com.android.adservices.service.FlagsConstants.KEY_PROTECTED_SIGNALS_PERIODIC_ENCODING_ENABLED;
57 import static com.android.adservices.service.adselection.AdSelectionFromOutcomesIntegrationTest.BID_FLOOR_SELECTION_SIGNAL_TEMPLATE;
58 import static com.android.adservices.service.adselection.AdSelectionFromOutcomesIntegrationTest.SELECTION_WATERFALL_LOGIC_JS;
59 import static com.android.adservices.service.adselection.AdSelectionFromOutcomesIntegrationTest.SELECTION_WATERFALL_LOGIC_JS_PATH;
60 import static com.android.adservices.service.adselection.AdSelectionServiceImpl.AUCTION_SERVER_API_IS_NOT_AVAILABLE;
61 import static com.android.adservices.service.adselection.GetAdSelectionDataRunner.REVOKED_CONSENT_RANDOM_DATA_SIZE;
62 import static com.android.adservices.service.stats.AdSelectionExecutionLoggerTestFixture.sCallerMetadata;
63 import static com.android.adservices.service.stats.AdServicesLoggerUtil.FIELD_UNSET;
64 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__AD_SELECTION_SERVICE_AUCTION_SERVER_API_NOT_AVAILABLE;
65 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__GET_AD_SELECTION_DATA_RUNNER_FILTER_AND_REVOKED_CONSENT_EXCEPTION;
66 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__GET_AD_SELECTION_DATA_RUNNER_NOTIFY_FAILURE_INVALID_ARGUMENT;
67 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__PERSIST_AD_SELECTION_RESULT_RUNNER_NOTIFY_EMPTY_SUCCESS_SILENT_CONSENT_FAILURE;
68 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__PERSIST_AD_SELECTION_RESULT_RUNNER_RESULT_IS_CHAFF;
69 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__ERROR_CODE__PERSIST_AD_SELECTION_RESULT_RUNNER_REVOKED_CONSENT_FILTER_EXCEPTION;
70 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__GET_AD_SELECTION_DATA;
71 import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__PERSIST_AD_SELECTION_RESULT;
72 import static com.android.adservices.service.stats.AdsRelevanceStatusUtils.SERVER_AUCTION_COORDINATOR_SOURCE_DEFAULT;
73 import static com.android.adservices.service.stats.AdsRelevanceStatusUtils.SERVER_AUCTION_COORDINATOR_SOURCE_UNSET;
74 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
75 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
76 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyLong;
77 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
78 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
79 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow;
80 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
81 
82 import static com.google.common.truth.Truth.assertThat;
83 import static com.google.common.util.concurrent.Futures.immediateFuture;
84 
85 import static org.junit.Assert.assertTrue;
86 import static org.mockito.ArgumentMatchers.eq;
87 import static org.mockito.Mockito.doAnswer;
88 import static org.mockito.Mockito.never;
89 import static org.mockito.Mockito.reset;
90 import static org.mockito.Mockito.spy;
91 import static org.mockito.Mockito.times;
92 import static org.mockito.Mockito.verify;
93 
94 import android.adservices.adid.AdId;
95 import android.adservices.adselection.AdSelectionCallback;
96 import android.adservices.adselection.AdSelectionConfig;
97 import android.adservices.adselection.AdSelectionConfigFixture;
98 import android.adservices.adselection.AdSelectionFromOutcomesConfigFixture;
99 import android.adservices.adselection.AdSelectionFromOutcomesInput;
100 import android.adservices.adselection.AdSelectionResponse;
101 import android.adservices.adselection.AdSelectionService;
102 import android.adservices.adselection.AuctionEncryptionKeyFixture;
103 import android.adservices.adselection.GetAdSelectionDataCallback;
104 import android.adservices.adselection.GetAdSelectionDataInput;
105 import android.adservices.adselection.GetAdSelectionDataResponse;
106 import android.adservices.adselection.PersistAdSelectionResultCallback;
107 import android.adservices.adselection.PersistAdSelectionResultInput;
108 import android.adservices.adselection.PersistAdSelectionResultResponse;
109 import android.adservices.adselection.ReportEventRequest;
110 import android.adservices.adselection.ReportImpressionCallback;
111 import android.adservices.adselection.ReportImpressionInput;
112 import android.adservices.adselection.ReportInteractionCallback;
113 import android.adservices.adselection.ReportInteractionInput;
114 import android.adservices.adselection.SellerConfiguration;
115 import android.adservices.adselection.SetAppInstallAdvertisersCallback;
116 import android.adservices.adselection.SetAppInstallAdvertisersInput;
117 import android.adservices.adselection.UpdateAdCounterHistogramCallback;
118 import android.adservices.adselection.UpdateAdCounterHistogramInput;
119 import android.adservices.common.AdFilters;
120 import android.adservices.common.AdSelectionSignals;
121 import android.adservices.common.AdServicesStatusUtils;
122 import android.adservices.common.AdTechIdentifier;
123 import android.adservices.common.AppInstallFilters;
124 import android.adservices.common.AssetFileDescriptorUtil;
125 import android.adservices.common.CallingAppUidSupplierProcessImpl;
126 import android.adservices.common.CommonFixture;
127 import android.adservices.common.ComponentAdData;
128 import android.adservices.common.ComponentAdDataFixture;
129 import android.adservices.common.FledgeErrorResponse;
130 import android.adservices.common.FrequencyCapFilters;
131 import android.adservices.common.KeyedFrequencyCap;
132 import android.adservices.http.MockWebServerRule;
133 import android.content.res.AssetFileDescriptor;
134 import android.net.Uri;
135 import android.os.IBinder;
136 import android.os.Process;
137 import android.os.RemoteException;
138 import android.util.Base64;
139 
140 import androidx.room.Room;
141 
142 import com.android.adservices.MockWebServerRuleFactory;
143 import com.android.adservices.common.AdServicesExtendedMockitoTestCase;
144 import com.android.adservices.common.DBAdDataFixture;
145 import com.android.adservices.common.WebViewSupportUtil;
146 import com.android.adservices.common.logging.annotations.ExpectErrorLogUtilCall;
147 import com.android.adservices.concurrency.AdServicesExecutors;
148 import com.android.adservices.customaudience.DBCustomAudienceFixture;
149 import com.android.adservices.data.adselection.AdSelectionDatabase;
150 import com.android.adservices.data.adselection.AdSelectionDebugReportDao;
151 import com.android.adservices.data.adselection.AdSelectionDebugReportingDatabase;
152 import com.android.adservices.data.adselection.AdSelectionEntryDao;
153 import com.android.adservices.data.adselection.AdSelectionServerDatabase;
154 import com.android.adservices.data.adselection.AppInstallDao;
155 import com.android.adservices.data.adselection.ConsentedDebugConfigurationDao;
156 import com.android.adservices.data.adselection.DBProtectedServersEncryptionConfig;
157 import com.android.adservices.data.adselection.EncryptionContextDao;
158 import com.android.adservices.data.adselection.FrequencyCapDao;
159 import com.android.adservices.data.adselection.ProtectedServersEncryptionConfigDao;
160 import com.android.adservices.data.adselection.SharedStorageDatabase;
161 import com.android.adservices.data.adselection.datahandlers.ReportingData;
162 import com.android.adservices.data.common.DBAdData;
163 import com.android.adservices.data.customaudience.CustomAudienceDao;
164 import com.android.adservices.data.customaudience.CustomAudienceDatabase;
165 import com.android.adservices.data.customaudience.DBCustomAudience;
166 import com.android.adservices.data.enrollment.EnrollmentDao;
167 import com.android.adservices.data.measurement.DatastoreManager;
168 import com.android.adservices.data.signals.DBEncodedPayload;
169 import com.android.adservices.data.signals.EncodedPayloadDao;
170 import com.android.adservices.data.signals.ProtectedSignalsDao;
171 import com.android.adservices.data.signals.ProtectedSignalsDatabase;
172 import com.android.adservices.ohttp.ObliviousHttpGateway;
173 import com.android.adservices.ohttp.OhttpGatewayPrivateKey;
174 import com.android.adservices.service.DebugFlags;
175 import com.android.adservices.service.Flags;
176 import com.android.adservices.service.FlagsFactory;
177 import com.android.adservices.service.adid.AdIdCacheManager;
178 import com.android.adservices.service.adselection.debug.AuctionServerDebugConfigurationGenerator;
179 import com.android.adservices.service.adselection.debug.ConsentedDebugConfigurationGeneratorFactory;
180 import com.android.adservices.service.adselection.encryption.AdSelectionEncryptionKey;
181 import com.android.adservices.service.adselection.encryption.ObliviousHttpEncryptor;
182 import com.android.adservices.service.adselection.encryption.ObliviousHttpEncryptorImpl;
183 import com.android.adservices.service.adselection.encryption.ProtectedServersEncryptionConfigManager;
184 import com.android.adservices.service.adselection.encryption.ServerAuctionCoordinatorUriStrategyFactory;
185 import com.android.adservices.service.common.AdSelectionServiceFilter;
186 import com.android.adservices.service.common.AppImportanceFilter;
187 import com.android.adservices.service.common.FledgeAuthorizationFilter;
188 import com.android.adservices.service.common.RetryStrategyFactory;
189 import com.android.adservices.service.common.Throttler;
190 import com.android.adservices.service.common.cache.CacheProviderFactory;
191 import com.android.adservices.service.common.httpclient.AdServicesHttpClientResponse;
192 import com.android.adservices.service.common.httpclient.AdServicesHttpsClient;
193 import com.android.adservices.service.consent.ConsentManager;
194 import com.android.adservices.service.devapi.DevContext;
195 import com.android.adservices.service.devapi.DevContextFilter;
196 import com.android.adservices.service.devapi.DevSession;
197 import com.android.adservices.service.devapi.DevSessionState;
198 import com.android.adservices.service.exception.FilterException;
199 import com.android.adservices.service.kanon.KAnonSignJoinFactory;
200 import com.android.adservices.service.proto.bidding_auction_servers.BiddingAuctionServers.AuctionResult;
201 import com.android.adservices.service.proto.bidding_auction_servers.BiddingAuctionServers.BuyerInput;
202 import com.android.adservices.service.proto.bidding_auction_servers.BiddingAuctionServers.ProtectedAppSignals;
203 import com.android.adservices.service.proto.bidding_auction_servers.BiddingAuctionServers.ProtectedAuctionInput;
204 import com.android.adservices.service.proto.bidding_auction_servers.BiddingAuctionServers.WinReportingUrls;
205 import com.android.adservices.service.proto.bidding_auction_servers.BiddingAuctionServers.WinReportingUrls.ReportingUrls;
206 import com.android.adservices.service.shell.ShellCommandResult;
207 import com.android.adservices.service.shell.adselection.AdSelectionShellCommandFactory;
208 import com.android.adservices.service.shell.adselection.ViewAuctionResultCommand;
209 import com.android.adservices.service.stats.AdServicesLogger;
210 import com.android.adservices.service.stats.AdServicesLoggerImpl;
211 import com.android.adservices.service.stats.AdServicesStatsLog;
212 import com.android.adservices.service.stats.FetchProcessLogger;
213 import com.android.adservices.service.stats.GetAdSelectionDataApiCalledStats;
214 import com.android.adservices.service.stats.GetAdSelectionDataBuyerInputGeneratedStats;
215 import com.android.adservices.shared.testing.SkipLoggingUsageRule;
216 import com.android.adservices.shared.testing.annotations.SetFlagFalse;
217 import com.android.adservices.shared.testing.annotations.SetFlagTrue;
218 import com.android.adservices.shared.testing.annotations.SetIntegerFlag;
219 import com.android.adservices.shared.testing.annotations.SetLongFlag;
220 import com.android.adservices.testutils.DevSessionHelper;
221 import com.android.dx.mockito.inline.extended.ExtendedMockito;
222 import com.android.modules.utils.testing.ExtendedMockitoRule.MockStatic;
223 
224 import com.google.common.collect.ImmutableList;
225 import com.google.common.collect.ImmutableSet;
226 import com.google.common.io.BaseEncoding;
227 import com.google.common.util.concurrent.FluentFuture;
228 import com.google.common.util.concurrent.Futures;
229 import com.google.common.util.concurrent.ListenableFuture;
230 import com.google.mockwebserver.Dispatcher;
231 import com.google.mockwebserver.MockResponse;
232 import com.google.mockwebserver.RecordedRequest;
233 import com.google.protobuf.ByteString;
234 import com.google.protobuf.InvalidProtocolBufferException;
235 
236 import org.json.JSONObject;
237 import org.junit.After;
238 import org.junit.Assert;
239 import org.junit.Assume;
240 import org.junit.Before;
241 import org.junit.Rule;
242 import org.junit.Test;
243 import org.junit.function.ThrowingRunnable;
244 import org.mockito.ArgumentCaptor;
245 import org.mockito.Mock;
246 import org.mockito.stubbing.Answer;
247 
248 import java.io.IOException;
249 import java.io.OutputStreamWriter;
250 import java.io.PrintWriter;
251 import java.io.StringWriter;
252 import java.io.UncheckedIOException;
253 import java.nio.charset.StandardCharsets;
254 import java.time.Instant;
255 import java.util.Arrays;
256 import java.util.Collections;
257 import java.util.HashMap;
258 import java.util.HashSet;
259 import java.util.List;
260 import java.util.Map;
261 import java.util.Objects;
262 import java.util.Optional;
263 import java.util.Set;
264 import java.util.concurrent.CountDownLatch;
265 import java.util.concurrent.ExecutorService;
266 import java.util.concurrent.ScheduledThreadPoolExecutor;
267 import java.util.concurrent.TimeUnit;
268 import java.util.function.Function;
269 import java.util.stream.Collectors;
270 
271 @SetFlagTrue(KEY_FLEDGE_FREQUENCY_CAP_FILTERING_ENABLED)
272 @SetFlagTrue(KEY_FLEDGE_AUCTION_SERVER_ENABLED_FOR_UPDATE_HISTOGRAM)
273 @SetFlagTrue(KEY_FLEDGE_AUCTION_SERVER_ENABLED_FOR_REPORT_EVENT)
274 @SetFlagTrue(KEY_FLEDGE_AUCTION_SERVER_ENABLED_FOR_SELECT_ADS_MEDIATION)
275 @SetFlagTrue(KEY_FLEDGE_REGISTER_AD_BEACON_ENABLED)
276 @SetFlagFalse(KEY_FLEDGE_AUCTION_SERVER_KILL_SWITCH)
277 @SetFlagTrue(KEY_FLEDGE_AUCTION_SERVER_ENABLED_FOR_REPORT_IMPRESSION)
278 @SetFlagFalse(KEY_FLEDGE_AUCTION_SERVER_ENABLE_DEBUG_REPORTING)
279 @SetFlagFalse(KEY_FLEDGE_AUCTION_SERVER_OMIT_ADS_ENABLED)
280 @SetFlagTrue(KEY_PROTECTED_SIGNALS_PERIODIC_ENCODING_ENABLED)
281 @SetFlagFalse(KEY_FLEDGE_AUCTION_SERVER_REFRESH_EXPIRED_KEYS_DURING_AUCTION)
282 @SetFlagFalse(KEY_FLEDGE_AUCTION_SERVER_MEDIA_TYPE_CHANGE_ENABLED)
283 @MockStatic(ConsentManager.class)
284 @MockStatic(AppImportanceFilter.class)
285 @MockStatic(DebugFlags.class)
286 @MockStatic(FlagsFactory.class)
287 // TODO (b/384952360): refine CEL related verifications later
288 @SkipLoggingUsageRule(reason = "b/384952360")
289 public final class AuctionServerIntegrationTest extends AdServicesExtendedMockitoTestCase {
290     private static final int COUNTDOWN_LATCH_LIMIT_SECONDS = 10;
291     private static final int CALLER_UID = Process.myUid();
292     private static final String CALLER_PACKAGE_NAME = CommonFixture.TEST_PACKAGE_NAME;
293     private static final AdTechIdentifier SELLER = AdSelectionConfigFixture.SELLER;
294     private static final AdTechIdentifier WINNER_BUYER = AdSelectionConfigFixture.BUYER;
295     private static final AdTechIdentifier DIFFERENT_BUYER = BUYER_2;
296     private static final DBAdData WINNER_AD =
297             DBAdDataFixture.getValidDbAdDataListByBuyerWithAdRenderId(WINNER_BUYER).get(0);
298     private static final Uri WINNER_AD_RENDER_URI = WINNER_AD.getRenderUri();
299     private static final Set<Integer> WINNER_AD_COUNTERS = WINNER_AD.getAdCounterKeys();
300     private static final String BUYER_REPORTING_URI =
301             CommonFixture.getUri(WINNER_BUYER, "/reporting").toString();
302     private static final String SELLER_REPORTING_URI =
303             CommonFixture.getUri(SELLER, "/reporting").toString();
304     private static final String BUYER_INTERACTION_KEY = "buyer-interaction-key";
305     private static final String BUYER_INTERACTION_URI =
306             CommonFixture.getUri(WINNER_BUYER, "/interaction").toString();
307     private static final String SELLER_INTERACTION_KEY = "seller-interaction-key";
308     private static final String SELLER_INTERACTION_URI =
309             CommonFixture.getUri(SELLER, "/interaction").toString();
310 
311     public static final AppInstallFilters CURRENT_APP_FILTER =
312             new AppInstallFilters.Builder()
313                     .setPackageNames(new HashSet<>(Arrays.asList(CommonFixture.TEST_PACKAGE_NAME)))
314                     .build();
315 
316     private static final String COORDINATOR_URL = "https://example.com/keys";
317     private static final String COORDINATOR_HOST = "https://example.com";
318     private static final String DEFAULT_FETCH_URI = "https://default-example.com/keys";
319 
320     private static final String COORDINATOR_ALLOWLIST = COORDINATOR_URL + "," + DEFAULT_FETCH_URI;
321 
322     private static final WinReportingUrls WIN_REPORTING_URLS =
323             WinReportingUrls.newBuilder()
324                     .setBuyerReportingUrls(
325                             ReportingUrls.newBuilder()
326                                     .setReportingUrl(BUYER_REPORTING_URI)
327                                     .putInteractionReportingUrls(
328                                             BUYER_INTERACTION_KEY, BUYER_INTERACTION_URI)
329                                     .build())
330                     .setTopLevelSellerReportingUrls(
331                             ReportingUrls.newBuilder()
332                                     .setReportingUrl(SELLER_REPORTING_URI)
333                                     .putInteractionReportingUrls(
334                                             SELLER_INTERACTION_KEY, SELLER_INTERACTION_URI)
335                                     .build())
336                     .build();
337     private static final String WINNING_CUSTOM_AUDIENCE_NAME = "test-name";
338     private static final String WINNING_CUSTOM_AUDIENCE_OWNER = "test-owner";
339     private static final float BID = 5;
340     private static final float SCORE = 5;
341     private static final AuctionResult AUCTION_RESULT =
342             AuctionResult.newBuilder()
343                     .setAdType(AuctionResult.AdType.REMARKETING_AD)
344                     .setAdRenderUrl(WINNER_AD_RENDER_URI.toString())
345                     .setCustomAudienceName(WINNING_CUSTOM_AUDIENCE_NAME)
346                     .setCustomAudienceOwner(WINNING_CUSTOM_AUDIENCE_OWNER)
347                     .setBuyer(WINNER_BUYER.toString())
348                     .setBid(BID)
349                     .setScore(SCORE)
350                     .setIsChaff(false)
351                     .setWinReportingUrls(WIN_REPORTING_URLS)
352                     .build();
353 
354     private static final AuctionResult AUCTION_RESULT_PAS =
355             AuctionResult.newBuilder()
356                     .setAdType(AuctionResult.AdType.APP_INSTALL_AD)
357                     .setAdRenderUrl(WINNER_AD_RENDER_URI.toString())
358                     .setCustomAudienceOwner(WINNING_CUSTOM_AUDIENCE_OWNER)
359                     .setBuyer(WINNER_BUYER.toString())
360                     .setBid(BID)
361                     .setScore(SCORE)
362                     .setIsChaff(false)
363                     .setWinReportingUrls(WIN_REPORTING_URLS)
364                     .build();
365     private static final AuctionResult AUCTION_RESULT_CHAFF =
366             AuctionResult.newBuilder().setIsChaff(true).build();
367     private static final int NUM_BUYERS = 2;
368 
369     private static final long AUCTION_SERVER_AD_ID_FETCHER_TIMEOUT_MS = 20;
370     private static final boolean CONSOLE_MESSAGE_IN_LOGS_ENABLED = true;
371     private ExecutorService mLightweightExecutorService;
372     private ExecutorService mBackgroundExecutorService;
373     private ScheduledThreadPoolExecutor mScheduledExecutor;
374     private AdServicesHttpsClient mAdServicesHttpsClientSpy;
375     private AdServicesLogger mAdServicesLoggerMock;
376     private ServerAuctionTestHelper mServerAuctionTestHelper;
377 
378     @Rule(order = 2)
379     public final MockWebServerRule mockWebServerRule = MockWebServerRuleFactory.createForHttps();
380 
381     public DevSessionHelper mDevSessionHelper;
382 
383     // This object access some system APIs
384     @Mock public DevContextFilter mDevContextFilterMock;
385     @Mock public AppImportanceFilter mAppImportanceFilterMock;
386 
387     @Mock private FledgeAuthorizationFilter mFledgeAuthorizationFilterMock;
388     private AdFilteringFeatureFactory mAdFilteringFeatureFactory;
389     @Mock private ConsentManager mConsentManagerMock;
390     private CustomAudienceDao mCustomAudienceDaoSpy;
391     private ProtectedSignalsDao mProtectedSignalsDao;
392     private EncodedPayloadDao mEncodedPayloadDaoSpy;
393     private AdSelectionEntryDao mAdSelectionEntryDao;
394     private AppInstallDao mAppInstallDao;
395     private FrequencyCapDao mFrequencyCapDaoSpy;
396     private com.android.adservices.data.encryptionkey.EncryptionKeyDao mEncryptionKeyDao;
397     private ProtectedServersEncryptionConfigDao mProtectedServersEncryptionConfigDao;
398     private EnrollmentDao mEnrollmentDao;
399     private EncryptionContextDao mEncryptionContextDao;
400     @Mock private ObliviousHttpEncryptor mObliviousHttpEncryptorMock;
401     @Mock private AdSelectionServiceFilter mAdSelectionServiceFilterMock;
402     private AdSelectionService mAdSelectionService;
403     private AuctionServerPayloadFormatter mPayloadFormatter;
404     private AuctionServerPayloadExtractor mPayloadExtractor;
405     private AuctionServerDataCompressor mDataCompressor;
406     private AdSelectionDebugReportDao mAdSelectionDebugReportDaoSpy;
407     private AdIdFetcher mAdIdFetcher;
408     private MockAdIdWorker mMockAdIdWorker;
409     @Mock private KAnonSignJoinFactory mUnusedKAnonSignJoinFactory;
410     @Mock private AdServicesHttpsClient mMockHttpClient;
411     private RetryStrategyFactory mRetryStrategyFactory;
412     private AuctionServerDebugConfigurationGenerator mAuctionServerDebugConfigurationGenerator;
413     @Mock private DatastoreManager mDatastoreManager;
414     private ServerAuctionCoordinatorUriStrategyFactory mServerAuctionCoordinatorUriStrategyFactory;
415     @Mock DevContext mDevContextMock;
416 
417     @Before
setUp()418     public void setUp() {
419         // NOTE: not using annotation to set string flags below because the constants are private
420         flags.setFlag(KEY_FLEDGE_AUCTION_SERVER_COORDINATOR_URL_ALLOWLIST, COORDINATOR_ALLOWLIST);
421         flags.setFlag(KEY_FLEDGE_AUCTION_SERVER_AUCTION_KEY_FETCH_URI, DEFAULT_FETCH_URI);
422         flags.setFlag(
423                 KEY_FLEDGE_AUCTION_SERVER_AD_ID_FETCHER_TIMEOUT_MS,
424                 AUCTION_SERVER_AD_ID_FETCHER_TIMEOUT_MS);
425 
426         mLightweightExecutorService = AdServicesExecutors.getLightWeightExecutor();
427         mBackgroundExecutorService = AdServicesExecutors.getBackgroundExecutor();
428         mScheduledExecutor = AdServicesExecutors.getScheduler();
429         mocker.mockGetDebugFlags(mFakeDebugFlags);
430         mockGetConsentNotificationDebugMode(false);
431 
432         mAdServicesLoggerMock = ExtendedMockito.mock(AdServicesLoggerImpl.class);
433         mCustomAudienceDaoSpy =
434                 spy(
435                         Room.inMemoryDatabaseBuilder(mContext, CustomAudienceDatabase.class)
436                                 .addTypeConverter(new DBCustomAudience.Converters(true, true, true))
437                                 .build()
438                                 .customAudienceDao());
439         mEncodedPayloadDaoSpy =
440                 spy(
441                         Room.inMemoryDatabaseBuilder(mContext, ProtectedSignalsDatabase.class)
442                                 .build()
443                                 .getEncodedPayloadDao());
444         mAdSelectionEntryDao =
445                 Room.inMemoryDatabaseBuilder(mContext, AdSelectionDatabase.class)
446                         .build()
447                         .adSelectionEntryDao();
448         ProtectedSignalsDatabase protectedSignalsDatabase =
449                 Room.inMemoryDatabaseBuilder(mContext, ProtectedSignalsDatabase.class).build();
450         mProtectedSignalsDao = protectedSignalsDatabase.protectedSignalsDao();
451         SharedStorageDatabase sharedDb =
452                 Room.inMemoryDatabaseBuilder(mContext, SharedStorageDatabase.class).build();
453 
454         mocker.mockGetFlags(mFakeFlags);
455         mAppInstallDao = sharedDb.appInstallDao();
456         mFrequencyCapDaoSpy = spy(sharedDb.frequencyCapDao());
457         AdSelectionServerDatabase serverDb =
458                 Room.inMemoryDatabaseBuilder(mContext, AdSelectionServerDatabase.class).build();
459         mEncryptionKeyDao =
460                 com.android.adservices.data.encryptionkey.EncryptionKeyDao.getInstance();
461         mEnrollmentDao = EnrollmentDao.getInstance();
462         mProtectedServersEncryptionConfigDao = serverDb.protectedServersEncryptionConfigDao();
463         mEncryptionContextDao = serverDb.encryptionContextDao();
464         mAdFilteringFeatureFactory =
465                 new AdFilteringFeatureFactory(mAppInstallDao, mFrequencyCapDaoSpy, mFakeFlags);
466         when(ConsentManager.getInstance()).thenReturn(mConsentManagerMock);
467         when(AppImportanceFilter.create(any(), any())).thenReturn(mAppImportanceFilterMock);
468         doNothing()
469                 .when(mAppImportanceFilterMock)
470                 .assertCallerIsInForeground(anyInt(), anyInt(), any());
471         mAdServicesHttpsClientSpy =
472                 spy(
473                         new AdServicesHttpsClient(
474                                 AdServicesExecutors.getBlockingExecutor(),
475                                 CacheProviderFactory.createNoOpCache()));
476         AdSelectionDebugReportingDatabase adSelectionDebugReportingDatabase =
477                 Room.inMemoryDatabaseBuilder(mContext, AdSelectionDebugReportingDatabase.class)
478                         .build();
479         mAdSelectionDebugReportDaoSpy =
480                 spy(adSelectionDebugReportingDatabase.getAdSelectionDebugReportDao());
481         mMockAdIdWorker = new MockAdIdWorker(new AdIdCacheManager(mContext));
482         mAdIdFetcher =
483                 new AdIdFetcher(
484                         mContext, mMockAdIdWorker, mLightweightExecutorService, mScheduledExecutor);
485         mRetryStrategyFactory = RetryStrategyFactory.createInstanceForTesting();
486         ConsentedDebugConfigurationDao consentedDebugConfigurationDao =
487                 Room.inMemoryDatabaseBuilder(mContext, AdSelectionDatabase.class)
488                         .build()
489                         .consentedDebugConfigurationDao();
490         ConsentedDebugConfigurationGeneratorFactory consentedDebugConfigurationGeneratorFactory =
491                 new ConsentedDebugConfigurationGeneratorFactory(
492                         false, consentedDebugConfigurationDao);
493         mAuctionServerDebugConfigurationGenerator =
494                 new AuctionServerDebugConfigurationGenerator(
495                         Flags.ADID_KILL_SWITCH,
496                         Flags.DEFAULT_AUCTION_SERVER_AD_ID_FETCHER_TIMEOUT_MS,
497                         Flags.FLEDGE_AUCTION_SERVER_ENABLE_DEBUG_REPORTING,
498                         Flags.DEFAULT_FLEDGE_AUCTION_SERVER_ENABLE_PAS_UNLIMITED_EGRESS,
499                         Flags.DEFAULT_PROD_DEBUG_IN_AUCTION_SERVER,
500                         mAdIdFetcher,
501                         consentedDebugConfigurationGeneratorFactory.create(),
502                         mLightweightExecutorService);
503 
504         mServerAuctionCoordinatorUriStrategyFactory =
505                 new ServerAuctionCoordinatorUriStrategyFactory(
506                         mFakeFlags.getFledgeAuctionServerCoordinatorUrlAllowlist());
507 
508         mAdSelectionService = createAdSelectionService();
509 
510         mPayloadFormatter =
511                 AuctionServerPayloadFormatterFactory.createPayloadFormatter(
512                         mFakeFlags.getFledgeAuctionServerPayloadFormatVersion(),
513                         mFakeFlags.getFledgeAuctionServerPayloadBucketSizes(),
514                         /* sellerConfiguration= */ null);
515         mPayloadExtractor =
516                 AuctionServerPayloadFormatterFactory.createPayloadExtractor(
517                         mFakeFlags.getFledgeAuctionServerPayloadFormatVersion(),
518                         mAdServicesLoggerMock);
519 
520         mDataCompressor =
521                 AuctionServerDataCompressorFactory.getDataCompressor(
522                         mFakeFlags.getFledgeAuctionServerCompressionAlgorithmVersion());
523 
524         doReturn(DevContext.createForDevOptionsDisabled())
525                 .when(mDevContextFilterMock)
526                 .createDevContext();
527         mMockAdIdWorker.setResult(AdId.ZERO_OUT, true);
528 
529         mDevSessionHelper =
530                 new DevSessionHelper(
531                         mCustomAudienceDaoSpy,
532                         mAppInstallDao,
533                         mFrequencyCapDaoSpy,
534                         mProtectedSignalsDao,
535                         mEncodedPayloadDaoSpy,
536                         mDatastoreManager,
537                         mProtectedServersEncryptionConfigDao);
538 
539         mServerAuctionTestHelper =
540                 ServerAuctionTestHelper.getDefaultInstance(mAdServicesLoggerMock);
541     }
542 
543     @After
tearDown()544     public void tearDown() {
545         if (mAdServicesHttpsClientSpy != null) {
546             reset(mAdServicesHttpsClientSpy);
547         }
548         mDevSessionHelper.endDevSession();
549     }
550 
551     @Test
552     @SetFlagTrue(KEY_FLEDGE_AUCTION_SERVER_KILL_SWITCH)
553     @ExpectErrorLogUtilCall(
554             errorCode =
555                     AD_SERVICES_ERROR_REPORTED__ERROR_CODE__AD_SELECTION_SERVICE_AUCTION_SERVER_API_NOT_AVAILABLE,
556             ppapiName = AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__GET_AD_SELECTION_DATA)
557     @ExpectErrorLogUtilCall(
558             errorCode =
559                     AD_SERVICES_ERROR_REPORTED__ERROR_CODE__AD_SELECTION_SERVICE_AUCTION_SERVER_API_NOT_AVAILABLE,
560             ppapiName = AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__PERSIST_AD_SELECTION_RESULT)
testAuctionServer_killSwitchDisabled_throwsException()561     public void testAuctionServer_killSwitchDisabled_throwsException() throws InterruptedException {
562         mAdSelectionService = createAdSelectionService(); // create the service again with new flags
563 
564         GetAdSelectionDataInput getAdSelectionDataInput =
565                 new GetAdSelectionDataInput.Builder()
566                         .setSeller(SELLER)
567                         .setCallerPackageName(CALLER_PACKAGE_NAME)
568                         .build();
569 
570         ThrowingRunnable getAdSelectionDataRunnable =
571                 () -> invokeGetAdSelectionData(mAdSelectionService, getAdSelectionDataInput);
572 
573         PersistAdSelectionResultInput persistAdSelectionResultInput =
574                 new PersistAdSelectionResultInput.Builder()
575                         .setAdSelectionId(123456L)
576                         .setSeller(SELLER)
577                         .setAdSelectionResult(new byte[42])
578                         .setCallerPackageName(CALLER_PACKAGE_NAME)
579                         .build();
580         ThrowingRunnable persistAdSelectionResultRunnable =
581                 () ->
582                         invokePersistAdSelectionResult(
583                                 mAdSelectionService, persistAdSelectionResultInput);
584 
585         Assert.assertThrows(
586                 AUCTION_SERVER_API_IS_NOT_AVAILABLE,
587                 IllegalStateException.class,
588                 getAdSelectionDataRunnable);
589         Assert.assertThrows(
590                 AUCTION_SERVER_API_IS_NOT_AVAILABLE,
591                 IllegalStateException.class,
592                 persistAdSelectionResultRunnable);
593     }
594 
595     @Test
596     @ExpectErrorLogUtilCall(
597             errorCode =
598                     AD_SERVICES_ERROR_REPORTED__ERROR_CODE__GET_AD_SELECTION_DATA_RUNNER_FILTER_AND_REVOKED_CONSENT_EXCEPTION,
599             ppapiName = AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__GET_AD_SELECTION_DATA)
600     @ExpectErrorLogUtilCall(
601             errorCode =
602                     AD_SERVICES_ERROR_REPORTED__ERROR_CODE__PERSIST_AD_SELECTION_RESULT_RUNNER_REVOKED_CONSENT_FILTER_EXCEPTION,
603             ppapiName = AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__PERSIST_AD_SELECTION_RESULT)
604     @ExpectErrorLogUtilCall(
605             errorCode =
606                     AD_SERVICES_ERROR_REPORTED__ERROR_CODE__PERSIST_AD_SELECTION_RESULT_RUNNER_NOTIFY_EMPTY_SUCCESS_SILENT_CONSENT_FAILURE,
607             ppapiName = AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__PERSIST_AD_SELECTION_RESULT)
testAuctionServer_consentDisabled_throwsException()608     public void testAuctionServer_consentDisabled_throwsException() throws Exception {
609         doThrow(new FilterException(new ConsentManager.RevokedConsentException()))
610                 .when(mAdSelectionServiceFilterMock)
611                 .filterRequest(
612                         eq(SELLER),
613                         eq(CALLER_PACKAGE_NAME),
614                         eq(false),
615                         eq(true),
616                         eq(true),
617                         eq(CALLER_UID),
618                         eq(
619                                 AdServicesStatsLog
620                                         .AD_SERVICES_API_CALLED__API_NAME__GET_AD_SELECTION_DATA),
621                         eq(Throttler.ApiKey.FLEDGE_API_GET_AD_SELECTION_DATA),
622                         eq(DevContext.createForDevOptionsDisabled()));
623         doThrow(new FilterException(new ConsentManager.RevokedConsentException()))
624                 .when(mAdSelectionServiceFilterMock)
625                 .filterRequest(
626                         eq(SELLER),
627                         eq(CALLER_PACKAGE_NAME),
628                         eq(false),
629                         eq(true),
630                         eq(true),
631                         eq(CALLER_UID),
632                         eq(
633                                 AdServicesStatsLog
634                                         .AD_SERVICES_API_CALLED__API_NAME__PERSIST_AD_SELECTION_RESULT),
635                         eq(Throttler.ApiKey.FLEDGE_API_PERSIST_AD_SELECTION_RESULT),
636                         eq(DevContext.createForDevOptionsDisabled()));
637 
638         mAdSelectionService = createAdSelectionService(); // create the service again with new flags
639 
640         GetAdSelectionDataInput getAdSelectionDataInput =
641                 new GetAdSelectionDataInput.Builder()
642                         .setSeller(SELLER)
643                         .setCallerPackageName(CALLER_PACKAGE_NAME)
644                         .build();
645 
646         GetAdSelectionDataTestCallback callback1 =
647                 invokeGetAdSelectionData(mAdSelectionService, getAdSelectionDataInput);
648         long adSelectionId = callback1.mGetAdSelectionDataResponse.getAdSelectionId();
649 
650         assertTrue(callback1.mIsSuccess);
651         Assert.assertNotNull(callback1.mGetAdSelectionDataResponse.getAdSelectionData());
652         Assert.assertEquals(
653                 REVOKED_CONSENT_RANDOM_DATA_SIZE,
654                 callback1.mGetAdSelectionDataResponse.getAdSelectionData().length);
655 
656         PersistAdSelectionResultInput persistAdSelectionResultInput =
657                 new PersistAdSelectionResultInput.Builder()
658                         .setAdSelectionId(adSelectionId)
659                         .setSeller(SELLER)
660                         .setAdSelectionResult(new byte[42])
661                         .setCallerPackageName(CALLER_PACKAGE_NAME)
662                         .build();
663         PersistAdSelectionResultTestCallback callback2 =
664                 invokePersistAdSelectionResult(mAdSelectionService, persistAdSelectionResultInput);
665         assertTrue(callback2.mIsSuccess);
666         Assert.assertEquals(
667                 adSelectionId, callback2.mPersistAdSelectionResultResponse.getAdSelectionId());
668         Assert.assertNotNull(callback2.mPersistAdSelectionResultResponse.getAdRenderUri());
669         Assert.assertEquals(
670                 Uri.EMPTY, callback2.mPersistAdSelectionResultResponse.getAdRenderUri());
671     }
672 
673     @Test
testAuctionServerFlow_withoutEncrypt_validRequest_BothFiltersEnabled()674     public void testAuctionServerFlow_withoutEncrypt_validRequest_BothFiltersEnabled()
675             throws Exception {
676         setFlagsWithBothFiltersEnabled();
677         mAdFilteringFeatureFactory =
678                 new AdFilteringFeatureFactory(mAppInstallDao, mFrequencyCapDaoSpy, mFakeFlags);
679         // Create the service again with new flags and new feature factory
680         AdSelectionService adSelectionService = createAdSelectionService();
681 
682         when(mObliviousHttpEncryptorMock.encryptBytes(
683                         any(byte[].class), anyLong(), anyLong(), any(), any()))
684                 .thenAnswer(
685                         invocation ->
686                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
687         when(mObliviousHttpEncryptorMock.decryptBytes(any(byte[].class), anyLong()))
688                 .thenAnswer(invocation -> invocation.getArgument(0));
689 
690         int sequenceNumber1 = 1;
691         int sequenceNumber2 = 2;
692         int sequenceNumber3 = 3;
693         int filterMaxCount = 1;
694         List<DBAdData> ads =
695                 List.of(
696                         getFilterableAndServerEligibleFCapAd(sequenceNumber1, filterMaxCount),
697                         getFilterableAndServerEligibleAppInstallAd(sequenceNumber2),
698                         DBAdDataFixture.getValidDbAdDataNoFiltersBuilder(
699                                         WINNER_BUYER, sequenceNumber3)
700                                 .setAdRenderId(Integer.toString(sequenceNumber3))
701                                 .build());
702 
703         DBCustomAudience winningCustomAudience =
704                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
705                                 WINNER_BUYER,
706                                 WINNING_CUSTOM_AUDIENCE_NAME,
707                                 WINNING_CUSTOM_AUDIENCE_OWNER)
708                         .setAds(ads)
709                         .build();
710         Assert.assertNotNull(winningCustomAudience.getAds());
711         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
712                 winningCustomAudience, Uri.EMPTY, false, List.of());
713 
714         GetAdSelectionDataInput input =
715                 new GetAdSelectionDataInput.Builder()
716                         .setSeller(SELLER)
717                         .setCallerPackageName(CALLER_PACKAGE_NAME)
718                         .build();
719 
720         GetAdSelectionDataTestCallback getAdSelectionDataTestCallback =
721                 invokeGetAdSelectionData(adSelectionService, input);
722         long adSelectionId =
723                 getAdSelectionDataTestCallback.mGetAdSelectionDataResponse.getAdSelectionId();
724         assertTrue(getAdSelectionDataTestCallback.mIsSuccess);
725 
726         // Since encryption is mocked to do nothing then just passing encrypted byte[]
727         List<String> adRenderIdsFromBuyerInput =
728                 extractCAAdRenderIdListFromBuyerInput(
729                         getAdSelectionDataTestCallback,
730                         winningCustomAudience.getBuyer(),
731                         winningCustomAudience.getName(),
732                         winningCustomAudience.getOwner());
733 
734         // Expect no ads are filtered
735         assertThat(adRenderIdsFromBuyerInput.size()).isEqualTo(ads.size());
736 
737         PersistAdSelectionResultInput persistAdSelectionResultInput =
738                 new PersistAdSelectionResultInput.Builder()
739                         .setAdSelectionId(adSelectionId)
740                         .setSeller(SELLER)
741                         .setAdSelectionResult(prepareAuctionResultBytes())
742                         .setCallerPackageName(CALLER_PACKAGE_NAME)
743                         .build();
744 
745         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
746                 invokePersistAdSelectionResult(adSelectionService, persistAdSelectionResultInput);
747 
748         assertTrue(persistAdSelectionResultTestCallback.mIsSuccess);
749 
750         // FCap non-win histogram update
751         UpdateAdCounterHistogramInput updateHistogramInput =
752                 new UpdateAdCounterHistogramInput.Builder(
753                                 adSelectionId,
754                                 FrequencyCapFilters.AD_EVENT_TYPE_CLICK,
755                                 SELLER,
756                                 CALLER_PACKAGE_NAME)
757                         .build();
758         UpdateAdCounterHistogramTestCallback updateHistogramCallback =
759                 invokeUpdateAdCounterHistogram(adSelectionService, updateHistogramInput);
760         assertTrue(updateHistogramCallback.mIsSuccess);
761 
762         // Call set app install advertisers
763         setAppInstallAdvertisers(ImmutableSet.of(WINNER_BUYER), adSelectionService);
764 
765         // Collect device data again and expect to see both filter ads out
766         GetAdSelectionDataInput input2 =
767                 new GetAdSelectionDataInput.Builder()
768                         .setSeller(SELLER)
769                         .setCallerPackageName(CALLER_PACKAGE_NAME)
770                         .build();
771 
772         GetAdSelectionDataTestCallback getAdSelectionDataTestCallback2 =
773                 invokeGetAdSelectionData(adSelectionService, input2);
774 
775         // Since encryption is mocked to do nothing then just passing encrypted byte[]
776         List<String> adRenderIdsFromBuyerInput2 =
777                 extractCAAdRenderIdListFromBuyerInput(
778                         getAdSelectionDataTestCallback2,
779                         winningCustomAudience.getBuyer(),
780                         winningCustomAudience.getName(),
781                         winningCustomAudience.getOwner());
782         // Both ads with filters are filtered out
783         assertThat(ads.size() - 2).isEqualTo(adRenderIdsFromBuyerInput2.size());
784 
785         // Assert that only ad remaining is the non filter one
786         assertThat(adRenderIdsFromBuyerInput2.get(0)).isEqualTo(Integer.toString(sequenceNumber3));
787     }
788 
789     @SetFlagTrue(KEY_ENABLE_CUSTOM_AUDIENCE_COMPONENT_ADS)
790     @Test
testAuctionServerFlow_withoutEncrypt_validRequest_ComponentAdsEnabled()791     public void testAuctionServerFlow_withoutEncrypt_validRequest_ComponentAdsEnabled()
792             throws Exception {
793         setComponentAdsEnabled();
794         // Create the service again with new flags
795         AdSelectionService adSelectionService = createAdSelectionService();
796 
797         when(mObliviousHttpEncryptorMock.encryptBytes(
798                         any(byte[].class), anyLong(), anyLong(), any(), any()))
799                 .thenAnswer(
800                         invocation ->
801                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
802         when(mObliviousHttpEncryptorMock.decryptBytes(any(byte[].class), anyLong()))
803                 .thenAnswer(invocation -> invocation.getArgument(0));
804 
805         DBCustomAudience winningCustomAudience =
806                 DBCustomAudienceFixture.getValidBuilderByBuyerNoFilters(
807                                 WINNER_BUYER,
808                                 WINNING_CUSTOM_AUDIENCE_NAME,
809                                 WINNING_CUSTOM_AUDIENCE_OWNER)
810                         .build();
811         Assert.assertNotNull(winningCustomAudience.getAds());
812         List<ComponentAdData> componentAds =
813                 ComponentAdDataFixture.getValidComponentAdsByBuyer(WINNER_BUYER);
814         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
815                 winningCustomAudience, Uri.EMPTY, /* debuggable= */ false, componentAds);
816 
817         GetAdSelectionDataInput input =
818                 new GetAdSelectionDataInput.Builder()
819                         .setSeller(SELLER)
820                         .setCallerPackageName(CALLER_PACKAGE_NAME)
821                         .build();
822 
823         GetAdSelectionDataTestCallback getAdSelectionDataTestCallback =
824                 invokeGetAdSelectionData(adSelectionService, input);
825         long adSelectionId =
826                 getAdSelectionDataTestCallback.mGetAdSelectionDataResponse.getAdSelectionId();
827         assertTrue(getAdSelectionDataTestCallback.mIsSuccess);
828 
829         AuctionResult auctionResultWithComponentAds =
830                 AuctionResult.newBuilder()
831                         .setAdType(AuctionResult.AdType.REMARKETING_AD)
832                         .setAdRenderUrl(WINNER_AD_RENDER_URI.toString())
833                         .setCustomAudienceName(WINNING_CUSTOM_AUDIENCE_NAME)
834                         .setCustomAudienceOwner(WINNING_CUSTOM_AUDIENCE_OWNER)
835                         .setBuyer(WINNER_BUYER.toString())
836                         .setBid(BID)
837                         .setScore(SCORE)
838                         .setIsChaff(false)
839                         .setWinReportingUrls(WIN_REPORTING_URLS)
840                         .addAllAdComponentRenderUrls(
841                                 List.of(
842                                         componentAds.get(0).getRenderUri().toString(),
843                                         componentAds.get(1).getRenderUri().toString(),
844                                         componentAds.get(2).getRenderUri().toString(),
845                                         componentAds.get(3).getRenderUri().toString()))
846                         .build();
847 
848         PersistAdSelectionResultInput persistAdSelectionResultInput =
849                 new PersistAdSelectionResultInput.Builder()
850                         .setAdSelectionId(adSelectionId)
851                         .setSeller(SELLER)
852                         .setAdSelectionResult(
853                                 prepareAuctionResultBytes(auctionResultWithComponentAds))
854                         .setCallerPackageName(CALLER_PACKAGE_NAME)
855                         .build();
856 
857         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
858                 invokePersistAdSelectionResult(adSelectionService, persistAdSelectionResultInput);
859 
860         assertTrue(persistAdSelectionResultTestCallback.mIsSuccess);
861         expect.that(
862                         persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
863                                 .getAdRenderUri())
864                 .isNotNull();
865         expect.that(
866                         persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
867                                 .getComponentAdUris())
868                 .containsExactlyElementsIn(
869                         List.of(
870                                 componentAds.get(0).getRenderUri(),
871                                 componentAds.get(1).getRenderUri(),
872                                 componentAds.get(2).getRenderUri(),
873                                 componentAds.get(3).getRenderUri()))
874                 .inOrder();
875     }
876 
877     @Test
testAuctionServerFlow_withoutEncrypt_validRequest_AppInstallDisabled()878     public void testAuctionServerFlow_withoutEncrypt_validRequest_AppInstallDisabled()
879             throws Exception {
880         // Enabling both filters to start so setAppInstallAdvertisers and updateAdCounterHistogram
881         // can be called as part of test setup
882         setFlagsWithBothFiltersEnabled();
883         mAdFilteringFeatureFactory =
884                 new AdFilteringFeatureFactory(mAppInstallDao, mFrequencyCapDaoSpy, mFakeFlags);
885         // create the service again with new flags and new feature factory
886         AdSelectionService adSelectionService = createAdSelectionService();
887         when(mObliviousHttpEncryptorMock.encryptBytes(
888                         any(byte[].class), anyLong(), anyLong(), any(), any()))
889                 .thenAnswer(
890                         invocation ->
891                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
892         when(mObliviousHttpEncryptorMock.decryptBytes(any(byte[].class), anyLong()))
893                 .thenAnswer(invocation -> invocation.getArgument(0));
894 
895         int sequenceNumber1 = 1;
896         int sequenceNumber2 = 2;
897         int filterMaxCount = 1;
898         List<DBAdData> ads =
899                 List.of(
900                         getFilterableAndServerEligibleFCapAd(sequenceNumber1, filterMaxCount),
901                         getFilterableAndServerEligibleAppInstallAd(sequenceNumber2));
902 
903         DBCustomAudience winningCustomAudience =
904                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
905                                 WINNER_BUYER,
906                                 WINNING_CUSTOM_AUDIENCE_NAME,
907                                 WINNING_CUSTOM_AUDIENCE_OWNER)
908                         .setAds(ads)
909                         .build();
910         Assert.assertNotNull(winningCustomAudience.getAds());
911         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
912                 winningCustomAudience, Uri.EMPTY, false, List.of());
913 
914         GetAdSelectionDataInput input =
915                 new GetAdSelectionDataInput.Builder()
916                         .setSeller(SELLER)
917                         .setCallerPackageName(CALLER_PACKAGE_NAME)
918                         .build();
919 
920         GetAdSelectionDataTestCallback getAdSelectionDataTestCallback =
921                 invokeGetAdSelectionData(adSelectionService, input);
922         long adSelectionId =
923                 getAdSelectionDataTestCallback.mGetAdSelectionDataResponse.getAdSelectionId();
924         assertTrue(getAdSelectionDataTestCallback.mIsSuccess);
925 
926         // Since encryption is mocked to do nothing then just passing encrypted byte[]
927         List<String> adRenderIdsFromBuyerInput =
928                 extractCAAdRenderIdListFromBuyerInput(
929                         getAdSelectionDataTestCallback,
930                         winningCustomAudience.getBuyer(),
931                         winningCustomAudience.getName(),
932                         winningCustomAudience.getOwner());
933         // Expect no ads are filtered
934         assertThat(adRenderIdsFromBuyerInput.size()).isEqualTo(ads.size());
935 
936         PersistAdSelectionResultInput persistAdSelectionResultInput =
937                 new PersistAdSelectionResultInput.Builder()
938                         .setAdSelectionId(adSelectionId)
939                         .setSeller(SELLER)
940                         .setAdSelectionResult(prepareAuctionResultBytes())
941                         .setCallerPackageName(CALLER_PACKAGE_NAME)
942                         .build();
943 
944         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
945                 invokePersistAdSelectionResult(adSelectionService, persistAdSelectionResultInput);
946 
947         assertTrue(persistAdSelectionResultTestCallback.mIsSuccess);
948 
949         // FCap non-win histogram update
950         UpdateAdCounterHistogramInput updateHistogramInput =
951                 new UpdateAdCounterHistogramInput.Builder(
952                                 adSelectionId,
953                                 FrequencyCapFilters.AD_EVENT_TYPE_CLICK,
954                                 SELLER,
955                                 CALLER_PACKAGE_NAME)
956                         .build();
957         UpdateAdCounterHistogramTestCallback updateHistogramCallback =
958                 invokeUpdateAdCounterHistogram(adSelectionService, updateHistogramInput);
959         assertTrue(updateHistogramCallback.mIsSuccess);
960 
961         // Call set app install advertisers
962         setAppInstallAdvertisers(ImmutableSet.of(WINNER_BUYER), adSelectionService);
963 
964         flags.setFlag(KEY_FLEDGE_APP_INSTALL_FILTERING_ENABLED, false);
965 
966         mAdFilteringFeatureFactory =
967                 new AdFilteringFeatureFactory(mAppInstallDao, mFrequencyCapDaoSpy, mFakeFlags);
968         // Create the service again with new flags and new feature factory
969         adSelectionService = createAdSelectionService();
970 
971         // Collect device data again and expect one less ads due to FCap filter
972         GetAdSelectionDataInput input2 =
973                 new GetAdSelectionDataInput.Builder()
974                         .setSeller(SELLER)
975                         .setCallerPackageName(CALLER_PACKAGE_NAME)
976                         .build();
977 
978         GetAdSelectionDataTestCallback getAdSelectionDataTestCallback2 =
979                 invokeGetAdSelectionData(adSelectionService, input2);
980 
981         // Since encryption is mocked to do nothing then just passing encrypted byte[]
982         List<String> adRenderIdsFromBuyerInput2 =
983                 extractCAAdRenderIdListFromBuyerInput(
984                         getAdSelectionDataTestCallback2,
985                         winningCustomAudience.getBuyer(),
986                         winningCustomAudience.getName(),
987                         winningCustomAudience.getOwner());
988         // Only fcap ad is filtered out since app install is disabled
989         Assert.assertEquals(1, adRenderIdsFromBuyerInput2.size());
990 
991         // Assert that only ad remaining is the app install ad
992         assertThat(adRenderIdsFromBuyerInput2.get(0)).isEqualTo(Integer.toString(sequenceNumber2));
993     }
994 
995     @Test
testAuctionServerFlow_withoutEncrypt_validRequest_FrequencyCapDisabled()996     public void testAuctionServerFlow_withoutEncrypt_validRequest_FrequencyCapDisabled()
997             throws Exception {
998         // Enabling both filters to start so setAppInstallAdvertisers and updateAdCounterHistogram
999         // can be called as part of test setup
1000         setFlagsWithBothFiltersEnabled();
1001         mAdFilteringFeatureFactory =
1002                 new AdFilteringFeatureFactory(mAppInstallDao, mFrequencyCapDaoSpy, mFakeFlags);
1003         // Create the service again with new flags and new feature factory
1004         AdSelectionService adSelectionService = createAdSelectionService();
1005 
1006         when(mObliviousHttpEncryptorMock.encryptBytes(
1007                         any(byte[].class), anyLong(), anyLong(), any(), any()))
1008                 .thenAnswer(
1009                         invocation ->
1010                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
1011         when(mObliviousHttpEncryptorMock.decryptBytes(any(byte[].class), anyLong()))
1012                 .thenAnswer(invocation -> invocation.getArgument(0));
1013 
1014         int sequenceNumber1 = 1;
1015         int sequenceNumber2 = 2;
1016         int filterMaxCount = 1;
1017         List<DBAdData> ads =
1018                 List.of(
1019                         getFilterableAndServerEligibleFCapAd(sequenceNumber1, filterMaxCount),
1020                         getFilterableAndServerEligibleAppInstallAd(sequenceNumber2));
1021 
1022         DBCustomAudience winningCustomAudience =
1023                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
1024                                 WINNER_BUYER,
1025                                 WINNING_CUSTOM_AUDIENCE_NAME,
1026                                 WINNING_CUSTOM_AUDIENCE_OWNER)
1027                         .setAds(ads)
1028                         .build();
1029         Assert.assertNotNull(winningCustomAudience.getAds());
1030         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
1031                 winningCustomAudience, Uri.EMPTY, false, List.of());
1032 
1033         GetAdSelectionDataInput input =
1034                 new GetAdSelectionDataInput.Builder()
1035                         .setSeller(SELLER)
1036                         .setCallerPackageName(CALLER_PACKAGE_NAME)
1037                         .build();
1038 
1039         GetAdSelectionDataTestCallback getAdSelectionDataTestCallback =
1040                 invokeGetAdSelectionData(adSelectionService, input);
1041         long adSelectionId =
1042                 getAdSelectionDataTestCallback.mGetAdSelectionDataResponse.getAdSelectionId();
1043         assertTrue(getAdSelectionDataTestCallback.mIsSuccess);
1044 
1045         // Since encryption is mocked to do nothing then just passing encrypted byte[]
1046         List<String> adRenderIdsFromBuyerInput =
1047                 extractCAAdRenderIdListFromBuyerInput(
1048                         getAdSelectionDataTestCallback,
1049                         winningCustomAudience.getBuyer(),
1050                         winningCustomAudience.getName(),
1051                         winningCustomAudience.getOwner());
1052         // Expect no ads are filtered
1053         assertThat(adRenderIdsFromBuyerInput.size()).isEqualTo(ads.size());
1054 
1055         PersistAdSelectionResultInput persistAdSelectionResultInput =
1056                 new PersistAdSelectionResultInput.Builder()
1057                         .setAdSelectionId(adSelectionId)
1058                         .setSeller(SELLER)
1059                         .setAdSelectionResult(prepareAuctionResultBytes())
1060                         .setCallerPackageName(CALLER_PACKAGE_NAME)
1061                         .build();
1062 
1063         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
1064                 invokePersistAdSelectionResult(adSelectionService, persistAdSelectionResultInput);
1065 
1066         assertTrue(persistAdSelectionResultTestCallback.mIsSuccess);
1067 
1068         // FCap FCap non-win histogram updat
1069         UpdateAdCounterHistogramInput updateHistogramInput =
1070                 new UpdateAdCounterHistogramInput.Builder(
1071                                 adSelectionId,
1072                                 FrequencyCapFilters.AD_EVENT_TYPE_CLICK,
1073                                 SELLER,
1074                                 CALLER_PACKAGE_NAME)
1075                         .build();
1076         UpdateAdCounterHistogramTestCallback updateHistogramCallback =
1077                 invokeUpdateAdCounterHistogram(adSelectionService, updateHistogramInput);
1078         assertTrue(updateHistogramCallback.mIsSuccess);
1079 
1080         // Call set app install advertisers
1081         setAppInstallAdvertisers(ImmutableSet.of(WINNER_BUYER), adSelectionService);
1082 
1083         flags.setFlag(KEY_FLEDGE_FREQUENCY_CAP_FILTERING_ENABLED, false);
1084         mAdFilteringFeatureFactory =
1085                 new AdFilteringFeatureFactory(mAppInstallDao, mFrequencyCapDaoSpy, mFakeFlags);
1086         adSelectionService =
1087                 createAdSelectionService(); // create the service again with new flags and
1088         // new feature factory
1089 
1090         // Collect device data again and expect one less ads due to app install filter
1091         GetAdSelectionDataInput input2 =
1092                 new GetAdSelectionDataInput.Builder()
1093                         .setSeller(SELLER)
1094                         .setCallerPackageName(CALLER_PACKAGE_NAME)
1095                         .build();
1096 
1097         GetAdSelectionDataTestCallback getAdSelectionDataTestCallback2 =
1098                 invokeGetAdSelectionData(adSelectionService, input2);
1099 
1100         // Since encryption is mocked to do nothing then just passing encrypted byte[]
1101         List<String> adRenderIdsFromBuyerInput2 =
1102                 extractCAAdRenderIdListFromBuyerInput(
1103                         getAdSelectionDataTestCallback2,
1104                         winningCustomAudience.getBuyer(),
1105                         winningCustomAudience.getName(),
1106                         winningCustomAudience.getOwner());
1107         // Only app install ad is filtered out since f cap is disabled
1108         Assert.assertEquals(1, adRenderIdsFromBuyerInput2.size());
1109 
1110         // Assert that only ad remaining is the fcap ad
1111         assertThat(adRenderIdsFromBuyerInput2.get(0)).isEqualTo(Integer.toString(sequenceNumber1));
1112     }
1113 
1114     @Test
1115     @SetFlagTrue(KEY_FLEDGE_AUCTION_SERVER_GET_AD_SELECTION_DATA_PAYLOAD_METRICS_ENABLED)
testGetAdSelectionData_withoutEncrypt_validRequest_successPayloadMetricsEnabled()1116     public void testGetAdSelectionData_withoutEncrypt_validRequest_successPayloadMetricsEnabled()
1117             throws Exception {
1118         ArgumentCaptor<GetAdSelectionDataApiCalledStats> argumentCaptorApiCalledStats =
1119                 ArgumentCaptor.forClass(GetAdSelectionDataApiCalledStats.class);
1120 
1121         ArgumentCaptor<GetAdSelectionDataBuyerInputGeneratedStats> argumentCaptorBuyerInputStats =
1122                 ArgumentCaptor.forClass(GetAdSelectionDataBuyerInputGeneratedStats.class);
1123         // Create a logging latch with count of 3, 2 for buyer input logs and 1 for api logs
1124         CountDownLatch loggingLatch = new CountDownLatch(3);
1125         Answer<Void> countDownAnswer =
1126                 unused -> {
1127                     loggingLatch.countDown();
1128                     return null;
1129                 };
1130         ExtendedMockito.doAnswer(countDownAnswer)
1131                 .when(mAdServicesLoggerMock)
1132                 .logGetAdSelectionDataApiCalledStats(any());
1133         ExtendedMockito.doAnswer(countDownAnswer)
1134                 .when(mAdServicesLoggerMock)
1135                 .logGetAdSelectionDataBuyerInputGeneratedStats(any());
1136 
1137         mAdSelectionService = createAdSelectionService(); // create the service again with new flags
1138 
1139         Map<String, AdTechIdentifier> nameAndBuyersMap =
1140                 Map.of(
1141                         "Shoes CA of Buyer 1", WINNER_BUYER,
1142                         "Shirts CA of Buyer 1", WINNER_BUYER,
1143                         "Shoes CA Of Buyer 2", DIFFERENT_BUYER);
1144         Set<AdTechIdentifier> buyers = new HashSet<>(nameAndBuyersMap.values());
1145         Map<String, DBCustomAudience> namesAndCustomAudiences =
1146                 createAndPersistDBCustomAudiences(nameAndBuyersMap);
1147 
1148         when(mObliviousHttpEncryptorMock.encryptBytes(
1149                         any(byte[].class), anyLong(), anyLong(), any(), any()))
1150                 .thenAnswer(
1151                         invocation ->
1152                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
1153 
1154         GetAdSelectionDataInput input =
1155                 new GetAdSelectionDataInput.Builder()
1156                         .setSeller(SELLER)
1157                         .setCallerPackageName(CALLER_PACKAGE_NAME)
1158                         .build();
1159 
1160         GetAdSelectionDataTestCallback callback =
1161                 invokeGetAdSelectionData(mAdSelectionService, input);
1162 
1163         assertTrue(callback.mIsSuccess);
1164         Assert.assertNotNull(callback.mGetAdSelectionDataResponse);
1165         Assert.assertNotNull(callback.mGetAdSelectionDataResponse.getAdSelectionData());
1166 
1167         byte[] encryptedBytes = callback.mGetAdSelectionDataResponse.getAdSelectionData();
1168         // Since encryption is mocked to do nothing then just passing encrypted byte[]
1169         Map<AdTechIdentifier, BuyerInput> buyerInputMap =
1170                 getBuyerInputMapFromDecryptedBytes(encryptedBytes);
1171         Assert.assertEquals(buyers, buyerInputMap.keySet());
1172         for (AdTechIdentifier buyer : buyerInputMap.keySet()) {
1173             BuyerInput buyerInput = buyerInputMap.get(buyer);
1174             for (BuyerInput.CustomAudience buyerInputsCA : buyerInput.getCustomAudiencesList()) {
1175                 String buyerInputsCAName = buyerInputsCA.getName();
1176                 assertTrue(namesAndCustomAudiences.containsKey(buyerInputsCAName));
1177                 DBCustomAudience deviceCA = namesAndCustomAudiences.get(buyerInputsCAName);
1178                 Assert.assertEquals(deviceCA.getName(), buyerInputsCAName);
1179                 Assert.assertEquals(deviceCA.getBuyer(), buyer);
1180                 assertCasEquals(buyerInputsCA, deviceCA);
1181             }
1182         }
1183 
1184         loggingLatch.await();
1185         // Verify GetAdSelectionDataBuyerInputGeneratedStats metrics
1186         verify(mAdServicesLoggerMock, times(2))
1187                 .logGetAdSelectionDataBuyerInputGeneratedStats(
1188                         argumentCaptorBuyerInputStats.capture());
1189         List<GetAdSelectionDataBuyerInputGeneratedStats> stats =
1190                 argumentCaptorBuyerInputStats.getAllValues();
1191 
1192         GetAdSelectionDataBuyerInputGeneratedStats stats1 = stats.get(0);
1193         assertThat(stats1.getNumCustomAudiences()).isEqualTo(1);
1194         assertThat(stats1.getNumCustomAudiencesOmitAds()).isEqualTo(0);
1195 
1196         GetAdSelectionDataBuyerInputGeneratedStats stats2 = stats.get(1);
1197         assertThat(stats2.getNumCustomAudiences()).isEqualTo(2);
1198         assertThat(stats2.getNumCustomAudiencesOmitAds()).isEqualTo(0);
1199 
1200         // Verify GetAdSelectionDataApiCalledStats metrics
1201         verify(mAdServicesLoggerMock, times(1))
1202                 .logGetAdSelectionDataApiCalledStats(argumentCaptorApiCalledStats.capture());
1203         assertThat(argumentCaptorApiCalledStats.getValue().getStatusCode())
1204                 .isEqualTo(STATUS_SUCCESS);
1205         assertThat(argumentCaptorApiCalledStats.getValue().getPayloadSizeKb())
1206                 .isEqualTo(encryptedBytes.length / 1024);
1207         assertThat(argumentCaptorApiCalledStats.getValue().getNumBuyers()).isEqualTo(NUM_BUYERS);
1208         assertThat(argumentCaptorApiCalledStats.getValue().getServerAuctionCoordinatorSource())
1209                 .isEqualTo(SERVER_AUCTION_COORDINATOR_SOURCE_UNSET);
1210         assertThat(argumentCaptorApiCalledStats.getValue().getSellerMaxSizeKb())
1211                 .isEqualTo(FIELD_UNSET);
1212         assertThat(argumentCaptorApiCalledStats.getValue().getPayloadOptimizationResult())
1213                 .isEqualTo(
1214                         GetAdSelectionDataApiCalledStats.PayloadOptimizationResult
1215                                 .PAYLOAD_OPTIMIZATION_RESULT_UNKNOWN);
1216         assertThat(argumentCaptorApiCalledStats.getValue().getInputGenerationLatencyMs())
1217                 .isEqualTo(FIELD_UNSET);
1218         assertThat(argumentCaptorApiCalledStats.getValue().getCompressedBuyerInputCreatorVersion())
1219                 .isEqualTo(FIELD_UNSET);
1220         assertThat(argumentCaptorApiCalledStats.getValue().getNumReEstimations())
1221                 .isEqualTo(FIELD_UNSET);
1222     }
1223 
1224     @Test
1225     @SetFlagTrue(KEY_FLEDGE_AUCTION_SERVER_GET_AD_SELECTION_DATA_PAYLOAD_METRICS_ENABLED)
1226     @SetFlagTrue(KEY_FLEDGE_GET_AD_SELECTION_DATA_SELLER_CONFIGURATION_ENABLED)
1227     @SetIntegerFlag(
1228             name = KEY_FLEDGE_GET_AD_SELECTION_DATA_BUYER_INPUT_CREATOR_VERSION,
1229             value = CompressedBuyerInputCreatorSellerPayloadMaxImpl.VERSION)
1230     public void
testGetAdSelectionData_withoutEncrypt_validRequest_successPayloadMetricsEnabledWithSellerConfigurationEnabled()1231             testGetAdSelectionData_withoutEncrypt_validRequest_successPayloadMetricsEnabledWithSellerConfigurationEnabled()
1232                     throws Exception {
1233         ArgumentCaptor<GetAdSelectionDataApiCalledStats> argumentCaptorApiCalledStats =
1234                 ArgumentCaptor.forClass(GetAdSelectionDataApiCalledStats.class);
1235 
1236         ArgumentCaptor<GetAdSelectionDataBuyerInputGeneratedStats> argumentCaptorBuyerInputStats =
1237                 ArgumentCaptor.forClass(GetAdSelectionDataBuyerInputGeneratedStats.class);
1238         // Create a logging latch with count of 3, 2 for buyer input logs and 1 for api logs
1239         CountDownLatch loggingLatch = new CountDownLatch(3);
1240         Answer<Void> countDownAnswer =
1241                 unused -> {
1242                     loggingLatch.countDown();
1243                     return null;
1244                 };
1245         ExtendedMockito.doAnswer(countDownAnswer)
1246                 .when(mAdServicesLoggerMock)
1247                 .logGetAdSelectionDataApiCalledStats(any());
1248         ExtendedMockito.doAnswer(countDownAnswer)
1249                 .when(mAdServicesLoggerMock)
1250                 .logGetAdSelectionDataBuyerInputGeneratedStats(any());
1251 
1252         AdSelectionService adSelectionService =
1253                 createAdSelectionService(); // create the service again with new flags
1254 
1255         Map<String, AdTechIdentifier> nameAndBuyersMap =
1256                 Map.of(
1257                         "Shoes CA of Buyer 1", BUYER_1,
1258                         "Shirts CA of Buyer 1", BUYER_2,
1259                         "Shoes CA Of Buyer 2", BUYER_2);
1260         Set<AdTechIdentifier> buyers = new HashSet<>(nameAndBuyersMap.values());
1261         Map<String, DBCustomAudience> namesAndCustomAudiences =
1262                 createAndPersistDBCustomAudiences(nameAndBuyersMap);
1263 
1264         when(mObliviousHttpEncryptorMock.encryptBytes(
1265                         any(byte[].class), anyLong(), anyLong(), any(), any()))
1266                 .thenAnswer(
1267                         invocation ->
1268                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
1269 
1270         GetAdSelectionDataInput input =
1271                 new GetAdSelectionDataInput.Builder()
1272                         .setSeller(SELLER)
1273                         .setCallerPackageName(CALLER_PACKAGE_NAME)
1274                         .setSellerConfiguration(SELLER_CONFIGURATION)
1275                         .build();
1276 
1277         GetAdSelectionDataTestCallback callback =
1278                 invokeGetAdSelectionData(adSelectionService, input);
1279 
1280         assertTrue(callback.mIsSuccess);
1281         Assert.assertNotNull(callback.mGetAdSelectionDataResponse);
1282         Assert.assertNotNull(callback.mGetAdSelectionDataResponse.getAdSelectionData());
1283 
1284         byte[] encryptedBytes = callback.mGetAdSelectionDataResponse.getAdSelectionData();
1285         // Since encryption is mocked to do nothing then just passing encrypted byte[]
1286         Map<AdTechIdentifier, BuyerInput> buyerInputMap =
1287                 getBuyerInputMapFromDecryptedBytes(encryptedBytes);
1288         Assert.assertEquals(buyers, buyerInputMap.keySet());
1289         for (AdTechIdentifier buyer : buyerInputMap.keySet()) {
1290             BuyerInput buyerInput = buyerInputMap.get(buyer);
1291             for (BuyerInput.CustomAudience buyerInputsCA : buyerInput.getCustomAudiencesList()) {
1292                 String buyerInputsCAName = buyerInputsCA.getName();
1293                 assertTrue(namesAndCustomAudiences.containsKey(buyerInputsCAName));
1294                 DBCustomAudience deviceCA = namesAndCustomAudiences.get(buyerInputsCAName);
1295                 Assert.assertEquals(deviceCA.getName(), buyerInputsCAName);
1296                 Assert.assertEquals(deviceCA.getBuyer(), buyer);
1297                 assertCasEquals(buyerInputsCA, deviceCA);
1298             }
1299         }
1300 
1301         loggingLatch.await();
1302         // Verify GetAdSelectionDataBuyerInputGeneratedStats metrics
1303         verify(mAdServicesLoggerMock, times(2))
1304                 .logGetAdSelectionDataBuyerInputGeneratedStats(
1305                         argumentCaptorBuyerInputStats.capture());
1306         List<GetAdSelectionDataBuyerInputGeneratedStats> stats =
1307                 argumentCaptorBuyerInputStats.getAllValues();
1308 
1309         GetAdSelectionDataBuyerInputGeneratedStats stats1 = stats.get(0);
1310         assertThat(stats1.getNumCustomAudiences()).isEqualTo(1);
1311         assertThat(stats1.getNumCustomAudiencesOmitAds()).isEqualTo(0);
1312 
1313         GetAdSelectionDataBuyerInputGeneratedStats stats2 = stats.get(1);
1314         assertThat(stats2.getNumCustomAudiences()).isEqualTo(2);
1315         assertThat(stats2.getNumCustomAudiencesOmitAds()).isEqualTo(0);
1316 
1317         // Verify GetAdSelectionDataApiCalledStats metrics
1318         verify(mAdServicesLoggerMock, times(1))
1319                 .logGetAdSelectionDataApiCalledStats(argumentCaptorApiCalledStats.capture());
1320         assertThat(argumentCaptorApiCalledStats.getValue().getStatusCode())
1321                 .isEqualTo(STATUS_SUCCESS);
1322         assertThat(argumentCaptorApiCalledStats.getValue().getPayloadSizeKb())
1323                 .isEqualTo(encryptedBytes.length / 1024);
1324         assertThat(argumentCaptorApiCalledStats.getValue().getNumBuyers()).isEqualTo(NUM_BUYERS);
1325         assertThat(argumentCaptorApiCalledStats.getValue().getServerAuctionCoordinatorSource())
1326                 .isEqualTo(SERVER_AUCTION_COORDINATOR_SOURCE_UNSET);
1327         assertThat(argumentCaptorApiCalledStats.getValue().getSellerMaxSizeKb())
1328                 .isEqualTo(SELLER_CONFIGURATION.getMaximumPayloadSizeBytes() / 1024);
1329         assertThat(argumentCaptorApiCalledStats.getValue().getPayloadOptimizationResult())
1330                 .isEqualTo(
1331                         GetAdSelectionDataApiCalledStats.PayloadOptimizationResult
1332                                 .PAYLOAD_WITHIN_REQUESTED_MAX);
1333         assertThat(argumentCaptorApiCalledStats.getValue().getInputGenerationLatencyMs())
1334                 .isGreaterThan(0);
1335         assertThat(argumentCaptorApiCalledStats.getValue().getCompressedBuyerInputCreatorVersion())
1336                 .isEqualTo(CompressedBuyerInputCreatorSellerPayloadMaxImpl.VERSION);
1337         assertThat(argumentCaptorApiCalledStats.getValue().getNumReEstimations()).isEqualTo(0);
1338     }
1339 
1340     @Test
1341     @SetFlagTrue(KEY_FLEDGE_GET_AD_SELECTION_DATA_SELLER_CONFIGURATION_ENABLED)
1342     @SetIntegerFlag(
1343             name = KEY_FLEDGE_GET_AD_SELECTION_DATA_BUYER_INPUT_CREATOR_VERSION,
1344             value = CompressedBuyerInputCreatorSellerPayloadMaxImpl.VERSION)
1345     @SetIntegerFlag(
1346             name = KEY_FLEDGE_AUCTION_SERVER_PAYLOAD_FORMAT_VERSION,
1347             value = AuctionServerPayloadFormatterExactSize.VERSION)
1348     // Disable filtering as it takes too much time
1349     @SetFlagFalse(KEY_FLEDGE_FREQUENCY_CAP_FILTERING_ENABLED)
1350     @SetFlagFalse(KEY_FLEDGE_APP_INSTALL_FILTERING_ENABLED)
1351     @SetFlagFalse(KEY_FLEDGE_AUCTION_SERVER_GET_AD_SELECTION_DATA_PAYLOAD_METRICS_ENABLED)
1352     public void
testGetAdSelectionData_withoutEncrypt_validRequest_WithSellerConfigurationSellerMaxEnabled()1353             testGetAdSelectionData_withoutEncrypt_validRequest_WithSellerConfigurationSellerMaxEnabled()
1354                     throws Exception {
1355         mAdFilteringFeatureFactory =
1356                 new AdFilteringFeatureFactory(mAppInstallDao, mFrequencyCapDaoSpy, mFakeFlags);
1357 
1358         AdSelectionService adSelectionService =
1359                 createAdSelectionService(); // create the service again with new flags
1360 
1361         List<AdTechIdentifier> buyersList = ImmutableList.of(BUYER_1, BUYER_2);
1362 
1363         // Init with 100 CAs, which by compressing everything is larger than 3Kb
1364         createAndPersistBulkDBCustomAudiences(buyersList, 50);
1365 
1366         byte[] encodedSignals = new byte[] {2, 3, 5, 7, 11, 13, 17, 19};
1367         createAndPersistEncodedSignals(BUYER_1, encodedSignals);
1368         createAndPersistEncodedSignals(BUYER_2, encodedSignals);
1369 
1370         when(mObliviousHttpEncryptorMock.encryptBytes(
1371                         any(byte[].class), anyLong(), anyLong(), any(), any()))
1372                 .thenAnswer(
1373                         invocation ->
1374                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
1375 
1376         int maxPayloadSizeBytes = 4 * 1024; // 4KB
1377 
1378         SellerConfiguration sellerConfiguration =
1379                 new SellerConfiguration.Builder()
1380                         .setPerBuyerConfigurations(
1381                                 Set.of(PER_BUYER_CONFIGURATION_1, PER_BUYER_CONFIGURATION_2))
1382                         .setMaximumPayloadSizeBytes(maxPayloadSizeBytes)
1383                         .build();
1384 
1385         GetAdSelectionDataInput input =
1386                 new GetAdSelectionDataInput.Builder()
1387                         .setSeller(SELLER)
1388                         .setCallerPackageName(CALLER_PACKAGE_NAME)
1389                         .setSellerConfiguration(sellerConfiguration)
1390                         .build();
1391 
1392         GetAdSelectionDataTestCallback callback =
1393                 invokeGetAdSelectionData(adSelectionService, input);
1394 
1395         assertTrue(callback.mIsSuccess);
1396         Assert.assertNotNull(callback.mGetAdSelectionDataResponse);
1397         Assert.assertNotNull(callback.mGetAdSelectionDataResponse.getAssetFileDescriptor());
1398 
1399         int totalNumCAsInBuyerInput = 0;
1400 
1401         byte[] encryptedBytes = getAdSelectionData(callback.mGetAdSelectionDataResponse);
1402         // Since encryption is mocked to do nothing then just passing encrypted byte[]
1403         Map<AdTechIdentifier, BuyerInput> buyerInputMap =
1404                 getBuyerInputMapFromDecryptedBytes(encryptedBytes);
1405         for (AdTechIdentifier buyer : buyersList) {
1406             BuyerInput buyerInput = buyerInputMap.get(buyer);
1407 
1408             ProtectedAppSignals protectedAppSignals = buyerInput.getProtectedAppSignals();
1409             Assert.assertArrayEquals(
1410                     encodedSignals, protectedAppSignals.getAppInstallSignals().toByteArray());
1411 
1412             totalNumCAsInBuyerInput += buyerInput.getCustomAudiencesList().size();
1413         }
1414 
1415         assertThat(totalNumCAsInBuyerInput).isGreaterThan(20);
1416 
1417         // Make sure payload size is equal to than max, even with persisting 200 CAs
1418         assertThat(encryptedBytes.length)
1419                 .isEqualTo(sellerConfiguration.getMaximumPayloadSizeBytes());
1420 
1421         // Verify GetAdSelectionDataBuyerInputGeneratedStats metrics are not called
1422         verify(mAdServicesLoggerMock, never()).logGetAdSelectionDataBuyerInputGeneratedStats(any());
1423 
1424         // Verify GetAdSelectionDataApiCalledStats metrics are not called
1425         verify(mAdServicesLoggerMock, never()).logGetAdSelectionDataApiCalledStats(any());
1426     }
1427 
1428     @Test
1429     @SetFlagTrue(KEY_FLEDGE_GET_AD_SELECTION_DATA_SELLER_CONFIGURATION_ENABLED)
1430     @SetIntegerFlag(
1431             name = KEY_FLEDGE_GET_AD_SELECTION_DATA_BUYER_INPUT_CREATOR_VERSION,
1432             value = CompressedBuyerInputCreatorPerBuyerLimitsGreedyImpl.VERSION)
1433     @SetIntegerFlag(
1434             name = KEY_FLEDGE_AUCTION_SERVER_PAYLOAD_FORMAT_VERSION,
1435             value = AuctionServerPayloadFormatterExactSize.VERSION)
1436     // Disable filtering as it takes too much time
1437     @SetFlagFalse(KEY_FLEDGE_FREQUENCY_CAP_FILTERING_ENABLED)
1438     @SetFlagFalse(KEY_FLEDGE_APP_INSTALL_FILTERING_ENABLED)
1439     @SetFlagFalse(KEY_FLEDGE_AUCTION_SERVER_GET_AD_SELECTION_DATA_PAYLOAD_METRICS_ENABLED)
1440     @SetLongFlag(
1441             name = KEY_FLEDGE_AUCTION_SERVER_OVERALL_TIMEOUT_MS,
1442             value = FLEDGE_AUCTION_SERVER_OVERALL_TIMEOUT_MS * 2)
1443     public void
testGetAdSelectionData_withoutEncrypt_validRequest_WithSellerConfigurationPerBuyerLimitsGreedyEnabled()1444             testGetAdSelectionData_withoutEncrypt_validRequest_WithSellerConfigurationPerBuyerLimitsGreedyEnabled()
1445                     throws Exception {
1446         mAdFilteringFeatureFactory =
1447                 new AdFilteringFeatureFactory(mAppInstallDao, mFrequencyCapDaoSpy, mFakeFlags);
1448 
1449         // Create the service again with new flags
1450         AdSelectionService adSelectionService = createAdSelectionService();
1451         List<AdTechIdentifier> buyersList = ImmutableList.of(BUYER_1, BUYER_2);
1452 
1453         // Init with 100 CAs, which by compressing everything is larger than 4Kb
1454         createAndPersistBulkDBCustomAudiences(buyersList, 100);
1455 
1456         byte[] encodedSignals = new byte[] {2, 3, 5, 7, 11, 13, 17, 19};
1457         createAndPersistEncodedSignals(BUYER_1, encodedSignals);
1458         createAndPersistEncodedSignals(BUYER_2, encodedSignals);
1459 
1460         when(mObliviousHttpEncryptorMock.encryptBytes(
1461                         any(byte[].class), anyLong(), anyLong(), any(), any()))
1462                 .thenAnswer(
1463                         invocation ->
1464                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
1465 
1466         int maxPayloadSizeBytes = 4 * 1024; // 4KB
1467 
1468         SellerConfiguration sellerConfiguration =
1469                 new SellerConfiguration.Builder()
1470                         .setPerBuyerConfigurations(
1471                                 Set.of(PER_BUYER_CONFIGURATION_1, PER_BUYER_CONFIGURATION_2))
1472                         .setMaximumPayloadSizeBytes(maxPayloadSizeBytes)
1473                         .build();
1474 
1475         GetAdSelectionDataInput input =
1476                 new GetAdSelectionDataInput.Builder()
1477                         .setSeller(SELLER)
1478                         .setCallerPackageName(CALLER_PACKAGE_NAME)
1479                         .setSellerConfiguration(sellerConfiguration)
1480                         .build();
1481 
1482         GetAdSelectionDataTestCallback callback =
1483                 invokeGetAdSelectionData(adSelectionService, input);
1484 
1485         assertTrue(callback.mIsSuccess);
1486         Assert.assertNotNull(callback.mGetAdSelectionDataResponse);
1487         Assert.assertNotNull(callback.mGetAdSelectionDataResponse.getAssetFileDescriptor());
1488 
1489         int totalNumCAsInBuyerInput = 0;
1490 
1491         byte[] encryptedBytes = getAdSelectionData(callback.mGetAdSelectionDataResponse);
1492         // Since encryption is mocked to do nothing then just passing encrypted byte[]
1493         Map<AdTechIdentifier, BuyerInput> buyerInputMap =
1494                 getBuyerInputMapFromDecryptedBytes(encryptedBytes);
1495         for (AdTechIdentifier buyer : buyersList) {
1496             BuyerInput buyerInput = buyerInputMap.get(buyer);
1497 
1498             // no signals should be added since each buyer target size is less than 1.5 KB
1499             ProtectedAppSignals protectedAppSignals = buyerInput.getProtectedAppSignals();
1500             Assert.assertTrue(protectedAppSignals.getAppInstallSignals().isEmpty());
1501 
1502             totalNumCAsInBuyerInput += buyerInput.getCustomAudiencesList().size();
1503         }
1504 
1505         assertThat(totalNumCAsInBuyerInput).isGreaterThan(20);
1506 
1507         // Make sure payload size is smaller than max, even ith persisting 100 CAs
1508         assertThat(encryptedBytes.length)
1509                 .isAtMost(sellerConfiguration.getMaximumPayloadSizeBytes());
1510 
1511         // Verify GetAdSelectionDataBuyerInputGeneratedStats metrics are not called
1512         verify(mAdServicesLoggerMock, never()).logGetAdSelectionDataBuyerInputGeneratedStats(any());
1513 
1514         // Verify GetAdSelectionDataApiCalledStats metrics are not called
1515         verify(mAdServicesLoggerMock, never()).logGetAdSelectionDataApiCalledStats(any());
1516     }
1517 
1518     @Test
1519     @SetFlagTrue(KEY_FLEDGE_AUCTION_SERVER_GET_AD_SELECTION_DATA_PAYLOAD_METRICS_ENABLED)
1520     @SetFlagTrue(KEY_FLEDGE_AUCTION_SERVER_KEY_FETCH_METRICS_ENABLED)
1521     public void
testGetAdSelectionData_validRequest_successPayloadMetricsEnabled_withSourceCoordinator()1522             testGetAdSelectionData_validRequest_successPayloadMetricsEnabled_withSourceCoordinator()
1523                     throws Exception {
1524         ArgumentCaptor<GetAdSelectionDataApiCalledStats> argumentCaptorApiCalledStats =
1525                 ArgumentCaptor.forClass(GetAdSelectionDataApiCalledStats.class);
1526 
1527         ArgumentCaptor<GetAdSelectionDataBuyerInputGeneratedStats> argumentCaptorBuyerInputStats =
1528                 ArgumentCaptor.forClass(GetAdSelectionDataBuyerInputGeneratedStats.class);
1529         // Create a logging latch with count of 3, 2 for buyer input logs and 1 for api logs
1530         CountDownLatch loggingLatch = new CountDownLatch(3);
1531         Answer<Void> countDownAnswer =
1532                 unused -> {
1533                     loggingLatch.countDown();
1534                     return null;
1535                 };
1536         ExtendedMockito.doAnswer(countDownAnswer)
1537                 .when(mAdServicesLoggerMock)
1538                 .logGetAdSelectionDataApiCalledStats(any());
1539         ExtendedMockito.doAnswer(countDownAnswer)
1540                 .when(mAdServicesLoggerMock)
1541                 .logGetAdSelectionDataBuyerInputGeneratedStats(any());
1542 
1543         mAdSelectionService = createAdSelectionService(); // create the service again with new flags
1544 
1545         Map<String, AdTechIdentifier> nameAndBuyersMap =
1546                 Map.of(
1547                         "Shoes CA of Buyer 1", WINNER_BUYER,
1548                         "Shirts CA of Buyer 1", WINNER_BUYER,
1549                         "Shoes CA Of Buyer 2", DIFFERENT_BUYER);
1550         Set<AdTechIdentifier> buyers = new HashSet<>(nameAndBuyersMap.values());
1551         Map<String, DBCustomAudience> namesAndCustomAudiences =
1552                 createAndPersistDBCustomAudiences(nameAndBuyersMap);
1553 
1554         when(mObliviousHttpEncryptorMock.encryptBytes(
1555                         any(byte[].class), anyLong(), anyLong(), any(), any()))
1556                 .thenAnswer(
1557                         invocation ->
1558                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
1559 
1560         GetAdSelectionDataInput input =
1561                 new GetAdSelectionDataInput.Builder()
1562                         .setSeller(SELLER)
1563                         .setCallerPackageName(CALLER_PACKAGE_NAME)
1564                         .build();
1565 
1566         GetAdSelectionDataTestCallback callback =
1567                 invokeGetAdSelectionData(mAdSelectionService, input);
1568 
1569         assertTrue(callback.mIsSuccess);
1570         Assert.assertNotNull(callback.mGetAdSelectionDataResponse);
1571         Assert.assertNotNull(callback.mGetAdSelectionDataResponse.getAdSelectionData());
1572 
1573         byte[] encryptedBytes = callback.mGetAdSelectionDataResponse.getAdSelectionData();
1574         // Since encryption is mocked to do nothing then just passing encrypted byte[]
1575         Map<AdTechIdentifier, BuyerInput> buyerInputMap =
1576                 getBuyerInputMapFromDecryptedBytes(encryptedBytes);
1577         Assert.assertEquals(buyers, buyerInputMap.keySet());
1578         for (AdTechIdentifier buyer : buyerInputMap.keySet()) {
1579             BuyerInput buyerInput = buyerInputMap.get(buyer);
1580             for (BuyerInput.CustomAudience buyerInputsCA : buyerInput.getCustomAudiencesList()) {
1581                 String buyerInputsCAName = buyerInputsCA.getName();
1582                 assertTrue(namesAndCustomAudiences.containsKey(buyerInputsCAName));
1583                 DBCustomAudience deviceCA = namesAndCustomAudiences.get(buyerInputsCAName);
1584                 Assert.assertEquals(deviceCA.getName(), buyerInputsCAName);
1585                 Assert.assertEquals(deviceCA.getBuyer(), buyer);
1586                 assertCasEquals(buyerInputsCA, deviceCA);
1587             }
1588         }
1589 
1590         loggingLatch.await();
1591         // Verify GetAdSelectionDataBuyerInputGeneratedStats metrics
1592         verify(mAdServicesLoggerMock, times(2))
1593                 .logGetAdSelectionDataBuyerInputGeneratedStats(
1594                         argumentCaptorBuyerInputStats.capture());
1595         List<GetAdSelectionDataBuyerInputGeneratedStats> stats =
1596                 argumentCaptorBuyerInputStats.getAllValues();
1597 
1598         GetAdSelectionDataBuyerInputGeneratedStats stats1 = stats.get(0);
1599         assertThat(stats1.getNumCustomAudiences()).isEqualTo(1);
1600         assertThat(stats1.getNumCustomAudiencesOmitAds()).isEqualTo(0);
1601 
1602         GetAdSelectionDataBuyerInputGeneratedStats stats2 = stats.get(1);
1603         assertThat(stats2.getNumCustomAudiences()).isEqualTo(2);
1604         assertThat(stats2.getNumCustomAudiencesOmitAds()).isEqualTo(0);
1605 
1606         // Verify GetAdSelectionDataApiCalledStats metrics
1607         verify(mAdServicesLoggerMock, times(1))
1608                 .logGetAdSelectionDataApiCalledStats(argumentCaptorApiCalledStats.capture());
1609         assertThat(argumentCaptorApiCalledStats.getValue().getStatusCode())
1610                 .isEqualTo(STATUS_SUCCESS);
1611         assertThat(argumentCaptorApiCalledStats.getValue().getPayloadSizeKb())
1612                 .isEqualTo(encryptedBytes.length / 1024);
1613         assertThat(argumentCaptorApiCalledStats.getValue().getNumBuyers()).isEqualTo(NUM_BUYERS);
1614         assertThat(argumentCaptorApiCalledStats.getValue().getServerAuctionCoordinatorSource())
1615                 .isEqualTo(SERVER_AUCTION_COORDINATOR_SOURCE_DEFAULT);
1616     }
1617 
1618     @Test
1619     @SetFlagFalse(KEY_FLEDGE_AUCTION_SERVER_GET_AD_SELECTION_DATA_PAYLOAD_METRICS_ENABLED)
testGetAdSelectionData_withoutEncrypt_validRequest_successPayloadMetricsDisabled()1620     public void testGetAdSelectionData_withoutEncrypt_validRequest_successPayloadMetricsDisabled()
1621             throws Exception {
1622         mAdSelectionService = createAdSelectionService(); // create the service again with new flags
1623 
1624         Map<String, AdTechIdentifier> nameAndBuyersMap =
1625                 Map.of(
1626                         "Shoes CA of Buyer 1", WINNER_BUYER,
1627                         "Shirts CA of Buyer 1", WINNER_BUYER,
1628                         "Shoes CA Of Buyer 2", DIFFERENT_BUYER);
1629         Set<AdTechIdentifier> buyers = new HashSet<>(nameAndBuyersMap.values());
1630         Map<String, DBCustomAudience> namesAndCustomAudiences =
1631                 createAndPersistDBCustomAudiences(nameAndBuyersMap);
1632 
1633         when(mObliviousHttpEncryptorMock.encryptBytes(
1634                         any(byte[].class), anyLong(), anyLong(), any(), any()))
1635                 .thenAnswer(
1636                         invocation ->
1637                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
1638 
1639         GetAdSelectionDataInput input =
1640                 new GetAdSelectionDataInput.Builder()
1641                         .setSeller(SELLER)
1642                         .setCallerPackageName(CALLER_PACKAGE_NAME)
1643                         .build();
1644 
1645         GetAdSelectionDataTestCallback callback =
1646                 invokeGetAdSelectionData(mAdSelectionService, input);
1647 
1648         assertTrue(callback.mIsSuccess);
1649         Assert.assertNotNull(callback.mGetAdSelectionDataResponse);
1650         Assert.assertNotNull(callback.mGetAdSelectionDataResponse.getAdSelectionData());
1651 
1652         byte[] encryptedBytes = callback.mGetAdSelectionDataResponse.getAdSelectionData();
1653         // Since encryption is mocked to do nothing then just passing encrypted byte[]
1654         Map<AdTechIdentifier, BuyerInput> buyerInputMap =
1655                 getBuyerInputMapFromDecryptedBytes(encryptedBytes);
1656         Assert.assertEquals(buyers, buyerInputMap.keySet());
1657         for (AdTechIdentifier buyer : buyerInputMap.keySet()) {
1658             BuyerInput buyerInput = buyerInputMap.get(buyer);
1659             for (BuyerInput.CustomAudience buyerInputsCA : buyerInput.getCustomAudiencesList()) {
1660                 String buyerInputsCAName = buyerInputsCA.getName();
1661                 assertTrue(namesAndCustomAudiences.containsKey(buyerInputsCAName));
1662                 DBCustomAudience deviceCA = namesAndCustomAudiences.get(buyerInputsCAName);
1663                 Assert.assertEquals(deviceCA.getName(), buyerInputsCAName);
1664                 Assert.assertEquals(deviceCA.getBuyer(), buyer);
1665                 assertCasEquals(buyerInputsCA, deviceCA);
1666             }
1667         }
1668 
1669         verify(mAdServicesLoggerMock, never()).logGetAdSelectionDataApiCalledStats(any());
1670         verify(mAdServicesLoggerMock, never()).logGetAdSelectionDataBuyerInputGeneratedStats(any());
1671     }
1672 
1673     @Test
1674     @SetFlagTrue(KEY_FLEDGE_AUCTION_SERVER_OMIT_ADS_ENABLED)
testGetAdSelectionData_withoutEncrypt_validRequestWithOmitAdsInOneCA_success()1675     public void testGetAdSelectionData_withoutEncrypt_validRequestWithOmitAdsInOneCA_success()
1676             throws Exception {
1677         mAdSelectionService = createAdSelectionService(); // create the service again with new flags
1678 
1679         Map<String, AdTechIdentifier> nameAndBuyersMap =
1680                 Map.of(
1681                         "Shoes CA of Buyer 1", WINNER_BUYER,
1682                         "Shirts CA of Buyer 1", WINNER_BUYER,
1683                         "Shoes CA Of Buyer 2", DIFFERENT_BUYER);
1684         Set<AdTechIdentifier> buyers = new HashSet<>(nameAndBuyersMap.values());
1685         Map<String, DBCustomAudience> namesAndCustomAudiences =
1686                 createAndPersistDBCustomAudiences(nameAndBuyersMap);
1687 
1688         String buyer2ShirtsName = "Shirts CA of Buyer 2";
1689         // Insert a CA with omit ads enabled
1690         DBCustomAudience dbCustomAudienceOmitAdsEnabled =
1691                 createAndPersistDBCustomAudienceWithOmitAdsEnabled(
1692                         buyer2ShirtsName, DIFFERENT_BUYER);
1693         namesAndCustomAudiences.put(buyer2ShirtsName, dbCustomAudienceOmitAdsEnabled);
1694 
1695         when(mObliviousHttpEncryptorMock.encryptBytes(
1696                         any(byte[].class), anyLong(), anyLong(), any(), any()))
1697                 .thenAnswer(
1698                         invocation ->
1699                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
1700 
1701         GetAdSelectionDataInput input =
1702                 new GetAdSelectionDataInput.Builder()
1703                         .setSeller(SELLER)
1704                         .setCallerPackageName(CALLER_PACKAGE_NAME)
1705                         .build();
1706 
1707         GetAdSelectionDataTestCallback callback =
1708                 invokeGetAdSelectionData(mAdSelectionService, input);
1709 
1710         assertTrue(callback.mIsSuccess);
1711         Assert.assertNotNull(callback.mGetAdSelectionDataResponse);
1712         Assert.assertNotNull(callback.mGetAdSelectionDataResponse.getAdSelectionData());
1713 
1714         byte[] encryptedBytes = callback.mGetAdSelectionDataResponse.getAdSelectionData();
1715         // Since encryption is mocked to do nothing then just passing encrypted byte[]
1716         Map<AdTechIdentifier, BuyerInput> buyerInputMap =
1717                 getBuyerInputMapFromDecryptedBytes(encryptedBytes);
1718         Assert.assertEquals(buyers, buyerInputMap.keySet());
1719         for (AdTechIdentifier buyer : buyerInputMap.keySet()) {
1720             BuyerInput buyerInput = buyerInputMap.get(buyer);
1721             for (BuyerInput.CustomAudience buyerInputsCA : buyerInput.getCustomAudiencesList()) {
1722                 String buyerInputsCAName = buyerInputsCA.getName();
1723                 assertTrue(namesAndCustomAudiences.containsKey(buyerInputsCAName));
1724                 DBCustomAudience deviceCA = namesAndCustomAudiences.get(buyerInputsCAName);
1725                 Assert.assertEquals(deviceCA.getName(), buyerInputsCAName);
1726                 Assert.assertEquals(deviceCA.getBuyer(), buyer);
1727                 assertCasEquals(buyerInputsCA, deviceCA);
1728 
1729                 // Buyer 2 shirts ca should not have ad render ids list
1730                 if (deviceCA.getBuyer().equals(DIFFERENT_BUYER)
1731                         && deviceCA.getName().equals(buyer2ShirtsName)) {
1732                     assertThat(buyerInputsCA.getAdRenderIdsList()).isEmpty();
1733                 } else {
1734                     // All other cas should have ads
1735                     assertThat(buyerInputsCA.getAdRenderIdsList()).isNotEmpty();
1736                 }
1737             }
1738         }
1739     }
1740 
1741     @Test
testGetAdSelectionData_fCap_success()1742     public void testGetAdSelectionData_fCap_success() throws Exception {
1743         when(mObliviousHttpEncryptorMock.encryptBytes(
1744                         any(byte[].class), anyLong(), anyLong(), any(), any()))
1745                 .thenAnswer(
1746                         invocation ->
1747                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
1748         when(mObliviousHttpEncryptorMock.decryptBytes(any(byte[].class), anyLong()))
1749                 .thenAnswer(invocation -> invocation.getArgument(0));
1750 
1751         int sequenceNumber1 = 1;
1752         int sequenceNumber2 = 2;
1753         int filterMaxCount = 1;
1754         List<DBAdData> filterableAds =
1755                 List.of(
1756                         getFilterableAndServerEligibleFCapAd(sequenceNumber1, filterMaxCount),
1757                         getFilterableAndServerEligibleFCapAd(sequenceNumber2, filterMaxCount));
1758 
1759         DBCustomAudience winningCustomAudience =
1760                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
1761                                 WINNER_BUYER,
1762                                 WINNING_CUSTOM_AUDIENCE_NAME,
1763                                 WINNING_CUSTOM_AUDIENCE_OWNER)
1764                         .setAds(filterableAds)
1765                         .build();
1766         Assert.assertNotNull(winningCustomAudience.getAds());
1767         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
1768                 winningCustomAudience, Uri.EMPTY, false, List.of());
1769 
1770         GetAdSelectionDataInput input =
1771                 new GetAdSelectionDataInput.Builder()
1772                         .setSeller(SELLER)
1773                         .setCallerPackageName(CALLER_PACKAGE_NAME)
1774                         .build();
1775 
1776         GetAdSelectionDataTestCallback getAdSelectionDataTestCallback =
1777                 invokeGetAdSelectionData(mAdSelectionService, input);
1778         long adSelectionId =
1779                 getAdSelectionDataTestCallback.mGetAdSelectionDataResponse.getAdSelectionId();
1780         assertTrue(getAdSelectionDataTestCallback.mIsSuccess);
1781 
1782         // Since encryption is mocked to do nothing then just passing encrypted byte[]
1783         List<String> adRenderIdsFromBuyerInput =
1784                 extractCAAdRenderIdListFromBuyerInput(
1785                         getAdSelectionDataTestCallback,
1786                         winningCustomAudience.getBuyer(),
1787                         winningCustomAudience.getName(),
1788                         winningCustomAudience.getOwner());
1789         Assert.assertEquals(filterableAds.size(), adRenderIdsFromBuyerInput.size());
1790 
1791         PersistAdSelectionResultInput persistAdSelectionResultInput =
1792                 new PersistAdSelectionResultInput.Builder()
1793                         .setAdSelectionId(adSelectionId)
1794                         .setSeller(SELLER)
1795                         .setAdSelectionResult(prepareAuctionResultBytes())
1796                         .setCallerPackageName(CALLER_PACKAGE_NAME)
1797                         .build();
1798 
1799         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
1800                 invokePersistAdSelectionResult(mAdSelectionService, persistAdSelectionResultInput);
1801 
1802         assertTrue(persistAdSelectionResultTestCallback.mIsSuccess);
1803 
1804         // FCap non-win reporting
1805         UpdateAdCounterHistogramInput updateHistogramInput =
1806                 new UpdateAdCounterHistogramInput.Builder(
1807                                 adSelectionId,
1808                                 FrequencyCapFilters.AD_EVENT_TYPE_CLICK,
1809                                 SELLER,
1810                                 CALLER_PACKAGE_NAME)
1811                         .build();
1812         UpdateAdCounterHistogramTestCallback updateHistogramCallback =
1813                 invokeUpdateAdCounterHistogram(mAdSelectionService, updateHistogramInput);
1814         assertTrue(updateHistogramCallback.mIsSuccess);
1815 
1816         // Collect device data again and expect one less ads due to FCap filter
1817         GetAdSelectionDataInput input2 =
1818                 new GetAdSelectionDataInput.Builder()
1819                         .setSeller(SELLER)
1820                         .setCallerPackageName(CALLER_PACKAGE_NAME)
1821                         .build();
1822 
1823         GetAdSelectionDataTestCallback getAdSelectionDataTestCallback2 =
1824                 invokeGetAdSelectionData(mAdSelectionService, input2);
1825 
1826         // Since encryption is mocked to do nothing then just passing encrypted byte[]
1827         List<String> adRenderIdsFromBuyerInput2 =
1828                 extractCAAdRenderIdListFromBuyerInput(
1829                         getAdSelectionDataTestCallback2,
1830                         winningCustomAudience.getBuyer(),
1831                         winningCustomAudience.getName(),
1832                         winningCustomAudience.getOwner());
1833         // No ads collected for the same CA bc they are filtered out
1834         Assert.assertEquals(filterableAds.size() - 1, adRenderIdsFromBuyerInput2.size());
1835     }
1836 
1837     @Test
testGetAdSelectionData_withEncrypt_validRequestInDevMode_dataIsCleared()1838     public void testGetAdSelectionData_withEncrypt_validRequestInDevMode_dataIsCleared()
1839             throws Exception {
1840         mDevSessionHelper.startDevSession();
1841         prepareDataAndRunServerAuction();
1842 
1843         // Exit the dev session, clearing the database.
1844         mDevSessionHelper.endDevSession();
1845 
1846         GetAdSelectionDataTestCallback callback =
1847                 invokeGetAdSelectionData(
1848                         mAdSelectionService,
1849                         new GetAdSelectionDataInput.Builder()
1850                                 .setSeller(SELLER)
1851                                 .setCallerPackageName(CALLER_PACKAGE_NAME)
1852                                 .setCoordinatorOriginUri(Uri.parse(COORDINATOR_HOST))
1853                                 .build());
1854         assertThat(mCustomAudienceDaoSpy.getCustomAudienceCount()).isEqualTo(0);
1855         assertThat(mProtectedSignalsDao.getSignalsByBuyer(WINNER_BUYER)).isEmpty();
1856         assertThat(mEncodedPayloadDaoSpy.doesEncodedPayloadExist(WINNER_BUYER)).isFalse();
1857         assertThat(callback.mIsSuccess).isTrue();
1858         mDevSessionHelper.endDevSession();
1859     }
1860 
1861     @Test
testGetAdSelectionData_withEncrypt_validRequestBeforeDevMode_dataIsCleared()1862     public void testGetAdSelectionData_withEncrypt_validRequestBeforeDevMode_dataIsCleared()
1863             throws Exception {
1864         prepareDataAndRunServerAuction();
1865 
1866         // Exit the dev session, clearing the database.
1867         mDevSessionHelper.startDevSession();
1868 
1869         GetAdSelectionDataTestCallback callback =
1870                 invokeGetAdSelectionData(
1871                         mAdSelectionService,
1872                         new GetAdSelectionDataInput.Builder()
1873                                 .setSeller(SELLER)
1874                                 .setCallerPackageName(CALLER_PACKAGE_NAME)
1875                                 .setCoordinatorOriginUri(Uri.parse(COORDINATOR_HOST))
1876                                 .build());
1877         assertThat(mCustomAudienceDaoSpy.getCustomAudienceCount()).isEqualTo(0);
1878         assertThat(mProtectedSignalsDao.getSignalsByBuyer(WINNER_BUYER)).isEmpty();
1879         assertThat(mEncodedPayloadDaoSpy.doesEncodedPayloadExist(WINNER_BUYER)).isFalse();
1880         assertThat(callback.mIsSuccess).isTrue();
1881         mDevSessionHelper.endDevSession();
1882     }
1883 
1884     @Test
1885     @SetFlagTrue(KEY_FLEDGE_AUCTION_SERVER_ENABLE_DEBUG_REPORTING)
testGetAdSelectionData_withEncrypt_validRequest_DebugReportingFlagEnabled()1886     public void testGetAdSelectionData_withEncrypt_validRequest_DebugReportingFlagEnabled()
1887             throws Exception {
1888         prepareDataAndRunServerAuction();
1889     }
1890 
1891     @Test
1892     @SetFlagTrue(KEY_FLEDGE_AUCTION_SERVER_ENABLE_DEBUG_REPORTING)
testGetAdSelectionData_withEncrypt_validRequest_LatDisabled()1893     public void testGetAdSelectionData_withEncrypt_validRequest_LatDisabled() throws Exception {
1894         mMockAdIdWorker.setResult(MockAdIdWorker.MOCK_AD_ID, false);
1895 
1896         prepareDataAndRunServerAuction();
1897     }
1898 
1899     @Test
1900     @SetFlagTrue(KEY_FLEDGE_AUCTION_SERVER_ENABLE_DEBUG_REPORTING)
testGetAdSelectionData_withEncrypt_validRequest_GetAdIdTimeoutException()1901     public void testGetAdSelectionData_withEncrypt_validRequest_GetAdIdTimeoutException()
1902             throws Exception {
1903         mMockAdIdWorker.setResult(MockAdIdWorker.MOCK_AD_ID, false);
1904         mMockAdIdWorker.setDelay(AUCTION_SERVER_AD_ID_FETCHER_TIMEOUT_MS * 2);
1905 
1906         prepareDataAndRunServerAuction();
1907     }
1908 
1909     @Test
testPersistAdSelectionResult_withoutDecrypt_validRequest_success()1910     public void testPersistAdSelectionResult_withoutDecrypt_validRequest_success()
1911             throws Exception {
1912         when(mObliviousHttpEncryptorMock.encryptBytes(
1913                         any(byte[].class), anyLong(), anyLong(), any(), any()))
1914                 .thenAnswer(
1915                         invocation ->
1916                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
1917         when(mObliviousHttpEncryptorMock.decryptBytes(any(byte[].class), anyLong()))
1918                 .thenAnswer(invocation -> invocation.getArgument(0));
1919 
1920         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
1921                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
1922                                 WINNER_BUYER,
1923                                 WINNING_CUSTOM_AUDIENCE_NAME,
1924                                 WINNING_CUSTOM_AUDIENCE_OWNER)
1925                         .setAds(
1926                                 DBAdDataFixture.getValidDbAdDataListByBuyerWithAdRenderId(
1927                                         WINNER_BUYER))
1928                         .build(),
1929                 Uri.EMPTY,
1930                 false,
1931                 List.of());
1932 
1933         GetAdSelectionDataInput input =
1934                 new GetAdSelectionDataInput.Builder()
1935                         .setSeller(SELLER)
1936                         .setCallerPackageName(CALLER_PACKAGE_NAME)
1937                         .build();
1938 
1939         GetAdSelectionDataTestCallback getAdSelectionDataTestCallback =
1940                 invokeGetAdSelectionData(mAdSelectionService, input);
1941         long adSelectionId =
1942                 getAdSelectionDataTestCallback.mGetAdSelectionDataResponse.getAdSelectionId();
1943 
1944         PersistAdSelectionResultInput persistAdSelectionResultInput =
1945                 new PersistAdSelectionResultInput.Builder()
1946                         .setAdSelectionId(adSelectionId)
1947                         .setSeller(SELLER)
1948                         .setAdSelectionResult(prepareAuctionResultBytes())
1949                         .setCallerPackageName(CALLER_PACKAGE_NAME)
1950                         .build();
1951 
1952         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
1953                 invokePersistAdSelectionResult(mAdSelectionService, persistAdSelectionResultInput);
1954 
1955         assertTrue(persistAdSelectionResultTestCallback.mIsSuccess);
1956         Assert.assertEquals(
1957                 WINNER_AD_RENDER_URI,
1958                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
1959                         .getAdRenderUri());
1960         Assert.assertEquals(
1961                 adSelectionId,
1962                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
1963                         .getAdSelectionId());
1964         ReportingData reportingData =
1965                 mAdSelectionEntryDao.getReportingDataForId(adSelectionId, false);
1966         Assert.assertEquals(
1967                 BUYER_REPORTING_URI, reportingData.getBuyerWinReportingUri().toString());
1968         Assert.assertEquals(
1969                 SELLER_REPORTING_URI, reportingData.getSellerWinReportingUri().toString());
1970     }
1971 
1972     @Test
1973     @SetFlagTrue(KEY_FLEDGE_AUCTION_SERVER_OMIT_ADS_ENABLED)
testPersistAdSelectionResult_omitAdsEnabled_success()1974     public void testPersistAdSelectionResult_omitAdsEnabled_success() throws Exception {
1975         AdServicesHttpClientResponse httpClientResponse =
1976                 mServerAuctionTestHelper.getPublicAuctionKeyHttpResponse();
1977         when(mMockHttpClient.fetchPayloadWithLogging(
1978                         eq(Uri.parse(COORDINATOR_URL)),
1979                         eq(DevContext.createForDevOptionsDisabled()),
1980                         any(FetchProcessLogger.class)))
1981                 .thenReturn(Futures.immediateFuture(httpClientResponse));
1982 
1983         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
1984                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
1985                                 WINNER_BUYER,
1986                                 WINNING_CUSTOM_AUDIENCE_NAME,
1987                                 WINNING_CUSTOM_AUDIENCE_OWNER)
1988                         .setAds(
1989                                 DBAdDataFixture.getValidDbAdDataListByBuyerWithAdRenderId(
1990                                         WINNER_BUYER))
1991                         .setAuctionServerRequestFlags(FLAG_AUCTION_SERVER_REQUEST_OMIT_ADS)
1992                         .build(),
1993                 Uri.EMPTY,
1994                 false,
1995                 List.of());
1996 
1997         AdSelectionService adSelectionService = createServiceWithMockHttpClient();
1998 
1999         GetAdSelectionDataInput input =
2000                 new GetAdSelectionDataInput.Builder()
2001                         .setSeller(SELLER)
2002                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2003                         .setCoordinatorOriginUri(Uri.parse(COORDINATOR_HOST))
2004                         .build();
2005 
2006         GetAdSelectionDataTestCallback callback =
2007                 invokeGetAdSelectionData(adSelectionService, input);
2008 
2009         assertTrue(callback.mIsSuccess);
2010         long adSelectionId = callback.mGetAdSelectionDataResponse.getAdSelectionId();
2011         Assert.assertNotNull(
2012                 mEncryptionContextDao.getEncryptionContext(
2013                         adSelectionId, ENCRYPTION_KEY_TYPE_AUCTION));
2014 
2015         ProtectedAuctionInput protectedAuctionInput =
2016                 mServerAuctionTestHelper.decryptAdSelectionData(
2017                         callback.mGetAdSelectionDataResponse.getAdSelectionData());
2018 
2019         Map<String, BuyerInput> buyerInputs =
2020                 mServerAuctionTestHelper.getDecompressedBuyerInputs(protectedAuctionInput);
2021 
2022         Assert.assertEquals(1, buyerInputs.size());
2023         assertTrue(buyerInputs.containsKey(WINNER_BUYER.toString()));
2024 
2025         // Assert that ads were omitted in buyer input
2026         Assert.assertEquals(
2027                 0,
2028                 buyerInputs
2029                         .get(WINNER_BUYER.toString())
2030                         .getCustomAudiences(0)
2031                         .getAdRenderIdsCount());
2032 
2033         byte[] encryptedServerResponse =
2034                 mServerAuctionTestHelper.encryptServerAuctionResult(
2035                         callback.mGetAdSelectionDataResponse, AUCTION_RESULT);
2036         PersistAdSelectionResultInput persistAdSelectionResultInput =
2037                 new PersistAdSelectionResultInput.Builder()
2038                         .setAdSelectionId(adSelectionId)
2039                         .setSeller(SELLER)
2040                         .setAdSelectionResult(encryptedServerResponse)
2041                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2042                         .build();
2043         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
2044                 invokePersistAdSelectionResult(adSelectionService, persistAdSelectionResultInput);
2045 
2046         assertTrue(persistAdSelectionResultTestCallback.mIsSuccess);
2047         Assert.assertEquals(
2048                 adSelectionId,
2049                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
2050                         .getAdSelectionId());
2051         Assert.assertEquals(
2052                 WINNER_AD_RENDER_URI,
2053                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
2054                         .getAdRenderUri());
2055         ReportingData reportingData =
2056                 mAdSelectionEntryDao.getReportingDataForId(adSelectionId, false);
2057         Assert.assertEquals(
2058                 BUYER_REPORTING_URI, reportingData.getBuyerWinReportingUri().toString());
2059         Assert.assertEquals(
2060                 SELLER_REPORTING_URI, reportingData.getSellerWinReportingUri().toString());
2061     }
2062 
2063     @Test
testAuctionServerResult_usedInWaterfallMediation_success()2064     public void testAuctionServerResult_usedInWaterfallMediation_success() throws Exception {
2065         Assume.assumeTrue(WebViewSupportUtil.isJSSandboxAvailable(mContext));
2066 
2067         Dispatcher dispatcher =
2068                 new Dispatcher() {
2069                     @Override
2070                     public MockResponse dispatch(RecordedRequest request) {
2071                         if (request.getPath().equals(SELECTION_WATERFALL_LOGIC_JS_PATH)) {
2072                             return new MockResponse().setBody(SELECTION_WATERFALL_LOGIC_JS);
2073                         }
2074                         return new MockResponse().setResponseCode(404);
2075                     }
2076                 };
2077         mockWebServerRule.startMockWebServer(dispatcher);
2078         final String selectionLogicPath = SELECTION_WATERFALL_LOGIC_JS_PATH;
2079 
2080         when(mObliviousHttpEncryptorMock.encryptBytes(
2081                         any(byte[].class), anyLong(), anyLong(), any(), any()))
2082                 .thenAnswer(
2083                         invocation ->
2084                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
2085         when(mObliviousHttpEncryptorMock.decryptBytes(any(byte[].class), anyLong()))
2086                 .thenAnswer(invocation -> invocation.getArgument(0));
2087 
2088         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
2089                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
2090                                 WINNER_BUYER,
2091                                 WINNING_CUSTOM_AUDIENCE_NAME,
2092                                 WINNING_CUSTOM_AUDIENCE_OWNER)
2093                         .setAds(
2094                                 DBAdDataFixture.getValidDbAdDataListByBuyerWithAdRenderId(
2095                                         WINNER_BUYER))
2096                         .build(),
2097                 Uri.EMPTY,
2098                 false,
2099                 List.of());
2100 
2101         GetAdSelectionDataInput input =
2102                 new GetAdSelectionDataInput.Builder()
2103                         .setSeller(SELLER)
2104                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2105                         .build();
2106 
2107         GetAdSelectionDataTestCallback getAdSelectionDataTestCallback =
2108                 invokeGetAdSelectionData(mAdSelectionService, input);
2109         long adSelectionId =
2110                 getAdSelectionDataTestCallback.mGetAdSelectionDataResponse.getAdSelectionId();
2111 
2112         PersistAdSelectionResultInput persistAdSelectionResultInput =
2113                 new PersistAdSelectionResultInput.Builder()
2114                         .setAdSelectionId(adSelectionId)
2115                         .setSeller(SELLER)
2116                         .setAdSelectionResult(prepareAuctionResultBytes())
2117                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2118                         .build();
2119 
2120         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
2121                 invokePersistAdSelectionResult(mAdSelectionService, persistAdSelectionResultInput);
2122 
2123         assertTrue(persistAdSelectionResultTestCallback.mIsSuccess);
2124         Assert.assertEquals(
2125                 WINNER_AD_RENDER_URI,
2126                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
2127                         .getAdRenderUri());
2128         Assert.assertEquals(
2129                 adSelectionId,
2130                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
2131                         .getAdSelectionId());
2132 
2133         AdSelectionSignals bidFloorSignalsBelowBid =
2134                 AdSelectionSignals.fromString(
2135                         String.format(BID_FLOOR_SELECTION_SIGNAL_TEMPLATE, BID - 1));
2136         AdSelectionFromOutcomesInput waterfallReturnsAdSelectionIdInput =
2137                 new AdSelectionFromOutcomesInput.Builder()
2138                         .setAdSelectionFromOutcomesConfig(
2139                                 AdSelectionFromOutcomesConfigFixture
2140                                         .anAdSelectionFromOutcomesConfig(
2141                                                 Collections.singletonList(adSelectionId),
2142                                                 bidFloorSignalsBelowBid,
2143                                                 mockWebServerRule.uriForPath(selectionLogicPath)))
2144                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2145                         .build();
2146         AdSelectionFromOutcomesTestCallback waterfallReturnsAdSelectionIdCallback =
2147                 invokeAdSelectionFromOutcomes(
2148                         mAdSelectionService, waterfallReturnsAdSelectionIdInput);
2149         assertTrue(waterfallReturnsAdSelectionIdCallback.mIsSuccess);
2150         Assert.assertNotNull(waterfallReturnsAdSelectionIdCallback.mAdSelectionResponse);
2151         Assert.assertEquals(
2152                 adSelectionId,
2153                 waterfallReturnsAdSelectionIdCallback.mAdSelectionResponse.getAdSelectionId());
2154 
2155         AdSelectionSignals bidFloorSignalsAboveBid =
2156                 AdSelectionSignals.fromString(
2157                         String.format(BID_FLOOR_SELECTION_SIGNAL_TEMPLATE, BID + 1));
2158         AdSelectionFromOutcomesInput waterfallInputReturnNull =
2159                 new AdSelectionFromOutcomesInput.Builder()
2160                         .setAdSelectionFromOutcomesConfig(
2161                                 AdSelectionFromOutcomesConfigFixture
2162                                         .anAdSelectionFromOutcomesConfig(
2163                                                 Collections.singletonList(adSelectionId),
2164                                                 bidFloorSignalsAboveBid,
2165                                                 mockWebServerRule.uriForPath(selectionLogicPath)))
2166                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2167                         .build();
2168         AdSelectionFromOutcomesTestCallback waterfallReturnsNullCallback =
2169                 invokeAdSelectionFromOutcomes(mAdSelectionService, waterfallInputReturnNull);
2170         assertTrue(waterfallReturnsNullCallback.mIsSuccess);
2171         Assert.assertNull(waterfallReturnsNullCallback.mAdSelectionResponse);
2172     }
2173 
2174     @Test
2175     @ExpectErrorLogUtilCall(
2176             errorCode =
2177                     AD_SERVICES_ERROR_REPORTED__ERROR_CODE__PERSIST_AD_SELECTION_RESULT_RUNNER_RESULT_IS_CHAFF,
2178             ppapiName = AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__PERSIST_AD_SELECTION_RESULT)
testPersistAdSelectionResult_withChaffAuctionResult_successEmptyUri()2179     public void testPersistAdSelectionResult_withChaffAuctionResult_successEmptyUri()
2180             throws Exception {
2181         AdServicesHttpClientResponse httpClientResponse =
2182                 mServerAuctionTestHelper.getPublicAuctionKeyHttpResponse();
2183         when(mMockHttpClient.fetchPayloadWithLogging(
2184                         eq(Uri.parse(COORDINATOR_URL)),
2185                         eq(DevContext.createForDevOptionsDisabled()),
2186                         any(FetchProcessLogger.class)))
2187                 .thenReturn(Futures.immediateFuture(httpClientResponse));
2188 
2189         AdSelectionService service = createServiceWithMockHttpClient();
2190 
2191         GetAdSelectionDataInput input =
2192                 new GetAdSelectionDataInput.Builder()
2193                         .setSeller(SELLER)
2194                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2195                         .setCoordinatorOriginUri(Uri.parse(COORDINATOR_HOST))
2196                         .build();
2197 
2198         GetAdSelectionDataTestCallback callback = invokeGetAdSelectionData(service, input);
2199 
2200         assertTrue(callback.mIsSuccess);
2201         long adSelectionId = callback.mGetAdSelectionDataResponse.getAdSelectionId();
2202         byte[] encryptedBytes = callback.mGetAdSelectionDataResponse.getAdSelectionData();
2203 
2204         Assert.assertNotNull(encryptedBytes);
2205         Assert.assertNotNull(
2206                 mEncryptionContextDao.getEncryptionContext(
2207                         adSelectionId, ENCRYPTION_KEY_TYPE_AUCTION));
2208 
2209         byte[] encryptedServerResponse =
2210                 mServerAuctionTestHelper.encryptServerAuctionResult(
2211                         callback.mGetAdSelectionDataResponse, AUCTION_RESULT_CHAFF);
2212 
2213         PersistAdSelectionResultInput persistAdSelectionResultInput =
2214                 new PersistAdSelectionResultInput.Builder()
2215                         .setSeller(SELLER)
2216                         .setAdSelectionId(adSelectionId)
2217                         .setAdSelectionResult(encryptedServerResponse)
2218                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2219                         .build();
2220 
2221         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
2222                 invokePersistAdSelectionResult(service, persistAdSelectionResultInput);
2223 
2224         assertTrue(persistAdSelectionResultTestCallback.mIsSuccess);
2225         Assert.assertEquals(
2226                 Uri.EMPTY,
2227                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
2228                         .getAdRenderUri());
2229     }
2230 
2231     @Test
2232     @SetFlagFalse(KEY_FLEDGE_ON_DEVICE_AUCTION_SHOULD_USE_UNIFIED_TABLES)
2233     public void
testReportImpression_serverAuction_impressionAndInteractionReportingUnifiedTablesDisabled()2234             testReportImpression_serverAuction_impressionAndInteractionReportingUnifiedTablesDisabled()
2235                     throws Exception {
2236         // Re init service with new flags
2237         AdSelectionServiceImpl adSelectionService =
2238                 new AdSelectionServiceImpl(
2239                         mAdSelectionEntryDao,
2240                         mAppInstallDao,
2241                         mCustomAudienceDaoSpy,
2242                         mEncodedPayloadDaoSpy,
2243                         mFrequencyCapDaoSpy,
2244                         mEncryptionKeyDao,
2245                         mEnrollmentDao,
2246                         mAdServicesHttpsClientSpy,
2247                         mDevContextFilterMock,
2248                         mLightweightExecutorService,
2249                         mBackgroundExecutorService,
2250                         mScheduledExecutor,
2251                         mContext,
2252                         mAdServicesLoggerMock,
2253                         mFakeFlags,
2254                         mFakeDebugFlags,
2255                         CallingAppUidSupplierProcessImpl.create(),
2256                         mFledgeAuthorizationFilterMock,
2257                         mAdSelectionServiceFilterMock,
2258                         mAdFilteringFeatureFactory,
2259                         mConsentManagerMock,
2260                         mObliviousHttpEncryptorMock,
2261                         mAdSelectionDebugReportDaoSpy,
2262                         mAdIdFetcher,
2263                         mUnusedKAnonSignJoinFactory,
2264                         /* shouldUseUnifiedTables= */ false,
2265                         mRetryStrategyFactory,
2266                         CONSOLE_MESSAGE_IN_LOGS_ENABLED,
2267                         mAuctionServerDebugConfigurationGenerator,
2268                         mServerAuctionCoordinatorUriStrategyFactory);
2269 
2270         Assume.assumeTrue(WebViewSupportUtil.isJSSandboxAvailable(mContext));
2271         mocker.mockGetFlags(new LegacyAuctionServerE2ETestFlags());
2272 
2273         CountDownLatch reportImpressionCountDownLatch = new CountDownLatch(4);
2274         Answer<ListenableFuture<Void>> successReportImpressionGetAnswer =
2275                 invocation -> {
2276                     reportImpressionCountDownLatch.countDown();
2277                     return Futures.immediateFuture(null);
2278                 };
2279         doAnswer(successReportImpressionGetAnswer)
2280                 .when(mAdServicesHttpsClientSpy)
2281                 .getAndReadNothing(any(Uri.class), any(DevContext.class));
2282         doAnswer(successReportImpressionGetAnswer)
2283                 .when(mAdServicesHttpsClientSpy)
2284                 .postPlainText(any(Uri.class), any(String.class), any(DevContext.class));
2285 
2286         when(mObliviousHttpEncryptorMock.encryptBytes(
2287                         any(byte[].class), anyLong(), anyLong(), any(), any()))
2288                 .thenAnswer(
2289                         invocation ->
2290                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
2291         when(mObliviousHttpEncryptorMock.decryptBytes(any(byte[].class), anyLong()))
2292                 .thenAnswer(invocation -> invocation.getArgument(0));
2293 
2294         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
2295                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
2296                                 WINNER_BUYER,
2297                                 WINNING_CUSTOM_AUDIENCE_NAME,
2298                                 WINNING_CUSTOM_AUDIENCE_OWNER)
2299                         .setAds(
2300                                 DBAdDataFixture.getValidDbAdDataListByBuyerWithAdRenderId(
2301                                         WINNER_BUYER))
2302                         .build(),
2303                 Uri.EMPTY,
2304                 false,
2305                 List.of());
2306 
2307         GetAdSelectionDataInput input =
2308                 new GetAdSelectionDataInput.Builder()
2309                         .setSeller(SELLER)
2310                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2311                         .build();
2312 
2313         GetAdSelectionDataTestCallback getAdSelectionDataTestCallback =
2314                 invokeGetAdSelectionData(adSelectionService, input);
2315         long adSelectionId =
2316                 getAdSelectionDataTestCallback.mGetAdSelectionDataResponse.getAdSelectionId();
2317 
2318         PersistAdSelectionResultInput persistAdSelectionResultInput =
2319                 new PersistAdSelectionResultInput.Builder()
2320                         .setAdSelectionId(adSelectionId)
2321                         .setSeller(SELLER)
2322                         .setAdSelectionResult(prepareAuctionResultBytes())
2323                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2324                         .build();
2325 
2326         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
2327                 invokePersistAdSelectionResult(adSelectionService, persistAdSelectionResultInput);
2328         Uri adRenderUriFromPersistAdSelectionResult =
2329                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
2330                         .getAdRenderUri();
2331         Assert.assertTrue(persistAdSelectionResultTestCallback.mIsSuccess);
2332         Assert.assertEquals(WINNER_AD_RENDER_URI, adRenderUriFromPersistAdSelectionResult);
2333         Assert.assertEquals(
2334                 adSelectionId,
2335                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
2336                         .getAdSelectionId());
2337         Assert.assertEquals(
2338                 BUYER_REPORTING_URI,
2339                 mAdSelectionEntryDao
2340                         .getReportingUris(adSelectionId)
2341                         .getBuyerWinReportingUri()
2342                         .toString());
2343         Assert.assertEquals(
2344                 SELLER_REPORTING_URI,
2345                 mAdSelectionEntryDao
2346                         .getReportingUris(adSelectionId)
2347                         .getSellerWinReportingUri()
2348                         .toString());
2349 
2350         // Invoke report impression
2351         ReportImpressionInput reportImpressionInput =
2352                 new ReportImpressionInput.Builder()
2353                         .setAdSelectionId(adSelectionId)
2354                         .setAdSelectionConfig(AdSelectionConfig.EMPTY)
2355                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2356                         .build();
2357         ReportImpressionTestCallback reportImpressionCallback =
2358                 invokeReportImpression(adSelectionService, reportImpressionInput);
2359 
2360         // Invoke report interaction for buyer
2361         String buyerInteractionData = "buyer-interaction-data";
2362         ReportInteractionInput reportBuyerInteractionInput =
2363                 new ReportInteractionInput.Builder()
2364                         .setAdSelectionId(adSelectionId)
2365                         .setInteractionKey(BUYER_INTERACTION_KEY)
2366                         .setInteractionData(buyerInteractionData)
2367                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2368                         .setReportingDestinations(
2369                                 ReportEventRequest.FLAG_REPORTING_DESTINATION_BUYER)
2370                         .build();
2371         ReportInteractionsTestCallback reportBuyerInteractionsCallback =
2372                 invokeReportInteractions(adSelectionService, reportBuyerInteractionInput);
2373 
2374         // Invoke report interaction for seller
2375         String sellerInteractionData = "seller-interaction-data";
2376         ReportInteractionInput reportSellerInteractionInput =
2377                 new ReportInteractionInput.Builder()
2378                         .setAdSelectionId(adSelectionId)
2379                         .setInteractionKey(SELLER_INTERACTION_KEY)
2380                         .setInteractionData(sellerInteractionData)
2381                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2382                         .setReportingDestinations(
2383                                 ReportEventRequest.FLAG_REPORTING_DESTINATION_SELLER)
2384                         .build();
2385         ReportInteractionsTestCallback reportSellerInteractionsCallback =
2386                 invokeReportInteractions(adSelectionService, reportSellerInteractionInput);
2387 
2388         // Wait for countdown latch
2389         boolean isCountdownDone =
2390                 reportImpressionCountDownLatch.await(
2391                         COUNTDOWN_LATCH_LIMIT_SECONDS, TimeUnit.SECONDS);
2392         Assert.assertTrue(isCountdownDone);
2393 
2394         // Assert report impression
2395         Assert.assertTrue(reportImpressionCallback.mIsSuccess);
2396         verify(mAdServicesHttpsClientSpy, times(1))
2397                 .getAndReadNothing(eq(Uri.parse(SELLER_REPORTING_URI)), any());
2398         verify(mAdServicesHttpsClientSpy, times(1))
2399                 .getAndReadNothing(eq(Uri.parse(BUYER_REPORTING_URI)), any());
2400 
2401         // Assert report interaction for buyer
2402         Assert.assertTrue(reportBuyerInteractionsCallback.mIsSuccess);
2403         verify(mAdServicesHttpsClientSpy, times(1))
2404                 .postPlainText(
2405                         eq(Uri.parse(BUYER_INTERACTION_URI)), eq(buyerInteractionData), any());
2406 
2407         // Assert report interaction for seller
2408         Assert.assertTrue(reportSellerInteractionsCallback.mIsSuccess);
2409         verify(mAdServicesHttpsClientSpy, times(1))
2410                 .postPlainText(
2411                         eq(Uri.parse(SELLER_INTERACTION_URI)), eq(sellerInteractionData), any());
2412     }
2413 
2414     @Test
2415     @SetFlagTrue(KEY_FLEDGE_ON_DEVICE_AUCTION_SHOULD_USE_UNIFIED_TABLES)
2416     public void
testReportImpression_serverAuction_impressionAndInteractionReportingUnifiedTablesEnabled()2417             testReportImpression_serverAuction_impressionAndInteractionReportingUnifiedTablesEnabled()
2418                     throws Exception {
2419         // Re init service with new flags
2420         AdSelectionServiceImpl adSelectionService =
2421                 new AdSelectionServiceImpl(
2422                         mAdSelectionEntryDao,
2423                         mAppInstallDao,
2424                         mCustomAudienceDaoSpy,
2425                         mEncodedPayloadDaoSpy,
2426                         mFrequencyCapDaoSpy,
2427                         mEncryptionKeyDao,
2428                         mEnrollmentDao,
2429                         mAdServicesHttpsClientSpy,
2430                         mDevContextFilterMock,
2431                         mLightweightExecutorService,
2432                         mBackgroundExecutorService,
2433                         mScheduledExecutor,
2434                         mContext,
2435                         mAdServicesLoggerMock,
2436                         mFakeFlags,
2437                         mFakeDebugFlags,
2438                         CallingAppUidSupplierProcessImpl.create(),
2439                         mFledgeAuthorizationFilterMock,
2440                         mAdSelectionServiceFilterMock,
2441                         mAdFilteringFeatureFactory,
2442                         mConsentManagerMock,
2443                         mObliviousHttpEncryptorMock,
2444                         mAdSelectionDebugReportDaoSpy,
2445                         mAdIdFetcher,
2446                         mUnusedKAnonSignJoinFactory,
2447                         /* shouldUseUnifiedTables= */ true,
2448                         mRetryStrategyFactory,
2449                         CONSOLE_MESSAGE_IN_LOGS_ENABLED,
2450                         mAuctionServerDebugConfigurationGenerator,
2451                         mServerAuctionCoordinatorUriStrategyFactory);
2452 
2453         Assume.assumeTrue(WebViewSupportUtil.isJSSandboxAvailable(mContext));
2454         mocker.mockGetFlags(new LegacyAuctionServerE2ETestFlags());
2455 
2456         CountDownLatch reportImpressionCountDownLatch = new CountDownLatch(4);
2457         Answer<ListenableFuture<Void>> successReportImpressionGetAnswer =
2458                 invocation -> {
2459                     reportImpressionCountDownLatch.countDown();
2460                     return Futures.immediateFuture(null);
2461                 };
2462         doAnswer(successReportImpressionGetAnswer)
2463                 .when(mAdServicesHttpsClientSpy)
2464                 .getAndReadNothing(any(Uri.class), any(DevContext.class));
2465         doAnswer(successReportImpressionGetAnswer)
2466                 .when(mAdServicesHttpsClientSpy)
2467                 .postPlainText(any(Uri.class), any(String.class), any(DevContext.class));
2468 
2469         when(mObliviousHttpEncryptorMock.encryptBytes(
2470                         any(byte[].class), anyLong(), anyLong(), any(), any()))
2471                 .thenAnswer(
2472                         invocation ->
2473                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
2474         when(mObliviousHttpEncryptorMock.decryptBytes(any(byte[].class), anyLong()))
2475                 .thenAnswer(invocation -> invocation.getArgument(0));
2476 
2477         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
2478                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
2479                                 WINNER_BUYER,
2480                                 WINNING_CUSTOM_AUDIENCE_NAME,
2481                                 WINNING_CUSTOM_AUDIENCE_OWNER)
2482                         .setAds(
2483                                 DBAdDataFixture.getValidDbAdDataListByBuyerWithAdRenderId(
2484                                         WINNER_BUYER))
2485                         .build(),
2486                 Uri.EMPTY,
2487                 false,
2488                 List.of());
2489 
2490         GetAdSelectionDataInput input =
2491                 new GetAdSelectionDataInput.Builder()
2492                         .setSeller(SELLER)
2493                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2494                         .build();
2495 
2496         GetAdSelectionDataTestCallback getAdSelectionDataTestCallback =
2497                 invokeGetAdSelectionData(adSelectionService, input);
2498         long adSelectionId =
2499                 getAdSelectionDataTestCallback.mGetAdSelectionDataResponse.getAdSelectionId();
2500 
2501         PersistAdSelectionResultInput persistAdSelectionResultInput =
2502                 new PersistAdSelectionResultInput.Builder()
2503                         .setAdSelectionId(adSelectionId)
2504                         .setSeller(SELLER)
2505                         .setAdSelectionResult(prepareAuctionResultBytes())
2506                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2507                         .build();
2508 
2509         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
2510                 invokePersistAdSelectionResult(adSelectionService, persistAdSelectionResultInput);
2511         Uri adRenderUriFromPersistAdSelectionResult =
2512                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
2513                         .getAdRenderUri();
2514         Assert.assertTrue(persistAdSelectionResultTestCallback.mIsSuccess);
2515         Assert.assertEquals(WINNER_AD_RENDER_URI, adRenderUriFromPersistAdSelectionResult);
2516         Assert.assertEquals(
2517                 adSelectionId,
2518                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
2519                         .getAdSelectionId());
2520         Assert.assertEquals(
2521                 BUYER_REPORTING_URI,
2522                 mAdSelectionEntryDao
2523                         .getReportingUris(adSelectionId)
2524                         .getBuyerWinReportingUri()
2525                         .toString());
2526         Assert.assertEquals(
2527                 SELLER_REPORTING_URI,
2528                 mAdSelectionEntryDao
2529                         .getReportingUris(adSelectionId)
2530                         .getSellerWinReportingUri()
2531                         .toString());
2532 
2533         // Invoke report impression
2534         ReportImpressionInput reportImpressionInput =
2535                 new ReportImpressionInput.Builder()
2536                         .setAdSelectionId(adSelectionId)
2537                         .setAdSelectionConfig(AdSelectionConfig.EMPTY)
2538                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2539                         .build();
2540         ReportImpressionTestCallback reportImpressionCallback =
2541                 invokeReportImpression(adSelectionService, reportImpressionInput);
2542 
2543         // Invoke report interaction for buyer
2544         String buyerInteractionData = "buyer-interaction-data";
2545         ReportInteractionInput reportBuyerInteractionInput =
2546                 new ReportInteractionInput.Builder()
2547                         .setAdSelectionId(adSelectionId)
2548                         .setInteractionKey(BUYER_INTERACTION_KEY)
2549                         .setInteractionData(buyerInteractionData)
2550                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2551                         .setReportingDestinations(
2552                                 ReportEventRequest.FLAG_REPORTING_DESTINATION_BUYER)
2553                         .build();
2554         ReportInteractionsTestCallback reportBuyerInteractionsCallback =
2555                 invokeReportInteractions(adSelectionService, reportBuyerInteractionInput);
2556 
2557         // Invoke report interaction for seller
2558         String sellerInteractionData = "seller-interaction-data";
2559         ReportInteractionInput reportSellerInteractionInput =
2560                 new ReportInteractionInput.Builder()
2561                         .setAdSelectionId(adSelectionId)
2562                         .setInteractionKey(SELLER_INTERACTION_KEY)
2563                         .setInteractionData(sellerInteractionData)
2564                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2565                         .setReportingDestinations(
2566                                 ReportEventRequest.FLAG_REPORTING_DESTINATION_SELLER)
2567                         .build();
2568         ReportInteractionsTestCallback reportSellerInteractionsCallback =
2569                 invokeReportInteractions(adSelectionService, reportSellerInteractionInput);
2570 
2571         // Wait for countdown latch
2572         boolean isCountdownDone =
2573                 reportImpressionCountDownLatch.await(
2574                         COUNTDOWN_LATCH_LIMIT_SECONDS, TimeUnit.SECONDS);
2575         Assert.assertTrue(isCountdownDone);
2576 
2577         // Assert report impression
2578         Assert.assertTrue(reportImpressionCallback.mIsSuccess);
2579         verify(mAdServicesHttpsClientSpy, times(1))
2580                 .getAndReadNothing(eq(Uri.parse(SELLER_REPORTING_URI)), any());
2581         verify(mAdServicesHttpsClientSpy, times(1))
2582                 .getAndReadNothing(eq(Uri.parse(BUYER_REPORTING_URI)), any());
2583 
2584         // Assert report interaction for buyer
2585         Assert.assertTrue(reportBuyerInteractionsCallback.mIsSuccess);
2586         verify(mAdServicesHttpsClientSpy, times(1))
2587                 .postPlainText(
2588                         eq(Uri.parse(BUYER_INTERACTION_URI)), eq(buyerInteractionData), any());
2589 
2590         // Assert report interaction for seller
2591         Assert.assertTrue(reportSellerInteractionsCallback.mIsSuccess);
2592         verify(mAdServicesHttpsClientSpy, times(1))
2593                 .postPlainText(
2594                         eq(Uri.parse(SELLER_INTERACTION_URI)), eq(sellerInteractionData), any());
2595     }
2596 
2597     @Test
testReportImpression_serverAuction_sellerReportingFailure_noExceptionThrown()2598     public void testReportImpression_serverAuction_sellerReportingFailure_noExceptionThrown()
2599             throws Exception {
2600         Assume.assumeTrue(WebViewSupportUtil.isJSSandboxAvailable(mContext));
2601 
2602         CountDownLatch reportImpressionCountDownLatch = new CountDownLatch(2);
2603         Answer<ListenableFuture<Void>> failedReportImpressionGetAnswer =
2604                 invocation -> {
2605                     reportImpressionCountDownLatch.countDown();
2606                     return Futures.immediateFailedFuture(
2607                             new IllegalStateException("Exception for test!"));
2608                 };
2609         Answer<ListenableFuture<Void>> successReportImpressionGetAnswer =
2610                 invocation -> {
2611                     reportImpressionCountDownLatch.countDown();
2612                     return Futures.immediateFuture(null);
2613                 };
2614         doAnswer(successReportImpressionGetAnswer)
2615                 .when(mAdServicesHttpsClientSpy)
2616                 .getAndReadNothing(eq(Uri.parse(BUYER_REPORTING_URI)), any(DevContext.class));
2617         doAnswer(failedReportImpressionGetAnswer)
2618                 .when(mAdServicesHttpsClientSpy)
2619                 .getAndReadNothing(eq(Uri.parse(SELLER_REPORTING_URI)), any(DevContext.class));
2620 
2621         when(mObliviousHttpEncryptorMock.encryptBytes(
2622                         any(byte[].class), anyLong(), anyLong(), any(), any()))
2623                 .thenAnswer(
2624                         invocation ->
2625                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
2626         when(mObliviousHttpEncryptorMock.decryptBytes(any(byte[].class), anyLong()))
2627                 .thenAnswer(invocation -> invocation.getArgument(0));
2628 
2629         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
2630                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
2631                                 WINNER_BUYER,
2632                                 WINNING_CUSTOM_AUDIENCE_NAME,
2633                                 WINNING_CUSTOM_AUDIENCE_OWNER)
2634                         .setAds(
2635                                 DBAdDataFixture.getValidDbAdDataListByBuyerWithAdRenderId(
2636                                         WINNER_BUYER))
2637                         .build(),
2638                 Uri.EMPTY,
2639                 false,
2640                 List.of());
2641 
2642         GetAdSelectionDataInput input =
2643                 new GetAdSelectionDataInput.Builder()
2644                         .setSeller(SELLER)
2645                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2646                         .build();
2647 
2648         GetAdSelectionDataTestCallback getAdSelectionDataTestCallback =
2649                 invokeGetAdSelectionData(mAdSelectionService, input);
2650         long adSelectionId =
2651                 getAdSelectionDataTestCallback.mGetAdSelectionDataResponse.getAdSelectionId();
2652 
2653         PersistAdSelectionResultInput persistAdSelectionResultInput =
2654                 new PersistAdSelectionResultInput.Builder()
2655                         .setAdSelectionId(adSelectionId)
2656                         .setSeller(SELLER)
2657                         .setAdSelectionResult(prepareAuctionResultBytes())
2658                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2659                         .build();
2660 
2661         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
2662                 invokePersistAdSelectionResult(mAdSelectionService, persistAdSelectionResultInput);
2663 
2664         Uri adRenderUriFromPersistAdSelectionResult =
2665                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
2666                         .getAdRenderUri();
2667         assertTrue(persistAdSelectionResultTestCallback.mIsSuccess);
2668         Assert.assertEquals(WINNER_AD_RENDER_URI, adRenderUriFromPersistAdSelectionResult);
2669         Assert.assertEquals(
2670                 adSelectionId,
2671                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
2672                         .getAdSelectionId());
2673         Assert.assertEquals(
2674                 BUYER_REPORTING_URI,
2675                 mAdSelectionEntryDao
2676                         .getReportingUris(adSelectionId)
2677                         .getBuyerWinReportingUri()
2678                         .toString());
2679         Assert.assertEquals(
2680                 SELLER_REPORTING_URI,
2681                 mAdSelectionEntryDao
2682                         .getReportingUris(adSelectionId)
2683                         .getSellerWinReportingUri()
2684                         .toString());
2685 
2686         ReportImpressionInput reportImpressionInput =
2687                 new ReportImpressionInput.Builder()
2688                         .setAdSelectionId(adSelectionId)
2689                         .setAdSelectionConfig(AdSelectionConfig.EMPTY)
2690                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2691                         .build();
2692         ReportImpressionTestCallback callback =
2693                 invokeReportImpression(mAdSelectionService, reportImpressionInput);
2694         boolean isCountdownDone =
2695                 reportImpressionCountDownLatch.await(
2696                         COUNTDOWN_LATCH_LIMIT_SECONDS, TimeUnit.SECONDS);
2697         assertTrue(isCountdownDone);
2698         assertTrue(callback.mIsSuccess);
2699         verify(mAdServicesHttpsClientSpy, times(1))
2700                 .getAndReadNothing(eq(Uri.parse(SELLER_REPORTING_URI)), any());
2701         verify(mAdServicesHttpsClientSpy, times(1))
2702                 .getAndReadNothing(eq(Uri.parse(BUYER_REPORTING_URI)), any());
2703     }
2704 
2705     @Test
testReportImpression_serverAuction_buyerReportingFailure_noExceptionThrown()2706     public void testReportImpression_serverAuction_buyerReportingFailure_noExceptionThrown()
2707             throws Exception {
2708         Assume.assumeTrue(WebViewSupportUtil.isJSSandboxAvailable(mContext));
2709 
2710         CountDownLatch reportImpressionCountDownLatch = new CountDownLatch(2);
2711         Answer<ListenableFuture<Void>> failedReportImpressionGetAnswer =
2712                 invocation -> {
2713                     reportImpressionCountDownLatch.countDown();
2714                     return Futures.immediateFailedFuture(
2715                             new IllegalStateException("Exception for test!"));
2716                 };
2717         Answer<ListenableFuture<Void>> successReportImpressionGetAnswer =
2718                 invocation -> {
2719                     reportImpressionCountDownLatch.countDown();
2720                     return Futures.immediateFuture(null);
2721                 };
2722         doAnswer(successReportImpressionGetAnswer)
2723                 .when(mAdServicesHttpsClientSpy)
2724                 .getAndReadNothing(eq(Uri.parse(SELLER_REPORTING_URI)), any(DevContext.class));
2725         doAnswer(failedReportImpressionGetAnswer)
2726                 .when(mAdServicesHttpsClientSpy)
2727                 .getAndReadNothing(eq(Uri.parse(BUYER_REPORTING_URI)), any(DevContext.class));
2728 
2729         when(mObliviousHttpEncryptorMock.encryptBytes(
2730                         any(byte[].class), anyLong(), anyLong(), any(), any()))
2731                 .thenAnswer(
2732                         invocation ->
2733                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
2734         when(mObliviousHttpEncryptorMock.decryptBytes(any(byte[].class), anyLong()))
2735                 .thenAnswer(invocation -> invocation.getArgument(0));
2736 
2737         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
2738                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
2739                                 WINNER_BUYER,
2740                                 WINNING_CUSTOM_AUDIENCE_NAME,
2741                                 WINNING_CUSTOM_AUDIENCE_OWNER)
2742                         .setAds(
2743                                 DBAdDataFixture.getValidDbAdDataListByBuyerWithAdRenderId(
2744                                         WINNER_BUYER))
2745                         .build(),
2746                 Uri.EMPTY,
2747                 false,
2748                 List.of());
2749 
2750         GetAdSelectionDataInput input =
2751                 new GetAdSelectionDataInput.Builder()
2752                         .setSeller(SELLER)
2753                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2754                         .build();
2755 
2756         GetAdSelectionDataTestCallback getAdSelectionDataTestCallback =
2757                 invokeGetAdSelectionData(mAdSelectionService, input);
2758         long adSelectionId =
2759                 getAdSelectionDataTestCallback.mGetAdSelectionDataResponse.getAdSelectionId();
2760 
2761         PersistAdSelectionResultInput persistAdSelectionResultInput =
2762                 new PersistAdSelectionResultInput.Builder()
2763                         .setAdSelectionId(adSelectionId)
2764                         .setSeller(SELLER)
2765                         .setAdSelectionResult(prepareAuctionResultBytes())
2766                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2767                         .build();
2768 
2769         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
2770                 invokePersistAdSelectionResult(mAdSelectionService, persistAdSelectionResultInput);
2771 
2772         Uri adRenderUriFromPersistAdSelectionResult =
2773                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
2774                         .getAdRenderUri();
2775         assertTrue(persistAdSelectionResultTestCallback.mIsSuccess);
2776         Assert.assertEquals(WINNER_AD_RENDER_URI, adRenderUriFromPersistAdSelectionResult);
2777         Assert.assertEquals(
2778                 adSelectionId,
2779                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
2780                         .getAdSelectionId());
2781         Assert.assertEquals(
2782                 BUYER_REPORTING_URI,
2783                 mAdSelectionEntryDao
2784                         .getReportingUris(adSelectionId)
2785                         .getBuyerWinReportingUri()
2786                         .toString());
2787         Assert.assertEquals(
2788                 SELLER_REPORTING_URI,
2789                 mAdSelectionEntryDao
2790                         .getReportingUris(adSelectionId)
2791                         .getSellerWinReportingUri()
2792                         .toString());
2793 
2794         ReportImpressionInput reportImpressionInput =
2795                 new ReportImpressionInput.Builder()
2796                         .setAdSelectionId(adSelectionId)
2797                         .setAdSelectionConfig(AdSelectionConfig.EMPTY)
2798                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2799                         .build();
2800 
2801         ReportImpressionTestCallback callback =
2802                 invokeReportImpression(mAdSelectionService, reportImpressionInput);
2803         assertTrue(callback.mIsSuccess);
2804         boolean isCountdownDone =
2805                 reportImpressionCountDownLatch.await(
2806                         COUNTDOWN_LATCH_LIMIT_SECONDS, TimeUnit.SECONDS);
2807         assertTrue(isCountdownDone);
2808         verify(mAdServicesHttpsClientSpy, times(1))
2809                 .getAndReadNothing(eq(Uri.parse(SELLER_REPORTING_URI)), any());
2810         verify(mAdServicesHttpsClientSpy, times(1))
2811                 .getAndReadNothing(eq(Uri.parse(BUYER_REPORTING_URI)), any());
2812     }
2813 
2814     @Test
testPersistAdSelectionResult_withoutDecrypt_savesWinEventsSuccess()2815     public void testPersistAdSelectionResult_withoutDecrypt_savesWinEventsSuccess()
2816             throws Exception {
2817         mAdFilteringFeatureFactory =
2818                 new AdFilteringFeatureFactory(mAppInstallDao, mFrequencyCapDaoSpy, mFakeFlags);
2819         mAdSelectionService = createAdSelectionService();
2820 
2821         when(mObliviousHttpEncryptorMock.encryptBytes(
2822                         any(byte[].class), anyLong(), anyLong(), any(), any()))
2823                 .thenAnswer(
2824                         invocation ->
2825                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
2826         when(mObliviousHttpEncryptorMock.decryptBytes(any(byte[].class), anyLong()))
2827                 .thenAnswer(invocation -> invocation.getArgument(0));
2828 
2829         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
2830                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
2831                                 WINNER_BUYER,
2832                                 WINNING_CUSTOM_AUDIENCE_NAME,
2833                                 WINNING_CUSTOM_AUDIENCE_OWNER)
2834                         .setAds(
2835                                 DBAdDataFixture.getValidDbAdDataListByBuyerWithAdRenderId(
2836                                         WINNER_BUYER))
2837                         .build(),
2838                 Uri.EMPTY,
2839                 false,
2840                 List.of());
2841 
2842         GetAdSelectionDataInput input =
2843                 new GetAdSelectionDataInput.Builder()
2844                         .setSeller(SELLER)
2845                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2846                         .build();
2847 
2848         GetAdSelectionDataTestCallback getAdSelectionDataTestCallback =
2849                 invokeGetAdSelectionData(mAdSelectionService, input);
2850         assertTrue(getAdSelectionDataTestCallback.mIsSuccess);
2851         long adSelectionId =
2852                 getAdSelectionDataTestCallback.mGetAdSelectionDataResponse.getAdSelectionId();
2853 
2854         PersistAdSelectionResultInput persistAdSelectionResultInput =
2855                 new PersistAdSelectionResultInput.Builder()
2856                         .setAdSelectionId(adSelectionId)
2857                         .setSeller(SELLER)
2858                         .setAdSelectionResult(prepareAuctionResultBytes())
2859                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2860                         .build();
2861 
2862         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
2863                 invokePersistAdSelectionResult(mAdSelectionService, persistAdSelectionResultInput);
2864         assertTrue(persistAdSelectionResultTestCallback.mIsSuccess);
2865 
2866         // Assert fcap win reporting
2867         ArgumentCaptor<HistogramEvent> histogramEventArgumentCaptor =
2868                 ArgumentCaptor.forClass(HistogramEvent.class);
2869         verify(mFrequencyCapDaoSpy, times(WINNER_AD_COUNTERS.size()))
2870                 .insertHistogramEvent(
2871                         histogramEventArgumentCaptor.capture(),
2872                         anyInt(),
2873                         anyInt(),
2874                         anyInt(),
2875                         anyInt());
2876         List<HistogramEvent> capturedHistogramEventList =
2877                 histogramEventArgumentCaptor.getAllValues();
2878         Assert.assertEquals(
2879                 FrequencyCapFilters.AD_EVENT_TYPE_WIN,
2880                 capturedHistogramEventList.get(0).getAdEventType());
2881         Assert.assertEquals(
2882                 WINNER_AD_COUNTERS,
2883                 capturedHistogramEventList.stream()
2884                         .map(HistogramEvent::getAdCounterKey)
2885                         .collect(Collectors.toSet()));
2886     }
2887 
2888     @Test
testPersistAdSelectionResult_withoutDecrypt_savesNonWinEventsSuccess()2889     public void testPersistAdSelectionResult_withoutDecrypt_savesNonWinEventsSuccess()
2890             throws Exception {
2891         mAdFilteringFeatureFactory =
2892                 new AdFilteringFeatureFactory(mAppInstallDao, mFrequencyCapDaoSpy, mFakeFlags);
2893         mAdSelectionService = createAdSelectionService();
2894 
2895         when(mObliviousHttpEncryptorMock.encryptBytes(
2896                         any(byte[].class), anyLong(), anyLong(), any(), any()))
2897                 .thenAnswer(
2898                         invocation ->
2899                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
2900         when(mObliviousHttpEncryptorMock.decryptBytes(any(byte[].class), anyLong()))
2901                 .thenAnswer(invocation -> invocation.getArgument(0));
2902 
2903         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
2904                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
2905                                 WINNER_BUYER,
2906                                 WINNING_CUSTOM_AUDIENCE_NAME,
2907                                 WINNING_CUSTOM_AUDIENCE_OWNER)
2908                         .setAds(
2909                                 DBAdDataFixture.getValidDbAdDataListByBuyerWithAdRenderId(
2910                                         WINNER_BUYER))
2911                         .build(),
2912                 Uri.EMPTY,
2913                 false,
2914                 List.of());
2915 
2916         GetAdSelectionDataInput input =
2917                 new GetAdSelectionDataInput.Builder()
2918                         .setSeller(SELLER)
2919                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2920                         .build();
2921 
2922         GetAdSelectionDataTestCallback getAdSelectionDataTestCallback =
2923                 invokeGetAdSelectionData(mAdSelectionService, input);
2924         assertTrue(getAdSelectionDataTestCallback.mIsSuccess);
2925         long adSelectionId =
2926                 getAdSelectionDataTestCallback.mGetAdSelectionDataResponse.getAdSelectionId();
2927 
2928         PersistAdSelectionResultInput persistAdSelectionResultInput =
2929                 new PersistAdSelectionResultInput.Builder()
2930                         .setAdSelectionId(adSelectionId)
2931                         .setSeller(SELLER)
2932                         .setAdSelectionResult(prepareAuctionResultBytes())
2933                         .setCallerPackageName(CALLER_PACKAGE_NAME)
2934                         .build();
2935 
2936         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
2937                 invokePersistAdSelectionResult(mAdSelectionService, persistAdSelectionResultInput);
2938         assertTrue(persistAdSelectionResultTestCallback.mIsSuccess);
2939 
2940         // Assert fcap non-win reporting
2941         UpdateAdCounterHistogramInput updateHistogramInput =
2942                 new UpdateAdCounterHistogramInput.Builder(
2943                                 adSelectionId,
2944                                 FrequencyCapFilters.AD_EVENT_TYPE_VIEW,
2945                                 SELLER,
2946                                 CALLER_PACKAGE_NAME)
2947                         .build();
2948         UpdateAdCounterHistogramTestCallback updateHistogramCallback =
2949                 invokeUpdateAdCounterHistogram(mAdSelectionService, updateHistogramInput);
2950 
2951         int numOfKeys = WINNER_AD_COUNTERS.size();
2952         ArgumentCaptor<HistogramEvent> histogramEventArgumentCaptor =
2953                 ArgumentCaptor.forClass(HistogramEvent.class);
2954         assertTrue(updateHistogramCallback.mIsSuccess);
2955         verify(
2956                         mFrequencyCapDaoSpy,
2957                         // Each key is reported twice; WIN and VIEW events
2958                         times(2 * numOfKeys))
2959                 .insertHistogramEvent(
2960                         histogramEventArgumentCaptor.capture(),
2961                         anyInt(),
2962                         anyInt(),
2963                         anyInt(),
2964                         anyInt());
2965         List<HistogramEvent> capturedHistogramEventList =
2966                 histogramEventArgumentCaptor.getAllValues();
2967         Assert.assertEquals(
2968                 FrequencyCapFilters.AD_EVENT_TYPE_WIN,
2969                 capturedHistogramEventList.get(0).getAdEventType());
2970         Assert.assertEquals(
2971                 FrequencyCapFilters.AD_EVENT_TYPE_VIEW,
2972                 capturedHistogramEventList.get(numOfKeys).getAdEventType());
2973         Assert.assertEquals(
2974                 WINNER_AD_COUNTERS,
2975                 capturedHistogramEventList.subList(numOfKeys, 2 * numOfKeys).stream()
2976                         .map(HistogramEvent::getAdCounterKey)
2977                         .collect(Collectors.toSet()));
2978     }
2979 
2980     @Test
2981     @SetFlagTrue(KEY_FLEDGE_AUCTION_SERVER_MEDIA_TYPE_CHANGE_ENABLED)
testGetAdSelectionData_withServerAuctionMediaTypeChanged()2982     public void testGetAdSelectionData_withServerAuctionMediaTypeChanged() throws Exception {
2983         testPersistAdselectionResult_withCompleteAuction_success();
2984     }
2985 
2986     @Test
testGetAdSelectionData_shellCommand_success()2987     public void testGetAdSelectionData_shellCommand_success() throws Exception {
2988         String privateKeyHex = "e7b292f49df28b8065992cdeadbc9d032a0e09e8476cb6d8d507212e7be3b9b4";
2989         OhttpGatewayPrivateKey privKey =
2990                 OhttpGatewayPrivateKey.create(
2991                         BaseEncoding.base16().lowerCase().decode(privateKeyHex));
2992         AuctionEncryptionKeyFixture.AuctionKey auctionKey =
2993                 AuctionEncryptionKeyFixture.AuctionKey.builder()
2994                         .setKeyId("400bed24-c62f-46e0-a1ad-211361ad771a")
2995                         .setPublicKey("87ey8XZPXAd+/+ytKv2GFUWW5j9zdepSJ2G4gebDwyM=")
2996                         .build();
2997         AdServicesHttpClientResponse httpClientResponse =
2998                 AuctionEncryptionKeyFixture.mockAuctionKeyFetchResponseWithGivenKey(auctionKey);
2999         when(mMockHttpClient.fetchPayloadWithLogging(
3000                         eq(Uri.parse(COORDINATOR_URL)),
3001                         eq(DevContext.createForDevOptionsDisabled()),
3002                         any(FetchProcessLogger.class)))
3003                 .thenReturn(Futures.immediateFuture(httpClientResponse));
3004         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
3005                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
3006                                 WINNER_BUYER,
3007                                 WINNING_CUSTOM_AUDIENCE_NAME,
3008                                 WINNING_CUSTOM_AUDIENCE_OWNER)
3009                         .setAds(
3010                                 DBAdDataFixture.getValidDbAdDataListByBuyerWithAdRenderId(
3011                                         WINNER_BUYER))
3012                         .build(),
3013                 Uri.EMPTY,
3014                 false,
3015                 List.of());
3016         AdSelectionService service = createServiceWithMockHttpClient();
3017         GetAdSelectionDataInput input =
3018                 new GetAdSelectionDataInput.Builder()
3019                         .setSeller(SELLER)
3020                         .setCallerPackageName(CALLER_PACKAGE_NAME)
3021                         .setCoordinatorOriginUri(Uri.parse(COORDINATOR_HOST))
3022                         .build();
3023 
3024         GetAdSelectionDataTestCallback callback = invokeGetAdSelectionData(service, input);
3025         long adSelectionId = callback.mGetAdSelectionDataResponse.getAdSelectionId();
3026 
3027         // assert that we can decrypt server's response as well even when using non-default
3028         // coordinator
3029         byte[] encryptedServerResponse =
3030                 ObliviousHttpGateway.encrypt(
3031                         privKey,
3032                         callback.mGetAdSelectionDataResponse.getAdSelectionData(),
3033                         prepareAuctionResultBytes());
3034         PersistAdSelectionResultInput persistAdSelectionResultInput =
3035                 new PersistAdSelectionResultInput.Builder()
3036                         .setAdSelectionId(adSelectionId)
3037                         .setSeller(SELLER)
3038                         .setAdSelectionResult(encryptedServerResponse)
3039                         .setCallerPackageName(CALLER_PACKAGE_NAME)
3040                         .build();
3041         invokePersistAdSelectionResult(service, persistAdSelectionResultInput);
3042         StringWriter stringWriter = new StringWriter();
3043         PrintWriter out = new PrintWriter(stringWriter);
3044         PrintWriter err =
3045                 new PrintWriter(new OutputStreamWriter(System.err, StandardCharsets.UTF_8));
3046         ViewAuctionResultCommand command = new ViewAuctionResultCommand(mAdSelectionEntryDao);
3047         ShellCommandResult result =
3048                 command.run(
3049                         out,
3050                         err,
3051                         new String[] {
3052                             AdSelectionShellCommandFactory.COMMAND_PREFIX,
3053                             ViewAuctionResultCommand.CMD,
3054                             "--ad-selection-id",
3055                             Long.toString(adSelectionId)
3056                         });
3057         AuctionResult auctionResult =
3058                 AuctionResult.parseFrom(
3059                         Base64.decode(
3060                                 new JSONObject(stringWriter.toString()).getString("output_proto"),
3061                                 Base64.DEFAULT));
3062         Assert.assertEquals(WINNER_AD_RENDER_URI, Uri.parse(auctionResult.getAdRenderUrl()));
3063     }
3064 
3065     @Test
testPersistAdselectionResult_withCompleteAuction_success()3066     public void testPersistAdselectionResult_withCompleteAuction_success() throws Exception {
3067 
3068         AdServicesHttpClientResponse httpClientResponse =
3069                 mServerAuctionTestHelper.getPublicAuctionKeyHttpResponse();
3070         when(mMockHttpClient.fetchPayloadWithLogging(
3071                         eq(Uri.parse(COORDINATOR_URL)),
3072                         eq(DevContext.createForDevOptionsDisabled()),
3073                         any(FetchProcessLogger.class)))
3074                 .thenReturn(Futures.immediateFuture(httpClientResponse));
3075 
3076         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
3077                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
3078                                 WINNER_BUYER,
3079                                 WINNING_CUSTOM_AUDIENCE_NAME,
3080                                 WINNING_CUSTOM_AUDIENCE_OWNER)
3081                         .setAds(
3082                                 DBAdDataFixture.getValidDbAdDataListByBuyerWithAdRenderId(
3083                                         WINNER_BUYER))
3084                         .build(),
3085                 Uri.EMPTY,
3086                 false,
3087                 List.of());
3088 
3089         AdSelectionService service = createServiceWithMockHttpClient();
3090 
3091         GetAdSelectionDataInput input =
3092                 new GetAdSelectionDataInput.Builder()
3093                         .setSeller(SELLER)
3094                         .setCallerPackageName(CALLER_PACKAGE_NAME)
3095                         .setCoordinatorOriginUri(Uri.parse(COORDINATOR_HOST))
3096                         .build();
3097 
3098         GetAdSelectionDataTestCallback callback = invokeGetAdSelectionData(service, input);
3099 
3100         assertTrue(callback.mIsSuccess);
3101         long adSelectionId = callback.mGetAdSelectionDataResponse.getAdSelectionId();
3102         Assert.assertNotNull(
3103                 mEncryptionContextDao.getEncryptionContext(
3104                         adSelectionId, ENCRYPTION_KEY_TYPE_AUCTION));
3105 
3106         ProtectedAuctionInput protectedAuctionInput =
3107                 mServerAuctionTestHelper.decryptAdSelectionData(
3108                         callback.mGetAdSelectionDataResponse.getAdSelectionData());
3109 
3110         Map<String, BuyerInput> buyerInputs =
3111                 mServerAuctionTestHelper.getDecompressedBuyerInputs(protectedAuctionInput);
3112 
3113         Assert.assertEquals(CALLER_PACKAGE_NAME, protectedAuctionInput.getPublisherName());
3114         Assert.assertEquals(1, buyerInputs.size());
3115         assertTrue(buyerInputs.containsKey(WINNER_BUYER.toString()));
3116         Assert.assertEquals(
3117                 1, buyerInputs.get(WINNER_BUYER.toString()).getCustomAudiencesList().size());
3118         Assert.assertEquals(
3119                 WINNING_CUSTOM_AUDIENCE_NAME,
3120                 buyerInputs.get(WINNER_BUYER.toString()).getCustomAudiences(0).getName());
3121 
3122         // assert that we can decrypt server's response as well even when using non-default
3123         // coordinator
3124         byte[] encryptedServerResponse =
3125                 mServerAuctionTestHelper.encryptServerAuctionResult(
3126                         callback.mGetAdSelectionDataResponse, AUCTION_RESULT);
3127         PersistAdSelectionResultInput persistAdSelectionResultInput =
3128                 new PersistAdSelectionResultInput.Builder()
3129                         .setAdSelectionId(adSelectionId)
3130                         .setSeller(SELLER)
3131                         .setAdSelectionResult(encryptedServerResponse)
3132                         .setCallerPackageName(CALLER_PACKAGE_NAME)
3133                         .build();
3134         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
3135                 invokePersistAdSelectionResult(service, persistAdSelectionResultInput);
3136 
3137         assertTrue(persistAdSelectionResultTestCallback.mIsSuccess);
3138         Assert.assertEquals(
3139                 adSelectionId,
3140                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
3141                         .getAdSelectionId());
3142         Assert.assertEquals(
3143                 WINNER_AD_RENDER_URI,
3144                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
3145                         .getAdRenderUri());
3146         ReportingData reportingData =
3147                 mAdSelectionEntryDao.getReportingDataForId(adSelectionId, false);
3148         Assert.assertEquals(
3149                 BUYER_REPORTING_URI, reportingData.getBuyerWinReportingUri().toString());
3150         Assert.assertEquals(
3151                 SELLER_REPORTING_URI, reportingData.getSellerWinReportingUri().toString());
3152     }
3153 
3154     @Test
3155     @SetFlagTrue(KEY_FLEDGE_AUCTION_SERVER_REFRESH_EXPIRED_KEYS_DURING_AUCTION)
testGetAdSelectionData_refreshFlagOn_fetchesNewKey()3156     public void testGetAdSelectionData_refreshFlagOn_fetchesNewKey() throws Exception {
3157         String liveKeyId = "400bed24-c62f-46e0-a1ad-211361ad771a";
3158         String privateKeyHex = "e7b292f49df28b8065992cdeadbc9d032a0e09e8476cb6d8d507212e7be3b9b4";
3159         OhttpGatewayPrivateKey privKey =
3160                 OhttpGatewayPrivateKey.create(
3161                         BaseEncoding.base16().lowerCase().decode(privateKeyHex));
3162         AuctionEncryptionKeyFixture.AuctionKey auctionKey =
3163                 AuctionEncryptionKeyFixture.AuctionKey.builder()
3164                         .setKeyId(liveKeyId)
3165                         .setPublicKey("87ey8XZPXAd+/+ytKv2GFUWW5j9zdepSJ2G4gebDwyM=")
3166                         .build();
3167 
3168         AdServicesHttpClientResponse httpClientResponse =
3169                 AuctionEncryptionKeyFixture.mockAuctionKeyFetchResponseWithGivenKey(auctionKey);
3170         when(mMockHttpClient.fetchPayloadWithLogging(
3171                         eq(Uri.parse(COORDINATOR_URL)),
3172                         eq(DevContext.createForDevOptionsDisabled()),
3173                         any(FetchProcessLogger.class)))
3174                 .thenReturn(Futures.immediateFuture(httpClientResponse));
3175 
3176         String expiredKeyId = "000bed24-c62f-46e0-a1ad-211361ad771a";
3177         DBProtectedServersEncryptionConfig dbEncryptionKey =
3178                 DBProtectedServersEncryptionConfig.builder()
3179                         .setPublicKey("87ey8XZPXAd+/+ytKv2GFUWW5j9zdepSJ2G4gebDwyM=")
3180                         .setKeyIdentifier(expiredKeyId)
3181                         .setCoordinatorUrl(COORDINATOR_URL)
3182                         .setEncryptionKeyType(ENCRYPTION_KEY_TYPE_AUCTION)
3183                         .setExpiryTtlSeconds(-1L)
3184                         .build();
3185         mProtectedServersEncryptionConfigDao.insertKeys(ImmutableList.of(dbEncryptionKey));
3186 
3187         List<DBProtectedServersEncryptionConfig> protectedServersEncryptionConfigs =
3188                 mProtectedServersEncryptionConfigDao.getLatestExpiryNKeys(
3189                         AdSelectionEncryptionKey.AdSelectionEncryptionKeyType.AUCTION,
3190                         COORDINATOR_URL,
3191                         100);
3192         Assert.assertEquals(1, protectedServersEncryptionConfigs.size());
3193         Assert.assertEquals(
3194                 expiredKeyId, protectedServersEncryptionConfigs.get(0).getKeyIdentifier());
3195 
3196         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
3197                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
3198                                 WINNER_BUYER,
3199                                 WINNING_CUSTOM_AUDIENCE_NAME,
3200                                 WINNING_CUSTOM_AUDIENCE_OWNER)
3201                         .setAds(
3202                                 DBAdDataFixture.getValidDbAdDataListByBuyerWithAdRenderId(
3203                                         WINNER_BUYER))
3204                         .build(),
3205                 Uri.EMPTY,
3206                 false,
3207                 List.of());
3208 
3209         AdSelectionService service = createServiceWithMockHttpClient();
3210 
3211         GetAdSelectionDataInput input =
3212                 new GetAdSelectionDataInput.Builder()
3213                         .setSeller(SELLER)
3214                         .setCallerPackageName(CALLER_PACKAGE_NAME)
3215                         .setCoordinatorOriginUri(Uri.parse(COORDINATOR_HOST))
3216                         .build();
3217 
3218         GetAdSelectionDataTestCallback callback = invokeGetAdSelectionData(service, input);
3219 
3220         Assert.assertTrue(callback.mIsSuccess);
3221 
3222         protectedServersEncryptionConfigs =
3223                 mProtectedServersEncryptionConfigDao.getLatestExpiryNKeys(
3224                         AdSelectionEncryptionKey.AdSelectionEncryptionKeyType.AUCTION,
3225                         COORDINATOR_URL,
3226                         100);
3227 
3228         // assert that the DB now contains the new keys when refresh keys flag is off
3229         Assert.assertEquals(1, protectedServersEncryptionConfigs.size());
3230         Assert.assertEquals(liveKeyId, protectedServersEncryptionConfigs.get(0).getKeyIdentifier());
3231         verify(mMockHttpClient)
3232                 .fetchPayloadWithLogging(
3233                         eq(Uri.parse(COORDINATOR_URL)),
3234                         eq(DevContext.createForDevOptionsDisabled()),
3235                         any(FetchProcessLogger.class));
3236 
3237         long adSelectionId = callback.mGetAdSelectionDataResponse.getAdSelectionId();
3238 
3239         // assert that we can decrypt server's response as well even when using non-default
3240         // coordinator
3241         byte[] encryptedServerResponse =
3242                 ObliviousHttpGateway.encrypt(
3243                         privKey,
3244                         callback.mGetAdSelectionDataResponse.getAdSelectionData(),
3245                         prepareAuctionResultBytes());
3246         PersistAdSelectionResultInput persistAdSelectionResultInput =
3247                 new PersistAdSelectionResultInput.Builder()
3248                         .setAdSelectionId(adSelectionId)
3249                         .setSeller(SELLER)
3250                         .setAdSelectionResult(encryptedServerResponse)
3251                         .setCallerPackageName(CALLER_PACKAGE_NAME)
3252                         .build();
3253         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
3254                 invokePersistAdSelectionResult(service, persistAdSelectionResultInput);
3255 
3256         Assert.assertTrue(persistAdSelectionResultTestCallback.mIsSuccess);
3257         Assert.assertEquals(
3258                 adSelectionId,
3259                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
3260                         .getAdSelectionId());
3261         Assert.assertEquals(
3262                 WINNER_AD_RENDER_URI,
3263                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
3264                         .getAdRenderUri());
3265     }
3266 
3267     @Test
testGetAdSelectionData_refreshFlagOff_noNetworkCall()3268     public void testGetAdSelectionData_refreshFlagOff_noNetworkCall() throws Exception {
3269         String liveKeyId = "400bed24-c62f-46e0-a1ad-211361ad771a";
3270         String privateKeyHex = "e7b292f49df28b8065992cdeadbc9d032a0e09e8476cb6d8d507212e7be3b9b4";
3271         OhttpGatewayPrivateKey privKey =
3272                 OhttpGatewayPrivateKey.create(
3273                         BaseEncoding.base16().lowerCase().decode(privateKeyHex));
3274         AuctionEncryptionKeyFixture.AuctionKey auctionKey =
3275                 AuctionEncryptionKeyFixture.AuctionKey.builder()
3276                         .setKeyId(liveKeyId)
3277                         .setPublicKey("87ey8XZPXAd+/+ytKv2GFUWW5j9zdepSJ2G4gebDwyM=")
3278                         .build();
3279 
3280         AdServicesHttpClientResponse httpClientResponse =
3281                 AuctionEncryptionKeyFixture.mockAuctionKeyFetchResponseWithGivenKey(auctionKey);
3282         when(mMockHttpClient.fetchPayloadWithLogging(
3283                         eq(Uri.parse(COORDINATOR_URL)),
3284                         eq(DevContext.createForDevOptionsDisabled()),
3285                         any(FetchProcessLogger.class)))
3286                 .thenReturn(Futures.immediateFuture(httpClientResponse));
3287 
3288         String expiredKeyId = "000bed24-c62f-46e0-a1ad-211361ad771a";
3289         DBProtectedServersEncryptionConfig dbEncryptionKey =
3290                 DBProtectedServersEncryptionConfig.builder()
3291                         .setPublicKey("87ey8XZPXAd+/+ytKv2GFUWW5j9zdepSJ2G4gebDwyM=")
3292                         .setKeyIdentifier(expiredKeyId)
3293                         .setCoordinatorUrl(COORDINATOR_URL)
3294                         .setEncryptionKeyType(ENCRYPTION_KEY_TYPE_AUCTION)
3295                         .setExpiryTtlSeconds(-1L)
3296                         .build();
3297         mProtectedServersEncryptionConfigDao.insertKeys(ImmutableList.of(dbEncryptionKey));
3298 
3299         List<DBProtectedServersEncryptionConfig> protectedServersEncryptionConfigs =
3300                 mProtectedServersEncryptionConfigDao.getLatestExpiryNKeys(
3301                         AdSelectionEncryptionKey.AdSelectionEncryptionKeyType.AUCTION,
3302                         COORDINATOR_URL,
3303                         100);
3304         Assert.assertEquals(1, protectedServersEncryptionConfigs.size());
3305         Assert.assertEquals(
3306                 expiredKeyId, protectedServersEncryptionConfigs.get(0).getKeyIdentifier());
3307         verify(mMockHttpClient, never())
3308                 .fetchPayloadWithLogging(
3309                         eq(Uri.parse(COORDINATOR_URL)),
3310                         eq(DevContext.createForDevOptionsDisabled()),
3311                         any(FetchProcessLogger.class));
3312 
3313         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
3314                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
3315                                 WINNER_BUYER,
3316                                 WINNING_CUSTOM_AUDIENCE_NAME,
3317                                 WINNING_CUSTOM_AUDIENCE_OWNER)
3318                         .setAds(
3319                                 DBAdDataFixture.getValidDbAdDataListByBuyerWithAdRenderId(
3320                                         WINNER_BUYER))
3321                         .build(),
3322                 Uri.EMPTY,
3323                 false,
3324                 List.of());
3325 
3326         AdSelectionService service = createServiceWithMockHttpClient();
3327 
3328         GetAdSelectionDataInput input =
3329                 new GetAdSelectionDataInput.Builder()
3330                         .setSeller(SELLER)
3331                         .setCallerPackageName(CALLER_PACKAGE_NAME)
3332                         .setCoordinatorOriginUri(Uri.parse(COORDINATOR_HOST))
3333                         .build();
3334 
3335         GetAdSelectionDataTestCallback callback = invokeGetAdSelectionData(service, input);
3336 
3337         Assert.assertTrue(callback.mIsSuccess);
3338 
3339         protectedServersEncryptionConfigs =
3340                 mProtectedServersEncryptionConfigDao.getLatestExpiryNKeys(
3341                         AdSelectionEncryptionKey.AdSelectionEncryptionKeyType.AUCTION,
3342                         COORDINATOR_URL,
3343                         100);
3344 
3345         // assert that the DB still contains the expired keys when refresh keys flag is off
3346         Assert.assertEquals(1, protectedServersEncryptionConfigs.size());
3347         Assert.assertEquals(
3348                 expiredKeyId, protectedServersEncryptionConfigs.get(0).getKeyIdentifier());
3349 
3350         long adSelectionId = callback.mGetAdSelectionDataResponse.getAdSelectionId();
3351 
3352         // assert that we can decrypt server's response as well even when using non-default
3353         // coordinator
3354         byte[] encryptedServerResponse =
3355                 ObliviousHttpGateway.encrypt(
3356                         privKey,
3357                         callback.mGetAdSelectionDataResponse.getAdSelectionData(),
3358                         prepareAuctionResultBytes());
3359         PersistAdSelectionResultInput persistAdSelectionResultInput =
3360                 new PersistAdSelectionResultInput.Builder()
3361                         .setAdSelectionId(adSelectionId)
3362                         .setSeller(SELLER)
3363                         .setAdSelectionResult(encryptedServerResponse)
3364                         .setCallerPackageName(CALLER_PACKAGE_NAME)
3365                         .build();
3366         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
3367                 invokePersistAdSelectionResult(service, persistAdSelectionResultInput);
3368 
3369         Assert.assertEquals(
3370                 WINNER_AD_RENDER_URI,
3371                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
3372                         .getAdRenderUri());
3373     }
3374 
3375     @Test
testGetAdSelectionData_nullCoordinator_success()3376     public void testGetAdSelectionData_nullCoordinator_success() throws Exception {
3377         AuctionEncryptionKeyFixture.AuctionKey auctionKey =
3378                 AuctionEncryptionKeyFixture.AuctionKey.builder()
3379                         .setKeyId("400bed24-c62f-46e0-a1ad-211361ad771a")
3380                         .setPublicKey("87ey8XZPXAd+/+ytKv2GFUWW5j9zdepSJ2G4gebDwyM=")
3381                         .build();
3382 
3383         AdServicesHttpClientResponse httpClientResponse =
3384                 AuctionEncryptionKeyFixture.mockAuctionKeyFetchResponseWithGivenKey(auctionKey);
3385         when(mMockHttpClient.fetchPayloadWithLogging(
3386                         eq(Uri.parse(DEFAULT_FETCH_URI)),
3387                         eq(DevContext.createForDevOptionsDisabled()),
3388                         any(FetchProcessLogger.class)))
3389                 .thenReturn(Futures.immediateFuture(httpClientResponse));
3390 
3391         Map<String, AdTechIdentifier> nameAndBuyersMap =
3392                 Map.of(
3393                         "Shoes CA of Buyer 1", WINNER_BUYER,
3394                         "Shirts CA of Buyer 1", WINNER_BUYER,
3395                         "Shoes CA Of Buyer 2", DIFFERENT_BUYER);
3396         createAndPersistDBCustomAudiences(nameAndBuyersMap);
3397 
3398         AdSelectionService service = createServiceWithMockHttpClient();
3399 
3400         GetAdSelectionDataInput input =
3401                 new GetAdSelectionDataInput.Builder()
3402                         .setSeller(SELLER)
3403                         .setCallerPackageName(CALLER_PACKAGE_NAME)
3404                         .build();
3405 
3406         GetAdSelectionDataTestCallback callback = invokeGetAdSelectionData(service, input);
3407 
3408         assertTrue(callback.mIsSuccess);
3409         Assert.assertNotNull(callback.mGetAdSelectionDataResponse);
3410         Assert.assertNotNull(callback.mGetAdSelectionDataResponse.getAdSelectionData());
3411         long adSelectionId = callback.mGetAdSelectionDataResponse.getAdSelectionId();
3412         byte[] encryptedBytes = callback.mGetAdSelectionDataResponse.getAdSelectionData();
3413         Assert.assertNotNull(encryptedBytes);
3414         Assert.assertNotNull(
3415                 mEncryptionContextDao.getEncryptionContext(
3416                         adSelectionId, ENCRYPTION_KEY_TYPE_AUCTION));
3417     }
3418 
3419     @Test
3420     @ExpectErrorLogUtilCall(
3421             errorCode =
3422                     AD_SERVICES_ERROR_REPORTED__ERROR_CODE__GET_AD_SELECTION_DATA_RUNNER_NOTIFY_FAILURE_INVALID_ARGUMENT,
3423             ppapiName = AD_SERVICES_ERROR_REPORTED__PPAPI_NAME__GET_AD_SELECTION_DATA)
testGetAdSelectionData_invalidCoordinator_fails()3424     public void testGetAdSelectionData_invalidCoordinator_fails() throws Exception {
3425         AuctionEncryptionKeyFixture.AuctionKey auctionKey =
3426                 AuctionEncryptionKeyFixture.AuctionKey.builder()
3427                         .setKeyId("400bed24-c62f-46e0-a1ad-211361ad771a")
3428                         .setPublicKey("87ey8XZPXAd+/+ytKv2GFUWW5j9zdepSJ2G4gebDwyM=")
3429                         .build();
3430 
3431         AdServicesHttpClientResponse httpClientResponse =
3432                 AuctionEncryptionKeyFixture.mockAuctionKeyFetchResponseWithGivenKey(auctionKey);
3433         when(mMockHttpClient.fetchPayloadWithLogging(
3434                         eq(Uri.parse(COORDINATOR_URL)),
3435                         eq(DevContext.createForDevOptionsDisabled()),
3436                         any(FetchProcessLogger.class)))
3437                 .thenReturn(Futures.immediateFuture(httpClientResponse));
3438 
3439         Map<String, AdTechIdentifier> nameAndBuyersMap =
3440                 Map.of(
3441                         "Shoes CA of Buyer 1", WINNER_BUYER,
3442                         "Shirts CA of Buyer 1", WINNER_BUYER,
3443                         "Shoes CA Of Buyer 2", DIFFERENT_BUYER);
3444         createAndPersistDBCustomAudiences(nameAndBuyersMap);
3445 
3446         AdSelectionService service = createServiceWithMockHttpClient();
3447 
3448         GetAdSelectionDataInput input =
3449                 new GetAdSelectionDataInput.Builder()
3450                         .setSeller(SELLER)
3451                         .setCallerPackageName(CALLER_PACKAGE_NAME)
3452                         .setCoordinatorOriginUri(Uri.parse("a/b"))
3453                         .build();
3454 
3455         GetAdSelectionDataTestCallback callback = invokeGetAdSelectionData(service, input);
3456 
3457         Assert.assertFalse(callback.mIsSuccess);
3458         Assert.assertEquals(STATUS_INVALID_ARGUMENT, callback.mFledgeErrorResponse.getStatusCode());
3459     }
3460 
3461     @Test
testGetAdSelectionData_withoutEncrypt_protectedSignals_success()3462     public void testGetAdSelectionData_withoutEncrypt_protectedSignals_success() throws Exception {
3463         byte[] encodedSignals = new byte[] {2, 3, 5, 7, 11, 13, 17, 19};
3464         createAndPersistEncodedSignals(WINNER_BUYER, encodedSignals);
3465 
3466         when(mObliviousHttpEncryptorMock.encryptBytes(
3467                         any(byte[].class), anyLong(), anyLong(), any(), any()))
3468                 .thenAnswer(
3469                         invocation ->
3470                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
3471 
3472         GetAdSelectionDataInput input =
3473                 new GetAdSelectionDataInput.Builder()
3474                         .setSeller(SELLER)
3475                         .setCallerPackageName(CALLER_PACKAGE_NAME)
3476                         .build();
3477 
3478         GetAdSelectionDataTestCallback callback =
3479                 invokeGetAdSelectionData(mAdSelectionService, input);
3480 
3481         assertTrue(callback.mIsSuccess);
3482         Assert.assertNotNull(callback.mGetAdSelectionDataResponse);
3483         Assert.assertNotNull(callback.mGetAdSelectionDataResponse.getAdSelectionData());
3484 
3485         byte[] encryptedBytes = callback.mGetAdSelectionDataResponse.getAdSelectionData();
3486         // Since encryption is mocked to do nothing then just passing encrypted byte[]
3487         Map<AdTechIdentifier, BuyerInput> buyerInputMap =
3488                 getBuyerInputMapFromDecryptedBytes(encryptedBytes);
3489         Assert.assertEquals(1, buyerInputMap.keySet().size());
3490         Assert.assertTrue(buyerInputMap.keySet().contains(WINNER_BUYER));
3491         BuyerInput buyerInput = buyerInputMap.get(WINNER_BUYER);
3492         ProtectedAppSignals protectedAppSignals = buyerInput.getProtectedAppSignals();
3493         Assert.assertArrayEquals(
3494                 encodedSignals, protectedAppSignals.getAppInstallSignals().toByteArray());
3495     }
3496 
3497     @Test
testPersistAdSelectionResult_withoutDecrypt_validSignalsRequest_success()3498     public void testPersistAdSelectionResult_withoutDecrypt_validSignalsRequest_success()
3499             throws Exception {
3500         when(mObliviousHttpEncryptorMock.encryptBytes(
3501                         any(byte[].class), anyLong(), anyLong(), any(), any()))
3502                 .thenAnswer(
3503                         invocation ->
3504                                 FluentFuture.from(immediateFuture(invocation.getArgument(0))));
3505         when(mObliviousHttpEncryptorMock.decryptBytes(any(byte[].class), anyLong()))
3506                 .thenAnswer(invocation -> invocation.getArgument(0));
3507 
3508         byte[] encodedSignals = new byte[] {2, 3, 5, 7, 11, 13, 17, 19};
3509         createAndPersistEncodedSignals(WINNER_BUYER, encodedSignals);
3510 
3511         GetAdSelectionDataInput input =
3512                 new GetAdSelectionDataInput.Builder()
3513                         .setSeller(SELLER)
3514                         .setCallerPackageName(CALLER_PACKAGE_NAME)
3515                         .build();
3516 
3517         GetAdSelectionDataTestCallback getAdSelectionDataTestCallback =
3518                 invokeGetAdSelectionData(mAdSelectionService, input);
3519         long adSelectionId =
3520                 getAdSelectionDataTestCallback.mGetAdSelectionDataResponse.getAdSelectionId();
3521 
3522         PersistAdSelectionResultInput persistAdSelectionResultInput =
3523                 new PersistAdSelectionResultInput.Builder()
3524                         .setAdSelectionId(adSelectionId)
3525                         .setSeller(SELLER)
3526                         .setAdSelectionResult(prepareAuctionResultBytesPas())
3527                         .setCallerPackageName(CALLER_PACKAGE_NAME)
3528                         .build();
3529 
3530         PersistAdSelectionResultTestCallback persistAdSelectionResultTestCallback =
3531                 invokePersistAdSelectionResult(mAdSelectionService, persistAdSelectionResultInput);
3532 
3533         assertTrue(persistAdSelectionResultTestCallback.mIsSuccess);
3534         Assert.assertEquals(
3535                 WINNER_AD_RENDER_URI,
3536                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
3537                         .getAdRenderUri());
3538         Assert.assertEquals(
3539                 adSelectionId,
3540                 persistAdSelectionResultTestCallback.mPersistAdSelectionResultResponse
3541                         .getAdSelectionId());
3542         ReportingData reportingData =
3543                 mAdSelectionEntryDao.getReportingDataForId(adSelectionId, false);
3544         Assert.assertEquals(
3545                 BUYER_REPORTING_URI, reportingData.getBuyerWinReportingUri().toString());
3546         Assert.assertEquals(
3547                 SELLER_REPORTING_URI, reportingData.getSellerWinReportingUri().toString());
3548     }
3549 
3550     @Test
testGetAdSelectionData_withTestCoordinatorUriStrategy_uriNotInAllowlist_success()3551     public void testGetAdSelectionData_withTestCoordinatorUriStrategy_uriNotInAllowlist_success()
3552             throws Exception {
3553         Uri invalidCoordinator = Uri.parse("ex.com/testKeys");
3554 
3555         AdServicesHttpClientResponse httpClientResponse =
3556                 mServerAuctionTestHelper.getPublicAuctionKeyHttpResponse();
3557 
3558         when(mMockHttpClient.fetchPayloadWithLogging(
3559                         eq(invalidCoordinator), eq(mDevContextMock), any(FetchProcessLogger.class)))
3560                 .thenReturn(Futures.immediateFuture(httpClientResponse));
3561 
3562         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
3563                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
3564                                 WINNER_BUYER,
3565                                 WINNING_CUSTOM_AUDIENCE_NAME,
3566                                 WINNING_CUSTOM_AUDIENCE_OWNER)
3567                         .setAds(
3568                                 DBAdDataFixture.getValidDbAdDataListByBuyerWithAdRenderId(
3569                                         WINNER_BUYER))
3570                         .build(),
3571                 Uri.EMPTY,
3572                 false,
3573                 List.of());
3574 
3575         DevSession devSession =
3576                 DevSession.builder()
3577                         .setState(DevSessionState.IN_DEV)
3578                         .setServerAuctionTestKeysEnabled(true)
3579                         .build();
3580 
3581         when(mDevContextFilterMock.createDevContext()).thenReturn(mDevContextMock);
3582         when(mDevContextMock.getDevSession()).thenReturn(devSession);
3583 
3584         AdSelectionService service = createServiceWithMockHttpClient();
3585 
3586         GetAdSelectionDataInput input =
3587                 new GetAdSelectionDataInput.Builder()
3588                         .setSeller(SELLER)
3589                         .setCallerPackageName(CALLER_PACKAGE_NAME)
3590                         .setCoordinatorOriginUri(invalidCoordinator)
3591                         .build();
3592 
3593         GetAdSelectionDataTestCallback callback = invokeGetAdSelectionData(service, input);
3594 
3595         verify(mMockHttpClient)
3596                 .fetchPayloadWithLogging(
3597                         eq(invalidCoordinator), eq(mDevContextMock), any(FetchProcessLogger.class));
3598 
3599         assertThat(callback.mIsSuccess).isTrue();
3600         assertThat(callback.mGetAdSelectionDataResponse).isNotNull();
3601         assertThat(callback.mGetAdSelectionDataResponse.getAdSelectionData()).isNotNull();
3602 
3603         long adSelectionId = callback.mGetAdSelectionDataResponse.getAdSelectionId();
3604         assertThat(
3605                         mEncryptionContextDao.getEncryptionContext(
3606                                 adSelectionId, ENCRYPTION_KEY_TYPE_AUCTION))
3607                 .isNotNull();
3608 
3609         ProtectedAuctionInput protectedAuctionInput =
3610                 mServerAuctionTestHelper.decryptAdSelectionData(
3611                         callback.mGetAdSelectionDataResponse.getAdSelectionData());
3612 
3613         Map<String, BuyerInput> buyerInputs =
3614                 mServerAuctionTestHelper.getDecompressedBuyerInputs(protectedAuctionInput);
3615 
3616         Assert.assertEquals(CALLER_PACKAGE_NAME, protectedAuctionInput.getPublisherName());
3617         Assert.assertEquals(1, buyerInputs.size());
3618         assertTrue(buyerInputs.containsKey(WINNER_BUYER.toString()));
3619         Assert.assertEquals(
3620                 1, buyerInputs.get(WINNER_BUYER.toString()).getCustomAudiencesList().size());
3621         Assert.assertEquals(
3622                 WINNING_CUSTOM_AUDIENCE_NAME,
3623                 buyerInputs.get(WINNER_BUYER.toString()).getCustomAudiences(0).getName());
3624     }
3625 
createServiceWithMockHttpClient()3626     private AdSelectionServiceImpl createServiceWithMockHttpClient() {
3627         return new AdSelectionServiceImpl(
3628                 mAdSelectionEntryDao,
3629                 mAppInstallDao,
3630                 mCustomAudienceDaoSpy,
3631                 mEncodedPayloadDaoSpy,
3632                 mFrequencyCapDaoSpy,
3633                 mEncryptionKeyDao,
3634                 mEnrollmentDao,
3635                 mAdServicesHttpsClientSpy,
3636                 mDevContextFilterMock,
3637                 mLightweightExecutorService,
3638                 mBackgroundExecutorService,
3639                 mScheduledExecutor,
3640                 mContext,
3641                 mAdServicesLoggerMock,
3642                 mFakeFlags,
3643                 mFakeDebugFlags,
3644                 CallingAppUidSupplierProcessImpl.create(),
3645                 mFledgeAuthorizationFilterMock,
3646                 mAdSelectionServiceFilterMock,
3647                 mAdFilteringFeatureFactory,
3648                 mConsentManagerMock,
3649                 new ObliviousHttpEncryptorImpl(
3650                         new ProtectedServersEncryptionConfigManager(
3651                                 mProtectedServersEncryptionConfigDao,
3652                                 mFakeFlags,
3653                                 mMockHttpClient,
3654                                 mLightweightExecutorService,
3655                                 mAdServicesLoggerMock,
3656                                 mServerAuctionCoordinatorUriStrategyFactory),
3657                         mEncryptionContextDao,
3658                         mLightweightExecutorService),
3659                 mAdSelectionDebugReportDaoSpy,
3660                 mAdIdFetcher,
3661                 mUnusedKAnonSignJoinFactory,
3662                 false,
3663                 mRetryStrategyFactory,
3664                 CONSOLE_MESSAGE_IN_LOGS_ENABLED,
3665                 mAuctionServerDebugConfigurationGenerator,
3666                 mServerAuctionCoordinatorUriStrategyFactory);
3667     }
3668 
setAppInstallAdvertisers( Set<AdTechIdentifier> advertisers, AdSelectionService adSelectionService)3669     private void setAppInstallAdvertisers(
3670             Set<AdTechIdentifier> advertisers, AdSelectionService adSelectionService)
3671             throws RemoteException, InterruptedException {
3672         SetAppInstallAdvertisersInput setAppInstallAdvertisersInput =
3673                 new SetAppInstallAdvertisersInput.Builder()
3674                         .setAdvertisers(advertisers)
3675                         .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME)
3676                         .build();
3677         AppInstallResultCapturingCallback appInstallCallback =
3678                 invokeSetAppInstallAdvertisers(setAppInstallAdvertisersInput, adSelectionService);
3679         assertTrue(
3680                 "App Install call failed with: " + appInstallCallback.getException(),
3681                 appInstallCallback.isSuccess());
3682     }
3683 
invokeSetAppInstallAdvertisers( SetAppInstallAdvertisersInput input, AdSelectionService adSelectionService)3684     private AppInstallResultCapturingCallback invokeSetAppInstallAdvertisers(
3685             SetAppInstallAdvertisersInput input, AdSelectionService adSelectionService)
3686             throws RemoteException, InterruptedException {
3687         CountDownLatch appInstallDone = new CountDownLatch(1);
3688         AppInstallResultCapturingCallback appInstallCallback =
3689                 new AppInstallResultCapturingCallback(appInstallDone);
3690         adSelectionService.setAppInstallAdvertisers(input, appInstallCallback);
3691         assertTrue(appInstallDone.await(5, TimeUnit.SECONDS));
3692         return appInstallCallback;
3693     }
3694 
prepareDataAndRunServerAuction()3695     private void prepareDataAndRunServerAuction() throws Exception {
3696         AdServicesHttpClientResponse httpClientResponse =
3697                 mServerAuctionTestHelper.getPublicAuctionKeyHttpResponse();
3698 
3699         when(mMockHttpClient.fetchPayloadWithLogging(
3700                         eq(Uri.parse(COORDINATOR_URL)),
3701                         eq(DevContext.createForDevOptionsDisabled()),
3702                         any(FetchProcessLogger.class)))
3703                 .thenReturn(Futures.immediateFuture(httpClientResponse));
3704 
3705         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
3706                 DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
3707                                 WINNER_BUYER,
3708                                 WINNING_CUSTOM_AUDIENCE_NAME,
3709                                 WINNING_CUSTOM_AUDIENCE_OWNER)
3710                         .setAds(
3711                                 DBAdDataFixture.getValidDbAdDataListByBuyerWithAdRenderId(
3712                                         WINNER_BUYER))
3713                         .build(),
3714                 Uri.EMPTY,
3715                 false,
3716                 List.of());
3717 
3718         mAdSelectionService = createServiceWithMockHttpClient();
3719 
3720         GetAdSelectionDataInput input =
3721                 new GetAdSelectionDataInput.Builder()
3722                         .setSeller(SELLER)
3723                         .setCallerPackageName(CALLER_PACKAGE_NAME)
3724                         .setCoordinatorOriginUri(Uri.parse(COORDINATOR_HOST))
3725                         .build();
3726 
3727         GetAdSelectionDataTestCallback callback =
3728                 invokeGetAdSelectionData(mAdSelectionService, input);
3729 
3730         assertTrue(callback.mIsSuccess);
3731         Assert.assertNotNull(callback.mGetAdSelectionDataResponse);
3732         Assert.assertNotNull(callback.mGetAdSelectionDataResponse.getAdSelectionData());
3733         long adSelectionId = callback.mGetAdSelectionDataResponse.getAdSelectionId();
3734         byte[] encryptedBytes = callback.mGetAdSelectionDataResponse.getAdSelectionData();
3735         Assert.assertNotNull(encryptedBytes);
3736         Assert.assertNotNull(
3737                 mEncryptionContextDao.getEncryptionContext(
3738                         adSelectionId, ENCRYPTION_KEY_TYPE_AUCTION));
3739     }
3740 
3741     /**
3742      * Asserts if a {@link BuyerInput.CustomAudience} and {@link DBCustomAudience} objects are
3743      * equal.
3744      */
assertCasEquals( BuyerInput.CustomAudience buyerInputCA, DBCustomAudience dbCustomAudience)3745     private void assertCasEquals(
3746             BuyerInput.CustomAudience buyerInputCA, DBCustomAudience dbCustomAudience) {
3747         Assert.assertEquals(buyerInputCA.getName(), dbCustomAudience.getName());
3748         Assert.assertNotNull(dbCustomAudience.getTrustedBiddingData());
3749         Assert.assertEquals(
3750                 buyerInputCA.getBiddingSignalsKeysList(),
3751                 dbCustomAudience.getTrustedBiddingData().getKeys());
3752         Assert.assertNotNull(dbCustomAudience.getUserBiddingSignals());
3753         Assert.assertEquals(
3754                 buyerInputCA.getUserBiddingSignals(),
3755                 dbCustomAudience.getUserBiddingSignals().toString());
3756     }
3757 
createAdSelectionService()3758     private AdSelectionService createAdSelectionService() {
3759         return new AdSelectionServiceImpl(
3760                 mAdSelectionEntryDao,
3761                 mAppInstallDao,
3762                 mCustomAudienceDaoSpy,
3763                 mEncodedPayloadDaoSpy,
3764                 mFrequencyCapDaoSpy,
3765                 mEncryptionKeyDao,
3766                 mEnrollmentDao,
3767                 mAdServicesHttpsClientSpy,
3768                 mDevContextFilterMock,
3769                 mLightweightExecutorService,
3770                 mBackgroundExecutorService,
3771                 mScheduledExecutor,
3772                 mContext,
3773                 mAdServicesLoggerMock,
3774                 mFakeFlags,
3775                 mFakeDebugFlags,
3776                 CallingAppUidSupplierProcessImpl.create(),
3777                 mFledgeAuthorizationFilterMock,
3778                 mAdSelectionServiceFilterMock,
3779                 mAdFilteringFeatureFactory,
3780                 mConsentManagerMock,
3781                 mObliviousHttpEncryptorMock,
3782                 mAdSelectionDebugReportDaoSpy,
3783                 mAdIdFetcher,
3784                 mUnusedKAnonSignJoinFactory,
3785                 false,
3786                 mRetryStrategyFactory,
3787                 CONSOLE_MESSAGE_IN_LOGS_ENABLED,
3788                 mAuctionServerDebugConfigurationGenerator,
3789                 mServerAuctionCoordinatorUriStrategyFactory);
3790     }
3791 
getBuyerInputMapFromDecryptedBytes( byte[] decryptedBytes)3792     private Map<AdTechIdentifier, BuyerInput> getBuyerInputMapFromDecryptedBytes(
3793             byte[] decryptedBytes) {
3794         try {
3795             byte[] unformatted =
3796                     mPayloadExtractor
3797                             .extract(AuctionServerPayloadFormattedData.create(decryptedBytes))
3798                             .getData();
3799             ProtectedAuctionInput protectedAuctionInput =
3800                     ProtectedAuctionInput.parseFrom(unformatted);
3801             Map<String, ByteString> buyerInputBytesMap = protectedAuctionInput.getBuyerInputMap();
3802             Function<Map.Entry<String, ByteString>, AdTechIdentifier> entryToAdTechIdentifier =
3803                     entry -> AdTechIdentifier.fromString(entry.getKey());
3804             Function<Map.Entry<String, ByteString>, BuyerInput> entryToBuyerInput =
3805                     entry -> {
3806                         try {
3807                             byte[] compressedBytes = entry.getValue().toByteArray();
3808                             byte[] decompressedBytes =
3809                                     mDataCompressor
3810                                             .decompress(
3811                                                     AuctionServerDataCompressor.CompressedData
3812                                                             .create(compressedBytes))
3813                                             .getData();
3814                             return BuyerInput.parseFrom(decompressedBytes);
3815                         } catch (InvalidProtocolBufferException e) {
3816                             throw new UncheckedIOException(e);
3817                         }
3818                     };
3819             return buyerInputBytesMap.entrySet().stream()
3820                     .collect(Collectors.toMap(entryToAdTechIdentifier, entryToBuyerInput));
3821         } catch (InvalidProtocolBufferException e) {
3822             throw new UncheckedIOException(e);
3823         }
3824     }
3825 
createAndPersistDBCustomAudiences( Map<String, AdTechIdentifier> nameAndBuyers)3826     private Map<String, DBCustomAudience> createAndPersistDBCustomAudiences(
3827             Map<String, AdTechIdentifier> nameAndBuyers) {
3828         Map<String, DBCustomAudience> customAudiences = new HashMap<>();
3829         for (Map.Entry<String, AdTechIdentifier> entry : nameAndBuyers.entrySet()) {
3830             AdTechIdentifier buyer = entry.getValue();
3831             String name = entry.getKey();
3832             DBCustomAudience thisCustomAudience =
3833                     DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(buyer, name)
3834                             .build();
3835             customAudiences.put(name, thisCustomAudience);
3836             mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
3837                     thisCustomAudience, Uri.EMPTY, false, List.of());
3838         }
3839         return customAudiences;
3840     }
3841 
createAndPersistBulkDBCustomAudiences( List<AdTechIdentifier> buyers, int numCAsForBuyer)3842     private void createAndPersistBulkDBCustomAudiences(
3843             List<AdTechIdentifier> buyers, int numCAsForBuyer) {
3844         // Generates a 20 code point string, using only the letters a-z
3845         for (AdTechIdentifier buyer : buyers) {
3846             for (int i = 0; i < numCAsForBuyer; i++) {
3847 
3848                 DBCustomAudience thisCustomAudience =
3849                         DBCustomAudienceFixture.getValidBuilderByBuyerWithAdRenderId(
3850                                         buyer, getAlphaNumericString(15))
3851                                 .build();
3852                 mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
3853                         thisCustomAudience, Uri.EMPTY, false, List.of());
3854             }
3855         }
3856     }
3857 
createAndPersistEncodedSignals( AdTechIdentifier buyer, byte[] signals)3858     private DBEncodedPayload createAndPersistEncodedSignals(
3859             AdTechIdentifier buyer, byte[] signals) {
3860         DBEncodedPayload payload =
3861                 DBEncodedPayload.builder()
3862                         .setEncodedPayload(signals)
3863                         .setCreationTime(Instant.now())
3864                         .setBuyer(buyer)
3865                         .setVersion(0)
3866                         .build();
3867         mEncodedPayloadDaoSpy.persistEncodedPayload(payload);
3868         return payload;
3869     }
3870 
createAndPersistDBCustomAudienceWithOmitAdsEnabled( String name, AdTechIdentifier buyer)3871     private DBCustomAudience createAndPersistDBCustomAudienceWithOmitAdsEnabled(
3872             String name, AdTechIdentifier buyer) {
3873         DBCustomAudience thisCustomAudience =
3874                 DBCustomAudienceFixture.getValidBuilderByBuyerWithOmitAdsEnabled(buyer, name)
3875                         .build();
3876         mCustomAudienceDaoSpy.insertOrOverwriteCustomAudience(
3877                 thisCustomAudience, Uri.EMPTY, false, List.of());
3878         return thisCustomAudience;
3879     }
3880 
prepareAuctionResultBytes()3881     private byte[] prepareAuctionResultBytes() {
3882         byte[] auctionResultBytes = AUCTION_RESULT.toByteArray();
3883         AuctionServerDataCompressor.CompressedData compressedData =
3884                 mDataCompressor.compress(
3885                         AuctionServerDataCompressor.UncompressedData.create(auctionResultBytes));
3886         AuctionServerPayloadFormattedData formattedData =
3887                 mPayloadFormatter.apply(
3888                         AuctionServerPayloadUnformattedData.create(compressedData.getData()),
3889                         AuctionServerDataCompressorGzip.VERSION);
3890         return formattedData.getData();
3891     }
3892 
prepareAuctionResultBytes(AuctionResult auctionResult)3893     private byte[] prepareAuctionResultBytes(AuctionResult auctionResult) {
3894         byte[] auctionResultBytes = auctionResult.toByteArray();
3895         AuctionServerDataCompressor.CompressedData compressedData =
3896                 mDataCompressor.compress(
3897                         AuctionServerDataCompressor.UncompressedData.create(auctionResultBytes));
3898         AuctionServerPayloadFormattedData formattedData =
3899                 mPayloadFormatter.apply(
3900                         AuctionServerPayloadUnformattedData.create(compressedData.getData()),
3901                         AuctionServerDataCompressorGzip.VERSION);
3902         return formattedData.getData();
3903     }
3904 
prepareAuctionResultBytesPas()3905     private byte[] prepareAuctionResultBytesPas() {
3906         byte[] auctionResultBytes = AUCTION_RESULT_PAS.toByteArray();
3907         AuctionServerDataCompressor.CompressedData compressedData =
3908                 mDataCompressor.compress(
3909                         AuctionServerDataCompressor.UncompressedData.create(auctionResultBytes));
3910         AuctionServerPayloadFormattedData formattedData =
3911                 mPayloadFormatter.apply(
3912                         AuctionServerPayloadUnformattedData.create(compressedData.getData()),
3913                         AuctionServerDataCompressorGzip.VERSION);
3914         return formattedData.getData();
3915     }
3916 
extractCAAdRenderIdListFromBuyerInput( GetAdSelectionDataTestCallback callback, AdTechIdentifier buyer, String name, String owner)3917     private List<String> extractCAAdRenderIdListFromBuyerInput(
3918             GetAdSelectionDataTestCallback callback,
3919             AdTechIdentifier buyer,
3920             String name,
3921             String owner) {
3922         List<BuyerInput.CustomAudience> customAudienceList =
3923                 getBuyerInputMapFromDecryptedBytes(
3924                                 callback.mGetAdSelectionDataResponse.getAdSelectionData())
3925                         .get(buyer)
3926                         .getCustomAudiencesList();
3927         Optional<BuyerInput.CustomAudience> winningCustomAudienceFromBuyerInputOption =
3928                 customAudienceList.stream()
3929                         .filter(ca -> ca.getName().equals(name) && ca.getOwner().equals(owner))
3930                         .findFirst();
3931         Assert.assertTrue(winningCustomAudienceFromBuyerInputOption.isPresent());
3932         return winningCustomAudienceFromBuyerInputOption.get().getAdRenderIdsList();
3933     }
3934 
getFilterableAndServerEligibleFCapAd(int sequenceNumber, int filterMaxCount)3935     private DBAdData getFilterableAndServerEligibleFCapAd(int sequenceNumber, int filterMaxCount) {
3936         KeyedFrequencyCap fCap =
3937                 new KeyedFrequencyCap.Builder(sequenceNumber, filterMaxCount, ONE_DAY_DURATION)
3938                         .build();
3939         FrequencyCapFilters clickEventFilter =
3940                 new FrequencyCapFilters.Builder()
3941                         .setKeyedFrequencyCapsForClickEvents(ImmutableList.of(fCap))
3942                         .build();
3943         return getValidDbAdDataNoFiltersBuilder(WINNER_BUYER, sequenceNumber)
3944                 .setAdCounterKeys(ImmutableSet.<Integer>builder().add(sequenceNumber).build())
3945                 .setAdFilters(
3946                         new AdFilters.Builder().setFrequencyCapFilters(clickEventFilter).build())
3947                 .setAdRenderId(String.valueOf(sequenceNumber))
3948                 .build();
3949     }
3950 
getFilterableAndServerEligibleAppInstallAd(int sequenceNumber)3951     private DBAdData getFilterableAndServerEligibleAppInstallAd(int sequenceNumber) {
3952         return getValidDbAdDataNoFiltersBuilder(WINNER_BUYER, sequenceNumber)
3953                 .setAdCounterKeys(ImmutableSet.<Integer>builder().add(sequenceNumber).build())
3954                 .setAdFilters(
3955                         new AdFilters.Builder().setAppInstallFilters(CURRENT_APP_FILTER).build())
3956                 .setAdRenderId(String.valueOf(sequenceNumber))
3957                 .build();
3958     }
3959 
invokeGetAdSelectionData( AdSelectionService service, GetAdSelectionDataInput input)3960     public GetAdSelectionDataTestCallback invokeGetAdSelectionData(
3961             AdSelectionService service, GetAdSelectionDataInput input)
3962             throws RemoteException, InterruptedException {
3963         CountDownLatch countDownLatch = new CountDownLatch(1);
3964         GetAdSelectionDataTestCallback callback =
3965                 new GetAdSelectionDataTestCallback(countDownLatch);
3966         service.getAdSelectionData(input, sCallerMetadata, callback);
3967         callback.mCountDownLatch.await();
3968         return callback;
3969     }
3970 
invokePersistAdSelectionResult( AdSelectionService service, PersistAdSelectionResultInput input)3971     public PersistAdSelectionResultTestCallback invokePersistAdSelectionResult(
3972             AdSelectionService service, PersistAdSelectionResultInput input)
3973             throws RemoteException, InterruptedException {
3974         CountDownLatch countDownLatch = new CountDownLatch(1);
3975         PersistAdSelectionResultTestCallback callback =
3976                 new PersistAdSelectionResultTestCallback(countDownLatch);
3977         service.persistAdSelectionResult(input, sCallerMetadata, callback);
3978         callback.mCountDownLatch.await();
3979         return callback;
3980     }
3981 
invokeAdSelectionFromOutcomes( AdSelectionService service, AdSelectionFromOutcomesInput input)3982     public AdSelectionFromOutcomesTestCallback invokeAdSelectionFromOutcomes(
3983             AdSelectionService service, AdSelectionFromOutcomesInput input)
3984             throws RemoteException, InterruptedException {
3985         CountDownLatch countDownLatch = new CountDownLatch(1);
3986         AdSelectionFromOutcomesTestCallback callback =
3987                 new AdSelectionFromOutcomesTestCallback(countDownLatch);
3988         service.selectAdsFromOutcomes(input, null, callback);
3989         callback.mCountDownLatch.await();
3990         return callback;
3991     }
3992 
invokeReportImpression( AdSelectionService service, ReportImpressionInput input)3993     public ReportImpressionTestCallback invokeReportImpression(
3994             AdSelectionService service, ReportImpressionInput input)
3995             throws RemoteException, InterruptedException {
3996         CountDownLatch countDownLatch = new CountDownLatch(1);
3997         ReportImpressionTestCallback callback = new ReportImpressionTestCallback(countDownLatch);
3998         service.reportImpression(input, callback);
3999         callback.mCountDownLatch.await();
4000         return callback;
4001     }
4002 
invokeReportInteractions( AdSelectionService service, ReportInteractionInput input)4003     public ReportInteractionsTestCallback invokeReportInteractions(
4004             AdSelectionService service, ReportInteractionInput input)
4005             throws RemoteException, InterruptedException {
4006         CountDownLatch countDownLatch = new CountDownLatch(1);
4007         ReportInteractionsTestCallback callback =
4008                 new ReportInteractionsTestCallback(countDownLatch);
4009         service.reportInteraction(input, callback);
4010         callback.mCountDownLatch.await();
4011         return callback;
4012     }
4013 
invokeUpdateAdCounterHistogram( AdSelectionService service, UpdateAdCounterHistogramInput input)4014     public UpdateAdCounterHistogramTestCallback invokeUpdateAdCounterHistogram(
4015             AdSelectionService service, UpdateAdCounterHistogramInput input)
4016             throws RemoteException, InterruptedException {
4017         CountDownLatch countDownLatch = new CountDownLatch(1);
4018         UpdateAdCounterHistogramTestCallback callback =
4019                 new UpdateAdCounterHistogramTestCallback(countDownLatch);
4020         service.updateAdCounterHistogram(input, callback);
4021         callback.mCountDownLatch.await();
4022         return callback;
4023     }
4024 
4025     static class GetAdSelectionDataTestCallback extends GetAdSelectionDataCallback.Stub {
4026         final CountDownLatch mCountDownLatch;
4027         boolean mIsSuccess = false;
4028         GetAdSelectionDataResponse mGetAdSelectionDataResponse;
4029         FledgeErrorResponse mFledgeErrorResponse;
4030 
GetAdSelectionDataTestCallback(CountDownLatch countDownLatch)4031         GetAdSelectionDataTestCallback(CountDownLatch countDownLatch) {
4032             mCountDownLatch = countDownLatch;
4033             mGetAdSelectionDataResponse = null;
4034             mFledgeErrorResponse = null;
4035         }
4036 
4037         @Override
onSuccess(GetAdSelectionDataResponse getAdSelectionDataResponse)4038         public void onSuccess(GetAdSelectionDataResponse getAdSelectionDataResponse)
4039                 throws RemoteException {
4040             mIsSuccess = true;
4041             mGetAdSelectionDataResponse = getAdSelectionDataResponse;
4042             mCountDownLatch.countDown();
4043         }
4044 
4045         @Override
onFailure(FledgeErrorResponse fledgeErrorResponse)4046         public void onFailure(FledgeErrorResponse fledgeErrorResponse) throws RemoteException {
4047             mIsSuccess = false;
4048             mFledgeErrorResponse = fledgeErrorResponse;
4049             mCountDownLatch.countDown();
4050         }
4051     }
4052 
getAdSelectionData(GetAdSelectionDataResponse response)4053     private byte[] getAdSelectionData(GetAdSelectionDataResponse response) throws IOException {
4054         if (Objects.nonNull(response.getAssetFileDescriptor())) {
4055             AssetFileDescriptor assetFileDescriptor = response.getAssetFileDescriptor();
4056             return AssetFileDescriptorUtil.readAssetFileDescriptorIntoBuffer(assetFileDescriptor);
4057         } else {
4058             return response.getAdSelectionData();
4059         }
4060     }
4061 
setFlagsWithBothFiltersEnabled()4062     private void setFlagsWithBothFiltersEnabled() {
4063         flags.setFlag(KEY_FLEDGE_FREQUENCY_CAP_FILTERING_ENABLED, true);
4064         flags.setFlag(KEY_FLEDGE_APP_INSTALL_FILTERING_ENABLED, true);
4065     }
4066 
setComponentAdsEnabled()4067     private void setComponentAdsEnabled() {
4068         flags.setFlag(KEY_ENABLE_CUSTOM_AUDIENCE_COMPONENT_ADS, true);
4069     }
4070 
4071     private static final class PersistAdSelectionResultTestCallback
4072             extends PersistAdSelectionResultCallback.Stub {
4073         final CountDownLatch mCountDownLatch;
4074         boolean mIsSuccess = false;
4075         PersistAdSelectionResultResponse mPersistAdSelectionResultResponse;
4076         FledgeErrorResponse mFledgeErrorResponse;
4077 
PersistAdSelectionResultTestCallback(CountDownLatch countDownLatch)4078         PersistAdSelectionResultTestCallback(CountDownLatch countDownLatch) {
4079             mCountDownLatch = countDownLatch;
4080             mPersistAdSelectionResultResponse = null;
4081             mFledgeErrorResponse = null;
4082         }
4083 
4084         @Override
onSuccess(PersistAdSelectionResultResponse persistAdSelectionResultResponse)4085         public void onSuccess(PersistAdSelectionResultResponse persistAdSelectionResultResponse)
4086                 throws RemoteException {
4087             mIsSuccess = true;
4088             mPersistAdSelectionResultResponse = persistAdSelectionResultResponse;
4089             mCountDownLatch.countDown();
4090         }
4091 
4092         @Override
onFailure(FledgeErrorResponse fledgeErrorResponse)4093         public void onFailure(FledgeErrorResponse fledgeErrorResponse) throws RemoteException {
4094             mIsSuccess = false;
4095             mFledgeErrorResponse = fledgeErrorResponse;
4096             mCountDownLatch.countDown();
4097         }
4098     }
4099 
4100     private static final class AppInstallResultCapturingCallback
4101             implements SetAppInstallAdvertisersCallback {
4102         private boolean mIsSuccess;
4103         private Exception mException;
4104         private final CountDownLatch mCountDownLatch;
4105 
isSuccess()4106         public boolean isSuccess() {
4107             return mIsSuccess;
4108         }
4109 
getException()4110         public Exception getException() {
4111             return mException;
4112         }
4113 
AppInstallResultCapturingCallback(CountDownLatch countDownLatch)4114         AppInstallResultCapturingCallback(CountDownLatch countDownLatch) {
4115             mCountDownLatch = countDownLatch;
4116         }
4117 
4118         @Override
onSuccess()4119         public void onSuccess() throws RemoteException {
4120             mIsSuccess = true;
4121             mCountDownLatch.countDown();
4122         }
4123 
4124         @Override
onFailure(FledgeErrorResponse responseParcel)4125         public void onFailure(FledgeErrorResponse responseParcel) throws RemoteException {
4126             mIsSuccess = false;
4127             mException = AdServicesStatusUtils.asException(responseParcel);
4128             mCountDownLatch.countDown();
4129         }
4130 
4131         @Override
asBinder()4132         public IBinder asBinder() {
4133             throw new RuntimeException("Should not be called.");
4134         }
4135     }
4136 
4137     private static final class AdSelectionFromOutcomesTestCallback
4138             extends AdSelectionCallback.Stub {
4139 
4140         final CountDownLatch mCountDownLatch;
4141         boolean mIsSuccess = false;
4142         AdSelectionResponse mAdSelectionResponse;
4143         FledgeErrorResponse mFledgeErrorResponse;
4144 
AdSelectionFromOutcomesTestCallback(CountDownLatch countDownLatch)4145         AdSelectionFromOutcomesTestCallback(CountDownLatch countDownLatch) {
4146             mCountDownLatch = countDownLatch;
4147             mAdSelectionResponse = null;
4148             mFledgeErrorResponse = null;
4149         }
4150 
4151         @Override
onSuccess(AdSelectionResponse adSelectionResponse)4152         public void onSuccess(AdSelectionResponse adSelectionResponse) throws RemoteException {
4153             mIsSuccess = true;
4154             mAdSelectionResponse = adSelectionResponse;
4155             mCountDownLatch.countDown();
4156         }
4157 
4158         @Override
onFailure(FledgeErrorResponse fledgeErrorResponse)4159         public void onFailure(FledgeErrorResponse fledgeErrorResponse) throws RemoteException {
4160             mIsSuccess = false;
4161             mFledgeErrorResponse = fledgeErrorResponse;
4162             mCountDownLatch.countDown();
4163         }
4164     }
4165 
4166     private static final class ReportImpressionTestCallback extends ReportImpressionCallback.Stub {
4167         final CountDownLatch mCountDownLatch;
4168         boolean mIsSuccess = false;
4169         FledgeErrorResponse mFledgeErrorResponse;
4170 
ReportImpressionTestCallback(CountDownLatch countDownLatch)4171         ReportImpressionTestCallback(CountDownLatch countDownLatch) {
4172             mCountDownLatch = countDownLatch;
4173             mFledgeErrorResponse = null;
4174         }
4175 
4176         @Override
onSuccess()4177         public void onSuccess() throws RemoteException {
4178             mIsSuccess = true;
4179             mCountDownLatch.countDown();
4180         }
4181 
4182         @Override
onFailure(FledgeErrorResponse fledgeErrorResponse)4183         public void onFailure(FledgeErrorResponse fledgeErrorResponse) throws RemoteException {
4184             mIsSuccess = false;
4185             mFledgeErrorResponse = fledgeErrorResponse;
4186             mCountDownLatch.countDown();
4187         }
4188     }
4189 
4190     private static final class ReportInteractionsTestCallback
4191             extends ReportInteractionCallback.Stub {
4192         final CountDownLatch mCountDownLatch;
4193         boolean mIsSuccess = false;
4194         FledgeErrorResponse mFledgeErrorResponse;
4195 
ReportInteractionsTestCallback(CountDownLatch countDownLatch)4196         ReportInteractionsTestCallback(CountDownLatch countDownLatch) {
4197             mCountDownLatch = countDownLatch;
4198             mFledgeErrorResponse = null;
4199         }
4200 
4201         @Override
onSuccess()4202         public void onSuccess() throws RemoteException {
4203             mIsSuccess = true;
4204             mCountDownLatch.countDown();
4205         }
4206 
4207         @Override
onFailure(FledgeErrorResponse fledgeErrorResponse)4208         public void onFailure(FledgeErrorResponse fledgeErrorResponse) throws RemoteException {
4209             mIsSuccess = false;
4210             mFledgeErrorResponse = fledgeErrorResponse;
4211             mCountDownLatch.countDown();
4212         }
4213     }
4214 
4215     private static final class UpdateAdCounterHistogramTestCallback
4216             extends UpdateAdCounterHistogramCallback.Stub {
4217         final CountDownLatch mCountDownLatch;
4218         boolean mIsSuccess = false;
4219         FledgeErrorResponse mFledgeErrorResponse;
4220 
UpdateAdCounterHistogramTestCallback(CountDownLatch countDownLatch)4221         UpdateAdCounterHistogramTestCallback(CountDownLatch countDownLatch) {
4222             mCountDownLatch = countDownLatch;
4223             mFledgeErrorResponse = null;
4224         }
4225 
4226         @Override
onSuccess()4227         public void onSuccess() throws RemoteException {
4228             mIsSuccess = true;
4229             mCountDownLatch.countDown();
4230         }
4231 
4232         @Override
onFailure(FledgeErrorResponse fledgeErrorResponse)4233         public void onFailure(FledgeErrorResponse fledgeErrorResponse) throws RemoteException {
4234             mIsSuccess = false;
4235             mFledgeErrorResponse = fledgeErrorResponse;
4236             mCountDownLatch.countDown();
4237         }
4238     }
4239 
4240     // TODO(b/388097793): this is used on 2 tests that would fail if the FlagsFactory singleton is
4241     // the mFakeFlags set by flags; we need to refactor those tests and/or add a new infra that
4242     // would "clone" the initial flags (before it's annotated by the test)
4243     private static final class LegacyAuctionServerE2ETestFlags implements Flags {
4244         @Override
getFledgeRegisterAdBeaconEnabled()4245         public boolean getFledgeRegisterAdBeaconEnabled() {
4246             return true;
4247         }
4248 
4249         @Override
getFledgeAuctionServerKillSwitch()4250         public boolean getFledgeAuctionServerKillSwitch() {
4251             return false;
4252         }
4253 
4254         @Override
getFledgeAuctionServerEnabledForReportImpression()4255         public boolean getFledgeAuctionServerEnabledForReportImpression() {
4256             return true;
4257         }
4258     }
4259 }
4260