| /* |
| * Copyright (C) 2022 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.adservices.service.adselection; |
| |
| import static android.adservices.adselection.ReportInteractionRequest.FLAG_REPORTING_DESTINATION_BUYER; |
| import static android.adservices.adselection.ReportInteractionRequest.FLAG_REPORTING_DESTINATION_SELLER; |
| import static android.adservices.common.AdServicesStatusUtils.RATE_LIMIT_REACHED_ERROR_MESSAGE; |
| import static android.adservices.common.AdServicesStatusUtils.STATUS_CALLER_NOT_ALLOWED; |
| import static android.adservices.common.AdServicesStatusUtils.STATUS_INTERNAL_ERROR; |
| import static android.adservices.common.AdServicesStatusUtils.STATUS_INVALID_ARGUMENT; |
| import static android.adservices.common.AdServicesStatusUtils.STATUS_RATE_LIMIT_REACHED; |
| import static android.adservices.common.AdServicesStatusUtils.STATUS_SUCCESS; |
| import static android.adservices.common.AdServicesStatusUtils.STATUS_UNAUTHORIZED; |
| import static android.adservices.common.AdServicesStatusUtils.STATUS_USER_CONSENT_REVOKED; |
| import static android.adservices.common.CommonFixture.TEST_PACKAGE_NAME; |
| |
| import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_CLASS__UNKNOWN; |
| import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN; |
| import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__OVERRIDE_AD_SELECTION_CONFIG_REMOTE_INFO; |
| import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__REMOVE_AD_SELECTION_CONFIG_REMOTE_INFO_OVERRIDE; |
| import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION; |
| import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__RESET_ALL_AD_SELECTION_CONFIG_REMOTE_OVERRIDES; |
| import static com.android.adservices.service.stats.AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__SET_APP_INSTALL_ADVERTISERS; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertThrows; |
| import static org.junit.Assert.assertTrue; |
| import static org.mockito.Mockito.never; |
| |
| import android.adservices.adselection.AdSelectionCallback; |
| import android.adservices.adselection.AdSelectionConfig; |
| import android.adservices.adselection.AdSelectionConfigFixture; |
| import android.adservices.adselection.AdSelectionFromOutcomesConfig; |
| import android.adservices.adselection.AdSelectionFromOutcomesConfigFixture; |
| import android.adservices.adselection.AdSelectionFromOutcomesInput; |
| import android.adservices.adselection.AdSelectionOverrideCallback; |
| import android.adservices.adselection.AdSelectionResponse; |
| import android.adservices.adselection.CustomAudienceSignalsFixture; |
| import android.adservices.adselection.RemoveAdCounterHistogramOverrideInput; |
| import android.adservices.adselection.ReportImpressionCallback; |
| import android.adservices.adselection.ReportImpressionInput; |
| import android.adservices.adselection.ReportInteractionCallback; |
| import android.adservices.adselection.ReportInteractionInput; |
| import android.adservices.adselection.SetAdCounterHistogramOverrideInput; |
| import android.adservices.adselection.SetAppInstallAdvertisersInput; |
| import android.adservices.adselection.UpdateAdCounterHistogramCallback; |
| import android.adservices.adselection.UpdateAdCounterHistogramInput; |
| import android.adservices.common.AdSelectionSignals; |
| import android.adservices.common.AdServicesStatusUtils; |
| import android.adservices.common.AdTechIdentifier; |
| import android.adservices.common.CallingAppUidSupplierProcessImpl; |
| import android.adservices.common.CommonFixture; |
| import android.adservices.common.FledgeErrorResponse; |
| import android.adservices.common.FrequencyCapFilters; |
| import android.adservices.common.KeyedFrequencyCapFixture; |
| import android.adservices.http.MockWebServerRule; |
| import android.content.Context; |
| import android.net.Uri; |
| import android.os.LimitExceededException; |
| import android.os.Process; |
| import android.os.RemoteException; |
| |
| import androidx.room.Room; |
| import androidx.test.core.app.ApplicationProvider; |
| |
| import com.android.adservices.LoggerFactory; |
| import com.android.adservices.MockWebServerRuleFactory; |
| import com.android.adservices.concurrency.AdServicesExecutors; |
| import com.android.adservices.data.DbTestUtil; |
| import com.android.adservices.data.adselection.AdSelectionDatabase; |
| import com.android.adservices.data.adselection.AdSelectionEntryDao; |
| import com.android.adservices.data.adselection.AppInstallDao; |
| import com.android.adservices.data.adselection.CustomAudienceSignals; |
| import com.android.adservices.data.adselection.DBAdSelection; |
| import com.android.adservices.data.adselection.DBAdSelectionFromOutcomesOverride; |
| import com.android.adservices.data.adselection.DBAdSelectionOverride; |
| import com.android.adservices.data.adselection.DBBuyerDecisionLogic; |
| import com.android.adservices.data.adselection.FrequencyCapDao; |
| import com.android.adservices.data.adselection.SharedStorageDatabase; |
| import com.android.adservices.data.customaudience.CustomAudienceDao; |
| import com.android.adservices.data.customaudience.CustomAudienceDatabase; |
| import com.android.adservices.data.customaudience.DBCustomAudience; |
| import com.android.adservices.data.enrollment.EnrollmentDao; |
| import com.android.adservices.service.Flags; |
| import com.android.adservices.service.adselection.AppInstallAdvertisersSetterTest.SetAppInstallAdvertisersTestCallback; |
| import com.android.adservices.service.common.AdSelectionServiceFilter; |
| import com.android.adservices.service.common.AppImportanceFilter; |
| import com.android.adservices.service.common.AppImportanceFilter.WrongCallingApplicationStateException; |
| import com.android.adservices.service.common.FledgeAuthorizationFilter; |
| import com.android.adservices.service.common.Throttler; |
| import com.android.adservices.service.common.cache.CacheProviderFactory; |
| import com.android.adservices.service.common.httpclient.AdServicesHttpsClient; |
| import com.android.adservices.service.consent.AdServicesApiConsent; |
| import com.android.adservices.service.consent.ConsentManager; |
| import com.android.adservices.service.devapi.AdSelectionDevOverridesHelper; |
| import com.android.adservices.service.devapi.DevContext; |
| import com.android.adservices.service.devapi.DevContextFilter; |
| import com.android.adservices.service.exception.FilterException; |
| import com.android.adservices.service.js.JSScriptEngine; |
| import com.android.adservices.service.stats.AdServicesLogger; |
| import com.android.adservices.service.stats.AdServicesLoggerImpl; |
| import com.android.adservices.service.stats.AdServicesStatsLog; |
| import com.android.dx.mockito.inline.extended.ExtendedMockito; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.util.concurrent.Futures; |
| import com.google.common.util.concurrent.ListenableFuture; |
| import com.google.mockwebserver.Dispatcher; |
| import com.google.mockwebserver.MockResponse; |
| import com.google.mockwebserver.MockWebServer; |
| import com.google.mockwebserver.RecordedRequest; |
| |
| import org.junit.After; |
| import org.junit.Assume; |
| import org.junit.Before; |
| import org.junit.Ignore; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.mockito.Mock; |
| import org.mockito.Mockito; |
| import org.mockito.MockitoSession; |
| import org.mockito.Spy; |
| import org.mockito.quality.Strictness; |
| import org.mockito.stubbing.Answer; |
| |
| import java.time.Clock; |
| import java.time.Instant; |
| import java.time.ZoneOffset; |
| import java.time.temporal.ChronoUnit; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.ExecutorService; |
| import java.util.concurrent.ScheduledThreadPoolExecutor; |
| import java.util.concurrent.TimeUnit; |
| |
| public class AdSelectionServiceImplTest { |
| private static final LoggerFactory.Logger sLogger = LoggerFactory.getFledgeLogger(); |
| private static final int CALLER_UID = Process.myUid(); |
| private static final Context CONTEXT = ApplicationProvider.getApplicationContext(); |
| private static final Clock CLOCK = Clock.fixed(Instant.now(), ZoneOffset.UTC); |
| private static final Uri RENDER_URI = Uri.parse("https://test.com/advert/"); |
| private static final Instant ACTIVATION_TIME = CLOCK.instant().truncatedTo(ChronoUnit.MILLIS); |
| private static final Uri BUYER_BIDDING_LOGIC_URI = Uri.parse("https://test.com"); |
| private static final long AD_SELECTION_ID = 1; |
| private static final long INCORRECT_AD_SELECTION_ID = 2; |
| private static final double BID = 5.0; |
| private static final AdTechIdentifier SELLER_VALID = AdTechIdentifier.fromString("test.com"); |
| private static final Uri DECISION_LOGIC_URI_INCONSISTENT = |
| Uri.parse("https://testinconsistent.com/test/decisions_logic_uris"); |
| private static final String DUMMY_DECISION_LOGIC_JS = |
| "function test() { return \"hello world\"; }"; |
| private static final String DUMMY_SELECTION_LOGIC_JS = |
| "function selection() { return \"hello world\"; }"; |
| private static final AdSelectionSignals DUMMY_TRUSTED_SCORING_SIGNALS = |
| AdSelectionSignals.fromString( |
| "{\n" |
| + "\t\"render_uri_1\": \"signals_for_1\",\n" |
| + "\t\"render_uri_2\": \"signals_for_2\"\n" |
| + "}"); |
| private static final AdSelectionSignals DUMMY_SELECTION_SIGNALS = |
| AdSelectionSignals.fromString("{\"selection\": \"signal_1\"}"); |
| |
| private static final long AD_SELECTION_ID_1 = 12345L; |
| private static final long AD_SELECTION_ID_2 = 123456L; |
| private static final long AD_SELECTION_ID_3 = 1234567L; |
| |
| // Auto-generated variable names are too long for lint check |
| private static final int SHORT_API_NAME_OVERRIDE = |
| AD_SERVICES_API_CALLED__API_NAME__OVERRIDE_AD_SELECTION_CONFIG_REMOTE_INFO; |
| private static final int SHORT_API_NAME_REMOVE_OVERRIDE = |
| AD_SERVICES_API_CALLED__API_NAME__REMOVE_AD_SELECTION_CONFIG_REMOTE_INFO_OVERRIDE; |
| private static final int SHORT_API_NAME_RESET_ALL_OVERRIDES = |
| AD_SERVICES_API_CALLED__API_NAME__RESET_ALL_AD_SELECTION_CONFIG_REMOTE_OVERRIDES; |
| private static final String TIMEOUT_MESSAGE = "Timed out"; |
| |
| // Interaction reporting contestants |
| private static final String CLICK_EVENT_SELLER = "click_seller"; |
| private static final String HOVER_EVENT_SELLER = "hover_seller"; |
| |
| private static final String CLICK_SELLER_PATH = "/click/seller"; |
| private static final String HOVER_SELLER_PATH = "/hover/seller"; |
| |
| private static final String CLICK_EVENT_BUYER = "click_buyer"; |
| private static final String HOVER_EVENT_BUYER = "hover_buyer"; |
| |
| private static final String CLICK_BUYER_PATH = "/click/buyer"; |
| private static final String HOVER_BUYER_PATH = "/hover/buyer"; |
| |
| private static final String INTERACTION_DATA = "{\"key\":\"value\"}"; |
| |
| private final ExecutorService mLightweightExecutorService = |
| AdServicesExecutors.getLightWeightExecutor(); |
| private final ExecutorService mBackgroundExecutorService = |
| AdServicesExecutors.getBackgroundExecutor(); |
| private final ScheduledThreadPoolExecutor mScheduledExecutor = |
| AdServicesExecutors.getScheduler(); |
| private final String mSellerReportingPath = "/reporting/seller"; |
| private final String mBuyerReportingPath = "/reporting/buyer"; |
| private final String mFetchJavaScriptPathSeller = "/fetchJavascript/seller"; |
| private final String mFetchJavaScriptPathBuyer = "/fetchJavascript/buyer"; |
| private final String mFetchTrustedScoringSignalsPath = "/fetchTrustedSignals/"; |
| private final AdTechIdentifier mContextualSignals = |
| AdTechIdentifier.fromString("{\"contextual_signals\":1}"); |
| private final int mBytesPerPeriod = 1; |
| |
| @Spy |
| private final AdServicesHttpsClient mClient = |
| new AdServicesHttpsClient( |
| AdServicesExecutors.getBlockingExecutor(), |
| CacheProviderFactory.createNoOpCache()); |
| |
| private final AdServicesLogger mAdServicesLoggerMock = |
| ExtendedMockito.mock(AdServicesLoggerImpl.class); |
| @Rule public MockWebServerRule mMockWebServerRule = MockWebServerRuleFactory.createForHttps(); |
| // This object access some system APIs |
| @Mock public DevContextFilter mDevContextFilter; |
| @Mock public AppImportanceFilter mAppImportanceFilterMock; |
| |
| @Spy |
| FledgeAuthorizationFilter mFledgeAuthorizationFilterSpy = |
| new FledgeAuthorizationFilter( |
| CONTEXT.getPackageManager(), |
| new EnrollmentDao(CONTEXT, DbTestUtil.getDbHelperForTest()), |
| mAdServicesLoggerMock); |
| |
| private Flags mFlags = new FlagsWithEnrollmentCheckEnabledSwitch(false); |
| |
| private MockitoSession mStaticMockSession = null; |
| @Mock private ConsentManager mConsentManagerMock; |
| private CustomAudienceDao mCustomAudienceDao; |
| private AdSelectionEntryDao mAdSelectionEntryDao; |
| private AppInstallDao mAppInstallDao; |
| private FrequencyCapDao mFrequencyCapDao; |
| private AdSelectionConfig.Builder mAdSelectionConfigBuilder; |
| |
| private Uri mBiddingLogicUri; |
| private CustomAudienceSignals mCustomAudienceSignals; |
| private AdTechIdentifier mSeller; |
| private AdFilteringFeatureFactory mAdFilteringFeatureFactory; |
| |
| @Mock private AdSelectionServiceFilter mAdSelectionServiceFilter; |
| |
| @Before |
| public void setUp() { |
| mStaticMockSession = |
| ExtendedMockito.mockitoSession() |
| .spyStatic(JSScriptEngine.class) |
| // mAdServicesLoggerMock is not referenced in many tests |
| .strictness(Strictness.LENIENT) |
| .initMocks(this) |
| .mockStatic(ConsentManager.class) |
| .mockStatic(AppImportanceFilter.class) |
| .startMocking(); |
| mCustomAudienceDao = |
| Room.inMemoryDatabaseBuilder(CONTEXT, CustomAudienceDatabase.class) |
| .addTypeConverter(new DBCustomAudience.Converters(true)) |
| .build() |
| .customAudienceDao(); |
| |
| mAdSelectionEntryDao = |
| Room.inMemoryDatabaseBuilder( |
| ApplicationProvider.getApplicationContext(), |
| AdSelectionDatabase.class) |
| .build() |
| .adSelectionEntryDao(); |
| SharedStorageDatabase sharedDb = |
| Room.inMemoryDatabaseBuilder( |
| ApplicationProvider.getApplicationContext(), |
| SharedStorageDatabase.class) |
| .build(); |
| |
| mAppInstallDao = sharedDb.appInstallDao(); |
| mFrequencyCapDao = sharedDb.frequencyCapDao(); |
| mAdFilteringFeatureFactory = |
| new AdFilteringFeatureFactory(mAppInstallDao, mFrequencyCapDao, mFlags); |
| |
| mBiddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| mCustomAudienceSignals = |
| CustomAudienceSignalsFixture.aCustomAudienceSignalsBuilder() |
| .setBuyer(AdTechIdentifier.fromString(mBiddingLogicUri.getHost())) |
| .build(); |
| |
| Map<AdTechIdentifier, AdSelectionSignals> perBuyerSignals = |
| Map.of( |
| AdTechIdentifier.fromString("test.com"), |
| AdSelectionSignals.fromString("{\"buyer_signals\":1}"), |
| AdTechIdentifier.fromString("test2.com"), |
| AdSelectionSignals.fromString("{\"buyer_signals\":2}"), |
| AdTechIdentifier.fromString("test3.com"), |
| AdSelectionSignals.fromString("{\"buyer_signals\":3}"), |
| AdTechIdentifier.fromString(mBiddingLogicUri.getHost()), |
| AdSelectionSignals.fromString("{\"buyer_signals\":0}")); |
| |
| mSeller = |
| AdTechIdentifier.fromString( |
| mMockWebServerRule.uriForPath(mFetchJavaScriptPathSeller).getHost()); |
| |
| mAdSelectionConfigBuilder = |
| AdSelectionConfigFixture.anAdSelectionConfigBuilder() |
| .setSeller(mSeller) |
| .setDecisionLogicUri( |
| mMockWebServerRule.uriForPath(mFetchJavaScriptPathSeller)) |
| .setTrustedScoringSignalsUri( |
| mMockWebServerRule.uriForPath(mFetchTrustedScoringSignalsPath)) |
| .setPerBuyerSignals(perBuyerSignals); |
| |
| doNothing() |
| .when(mAdSelectionServiceFilter) |
| .filterRequest( |
| mSeller, |
| TEST_PACKAGE_NAME, |
| true, |
| true, |
| CALLER_UID, |
| AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION, |
| Throttler.ApiKey.FLEDGE_API_REPORT_IMPRESSIONS); |
| when(ConsentManager.getInstance(CONTEXT)).thenReturn(mConsentManagerMock); |
| when(AppImportanceFilter.create(any(), anyInt(), any())) |
| .thenReturn(mAppImportanceFilterMock); |
| doNothing() |
| .when(mAppImportanceFilterMock) |
| .assertCallerIsInForeground(anyInt(), anyInt(), any()); |
| } |
| |
| @After |
| public void tearDown() { |
| if (mStaticMockSession != null) { |
| mStaticMockSession.finishMocking(); |
| } |
| } |
| |
| @Test |
| public void testReportImpressionSuccessWithRegisterAdBeaconDisabled() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| // Re init flags with registerAdBeaconDisabled |
| mFlags = |
| new FlagsWithEnrollmentCheckEnabledSwitch(false) { |
| @Override |
| public boolean getFledgeRegisterAdBeaconEnabled() { |
| return false; |
| } |
| }; |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| Uri biddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(biddingLogicUri) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(biddingLogicUri) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| // Count down callback + log interaction. |
| ReportImpressionTestCallback callback = |
| callReportImpression(adSelectionService, input, true); |
| |
| assertTrue(callback.mIsSuccess); |
| RecordedRequest fetchRequest = server.takeRequest(); |
| assertEquals(mFetchJavaScriptPathSeller, fetchRequest.getPath()); |
| |
| List<String> notifications = |
| ImmutableList.of(server.takeRequest().getPath(), server.takeRequest().getPath()); |
| |
| assertThat(notifications).containsExactly(mSellerReportingPath, mBuyerReportingPath); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionSuccessWithRegisterAdBeaconEnabled() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| Uri biddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(biddingLogicUri) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(biddingLogicUri) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| // Count down callback + log interaction. |
| ReportImpressionTestCallback callback = |
| callReportImpression(adSelectionService, input, true); |
| |
| assertTrue(callback.mIsSuccess); |
| RecordedRequest fetchRequest = server.takeRequest(); |
| assertEquals(mFetchJavaScriptPathSeller, fetchRequest.getPath()); |
| |
| List<String> notifications = |
| ImmutableList.of(server.takeRequest().getPath(), server.takeRequest().getPath()); |
| |
| assertThat(notifications).containsExactly(mSellerReportingPath, mBuyerReportingPath); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionSuccessWithEmptyBuyerSignals() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| Uri biddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(biddingLogicUri) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(biddingLogicUri) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| // Create empty per buyer signals |
| Map<AdTechIdentifier, AdSelectionSignals> emptyPerBuyerSignals = new HashMap<>(); |
| |
| AdSelectionConfig adSelectionConfig = |
| mAdSelectionConfigBuilder.setPerBuyerSignals(emptyPerBuyerSignals).build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| // Count down callback + log interaction. |
| ReportImpressionTestCallback callback = |
| callReportImpression(adSelectionService, input, true); |
| |
| assertTrue(callback.mIsSuccess); |
| RecordedRequest fetchRequest = server.takeRequest(); |
| assertEquals(mFetchJavaScriptPathSeller, fetchRequest.getPath()); |
| |
| List<String> notifications = |
| ImmutableList.of(server.takeRequest().getPath(), server.takeRequest().getPath()); |
| |
| assertThat(notifications).containsExactly(mSellerReportingPath, mBuyerReportingPath); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionSuccessAndDoesNotCrashAfterSellerThrowsAnException() |
| throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| ListenableFuture<Void> failedFuture = |
| Futures.submit( |
| () -> { |
| throw new IllegalStateException("Exception for test!"); |
| }, |
| mLightweightExecutorService); |
| |
| doReturn(failedFuture).when(mClient).getAndReadNothing(sellerReportingUri); |
| |
| Uri biddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| // Start mockserver with throttling for seller reporting |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(biddingLogicUri) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(biddingLogicUri) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| // Count down callback + log interaction. |
| ReportImpressionTestCallback callback = |
| callReportImpression(adSelectionService, input, true); |
| |
| assertTrue(callback.mIsSuccess); |
| RecordedRequest fetchRequest = server.takeRequest(); |
| assertEquals(mFetchJavaScriptPathSeller, fetchRequest.getPath()); |
| |
| assertEquals(server.takeRequest().getPath(), mBuyerReportingPath); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_INTERNAL_ERROR), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionSuccessAndDoesNotCrashAfterBuyerReportThrowsAnException() |
| throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| ListenableFuture<Void> failedFuture = |
| Futures.submit( |
| () -> { |
| throw new IllegalStateException("Exception for test!"); |
| }, |
| mLightweightExecutorService); |
| |
| doReturn(failedFuture).when(mClient).getAndReadNothing(buyerReportingUri); |
| |
| Uri biddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| // Start mockserver with throttling for buyer reporting |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(biddingLogicUri) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(biddingLogicUri) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| // Count down callback + log interaction. |
| ReportImpressionTestCallback callback = |
| callReportImpression(adSelectionService, input, true); |
| |
| assertTrue(callback.mIsSuccess); |
| RecordedRequest fetchRequest = server.takeRequest(); |
| assertEquals(mFetchJavaScriptPathSeller, fetchRequest.getPath()); |
| |
| assertEquals(server.takeRequest().getPath(), mSellerReportingPath); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_INTERNAL_ERROR), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionSuccessfullyRegistersEventUris() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| Uri biddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| Uri clickUriSeller = mMockWebServerRule.uriForPath(CLICK_SELLER_PATH); |
| Uri hoverUriSeller = mMockWebServerRule.uriForPath(HOVER_SELLER_PATH); |
| Uri clickUriBuyer = mMockWebServerRule.uriForPath(CLICK_BUYER_PATH); |
| Uri hoverUriBuyer = mMockWebServerRule.uriForPath(HOVER_BUYER_PATH); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) " |
| + "{\n" |
| + " registerAdBeacon('click_seller', '" |
| + clickUriSeller |
| + "');\n" |
| + " registerAdBeacon('hover_seller', '" |
| + hoverUriSeller |
| + "');\n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer ," |
| + "contextual_signals, custom_audience_signals) {\n" |
| + " registerAdBeacon('click_buyer', '" |
| + clickUriBuyer |
| + "');\n" |
| + " registerAdBeacon('hover_buyer', '" |
| + hoverUriBuyer |
| + "');\n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(biddingLogicUri) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(biddingLogicUri) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| // Count down callback + log interaction. |
| ReportImpressionTestCallback callback = |
| callReportImpression(adSelectionService, input, true); |
| |
| assertTrue(callback.mIsSuccess); |
| |
| // Check that database has correct seller registered events |
| assertTrue( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, CLICK_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| assertEquals( |
| clickUriSeller, |
| mAdSelectionEntryDao.getRegisteredAdInteractionUri( |
| AD_SELECTION_ID, CLICK_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, HOVER_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| assertEquals( |
| hoverUriSeller, |
| mAdSelectionEntryDao.getRegisteredAdInteractionUri( |
| AD_SELECTION_ID, HOVER_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| |
| // Check that database has correct buyer registered events |
| assertTrue( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, CLICK_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| assertEquals( |
| clickUriBuyer, |
| mAdSelectionEntryDao.getRegisteredAdInteractionUri( |
| AD_SELECTION_ID, CLICK_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, HOVER_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| assertEquals( |
| hoverUriBuyer, |
| mAdSelectionEntryDao.getRegisteredAdInteractionUri( |
| AD_SELECTION_ID, HOVER_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| |
| RecordedRequest fetchRequest = server.takeRequest(); |
| assertEquals(mFetchJavaScriptPathSeller, fetchRequest.getPath()); |
| |
| List<String> notifications = |
| ImmutableList.of(server.takeRequest().getPath(), server.takeRequest().getPath()); |
| |
| assertThat(notifications).containsExactly(mSellerReportingPath, mBuyerReportingPath); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionFailsWithRegisterAdBeaconDisabled() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| // Re init flags with registerAdBeaconDisabled |
| mFlags = |
| new FlagsWithEnrollmentCheckEnabledSwitch(false) { |
| @Override |
| public boolean getFledgeRegisterAdBeaconEnabled() { |
| return false; |
| } |
| }; |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| Uri biddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| Uri clickUriSeller = mMockWebServerRule.uriForPath(CLICK_SELLER_PATH); |
| Uri hoverUriSeller = mMockWebServerRule.uriForPath(HOVER_SELLER_PATH); |
| Uri clickUriBuyer = mMockWebServerRule.uriForPath(CLICK_BUYER_PATH); |
| Uri hoverUriBuyer = mMockWebServerRule.uriForPath(HOVER_BUYER_PATH); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) " |
| + "{\n" |
| + " registerAdBeacon('click_seller', '" |
| + clickUriSeller |
| + "');\n" |
| + " registerAdBeacon('hover_seller', '" |
| + hoverUriSeller |
| + "');\n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer ," |
| + "contextual_signals, custom_audience_signals) {\n" |
| + " registerAdBeacon('click_buyer', '" |
| + clickUriBuyer |
| + "');\n" |
| + " registerAdBeacon('hover_buyer', '" |
| + hoverUriBuyer |
| + "');\n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(biddingLogicUri) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(biddingLogicUri) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| ReportImpressionTestCallback callback = callReportImpression(adSelectionService, input); |
| |
| assertFalse(callback.mIsSuccess); |
| assertEquals(STATUS_INTERNAL_ERROR, callback.mFledgeErrorResponse.getStatusCode()); |
| |
| // Check that no events are registered |
| assertFalse( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, CLICK_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| |
| assertFalse( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, HOVER_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| |
| assertFalse( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, CLICK_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| |
| assertFalse( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, HOVER_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_INTERNAL_ERROR), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionSucceedsButDesNotRegisterUrisThatFailDomainValidation() |
| throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| Uri biddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| // Register uris with valid domains |
| Uri hoverUriSeller = mMockWebServerRule.uriForPath(HOVER_SELLER_PATH); |
| Uri clickUriBuyer = mMockWebServerRule.uriForPath(CLICK_BUYER_PATH); |
| |
| // Register uris with invalid domains by instantiating another mock server |
| MockWebServer differentServer = new MockWebServer(); |
| differentServer.play(); |
| Uri clickUriSeller = Uri.parse(differentServer.getUrl(CLICK_SELLER_PATH).toString()); |
| Uri hoverUriBuyer = Uri.parse(differentServer.getUrl(HOVER_BUYER_PATH).toString()); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) " |
| + "{\n" |
| + " registerAdBeacon('click_seller', '" |
| + clickUriSeller |
| + "');\n" |
| + " registerAdBeacon('hover_seller', '" |
| + hoverUriSeller |
| + "');\n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer ," |
| + "contextual_signals, custom_audience_signals) {\n" |
| + " registerAdBeacon('click_buyer', '" |
| + clickUriBuyer |
| + "');\n" |
| + " registerAdBeacon('hover_buyer', '" |
| + hoverUriBuyer |
| + "');\n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(biddingLogicUri) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(biddingLogicUri) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| // Count down callback + log interaction. |
| ReportImpressionTestCallback callback = |
| callReportImpression(adSelectionService, input, true); |
| |
| assertTrue(callback.mIsSuccess); |
| |
| // Check that seller click uri was not registered |
| assertFalse( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, CLICK_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| |
| // Check that seller hover uri was registered |
| assertTrue( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, HOVER_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| assertEquals( |
| hoverUriSeller, |
| mAdSelectionEntryDao.getRegisteredAdInteractionUri( |
| AD_SELECTION_ID, HOVER_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| |
| // Check that buyer click uri was registered |
| assertTrue( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, CLICK_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| assertEquals( |
| clickUriBuyer, |
| mAdSelectionEntryDao.getRegisteredAdInteractionUri( |
| AD_SELECTION_ID, CLICK_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| |
| // Check that buyer hover uri was not registered |
| assertFalse( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, HOVER_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| |
| RecordedRequest fetchRequest = server.takeRequest(); |
| assertEquals(mFetchJavaScriptPathSeller, fetchRequest.getPath()); |
| |
| List<String> notifications = |
| ImmutableList.of(server.takeRequest().getPath(), server.takeRequest().getPath()); |
| |
| assertThat(notifications).containsExactly(mSellerReportingPath, mBuyerReportingPath); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionSucceedsButDesNotRegisterMalformedUris() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| Uri biddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| // Register valid uris |
| Uri hoverUriSeller = mMockWebServerRule.uriForPath(HOVER_SELLER_PATH); |
| Uri clickUriBuyer = mMockWebServerRule.uriForPath(CLICK_BUYER_PATH); |
| |
| // Register malformed uris |
| Uri clickUriSeller = Uri.parse(CLICK_SELLER_PATH); |
| Uri hoverUriBuyer = Uri.parse(HOVER_BUYER_PATH); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) " |
| + "{\n" |
| + " registerAdBeacon('click_seller', '" |
| + clickUriSeller |
| + "');\n" |
| + " registerAdBeacon('hover_seller', '" |
| + hoverUriSeller |
| + "');\n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer ," |
| + "contextual_signals, custom_audience_signals) {\n" |
| + " registerAdBeacon('click_buyer', '" |
| + clickUriBuyer |
| + "');\n" |
| + " registerAdBeacon('hover_buyer', '" |
| + hoverUriBuyer |
| + "');\n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(biddingLogicUri) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(biddingLogicUri) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| // Count down callback + log interaction. |
| ReportImpressionTestCallback callback = |
| callReportImpression(adSelectionService, input, true); |
| |
| assertTrue(callback.mIsSuccess); |
| |
| // Check that seller click uri was not registered |
| assertFalse( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, CLICK_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| |
| // Check that seller hover uri was registered |
| assertTrue( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, HOVER_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| assertEquals( |
| hoverUriSeller, |
| mAdSelectionEntryDao.getRegisteredAdInteractionUri( |
| AD_SELECTION_ID, HOVER_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| |
| // Check that buyer click uri was registered |
| assertTrue( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, CLICK_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| assertEquals( |
| clickUriBuyer, |
| mAdSelectionEntryDao.getRegisteredAdInteractionUri( |
| AD_SELECTION_ID, CLICK_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| |
| // Check that buyer hover uri was not registered |
| assertFalse( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, HOVER_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| |
| RecordedRequest fetchRequest = server.takeRequest(); |
| assertEquals(mFetchJavaScriptPathSeller, fetchRequest.getPath()); |
| |
| List<String> notifications = |
| ImmutableList.of(server.takeRequest().getPath(), server.takeRequest().getPath()); |
| |
| assertThat(notifications).containsExactly(mSellerReportingPath, mBuyerReportingPath); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionOnlyRegisterSellerUrisWhenBuyerJSFails() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| Uri biddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| Uri clickUriSeller = mMockWebServerRule.uriForPath(CLICK_SELLER_PATH); |
| Uri hoverUriSeller = mMockWebServerRule.uriForPath(HOVER_SELLER_PATH); |
| Uri clickUriBuyer = mMockWebServerRule.uriForPath(CLICK_BUYER_PATH); |
| Uri hoverUriBuyer = mMockWebServerRule.uriForPath(HOVER_BUYER_PATH); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) " |
| + "{\n" |
| + " registerAdBeacon('click_seller', '" |
| + clickUriSeller |
| + "');\n" |
| + " registerAdBeacon('hover_seller', '" |
| + hoverUriSeller |
| + "');\n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer ," |
| + "contextual_signals, custom_audience_signals) {\n" |
| + " registerAdBeacon('click_buyer', '" |
| + clickUriBuyer |
| + "');\n" |
| + " registerAdBeacon('hover_buyer', '" |
| + hoverUriBuyer |
| + "');\n" |
| + " return {'status': -1, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(biddingLogicUri) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(biddingLogicUri) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| ReportImpressionTestCallback callback = callReportImpression(adSelectionService, input); |
| |
| assertFalse(callback.mIsSuccess); |
| |
| // Check that database has correct seller registered events |
| assertTrue( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, CLICK_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| assertEquals( |
| clickUriSeller, |
| mAdSelectionEntryDao.getRegisteredAdInteractionUri( |
| AD_SELECTION_ID, CLICK_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, HOVER_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| assertEquals( |
| hoverUriSeller, |
| mAdSelectionEntryDao.getRegisteredAdInteractionUri( |
| AD_SELECTION_ID, HOVER_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| |
| // Check that buyer events were not registered |
| assertFalse( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, CLICK_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| |
| assertFalse( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, HOVER_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| |
| assertEquals(callback.mFledgeErrorResponse.getStatusCode(), STATUS_INTERNAL_ERROR); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_INTERNAL_ERROR), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionDoesNotRegisterUrisWhenSellerJSFails() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| Uri biddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| Uri clickUriSeller = mMockWebServerRule.uriForPath(CLICK_SELLER_PATH); |
| Uri hoverUriSeller = mMockWebServerRule.uriForPath(HOVER_SELLER_PATH); |
| Uri clickUriBuyer = mMockWebServerRule.uriForPath(CLICK_BUYER_PATH); |
| Uri hoverUriBuyer = mMockWebServerRule.uriForPath(HOVER_BUYER_PATH); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) " |
| + "{\n" |
| + " registerAdBeacon('click_seller', '" |
| + clickUriSeller |
| + "');\n" |
| + " registerAdBeacon('hover_seller', '" |
| + hoverUriSeller |
| + "');\n" |
| + " return {'status': -1, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer ," |
| + "contextual_signals, custom_audience_signals) {\n" |
| + " registerAdBeacon('click_buyer', '" |
| + clickUriBuyer |
| + "');\n" |
| + " registerAdBeacon('hover_buyer', '" |
| + hoverUriBuyer |
| + "');\n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(biddingLogicUri) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(biddingLogicUri) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| ReportImpressionTestCallback callback = callReportImpression(adSelectionService, input); |
| |
| assertFalse(callback.mIsSuccess); |
| |
| // Check that no events were registered |
| assertFalse( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, CLICK_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| |
| assertFalse( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, HOVER_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| |
| assertFalse( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, CLICK_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| |
| assertFalse( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, HOVER_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| |
| assertEquals(callback.mFledgeErrorResponse.getStatusCode(), STATUS_INTERNAL_ERROR); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_INTERNAL_ERROR), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionDoesNotRegisterMoreThanMaxInteractionUrisFromPhFlag() |
| throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| Uri biddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| Uri clickUriSeller = mMockWebServerRule.uriForPath(CLICK_SELLER_PATH); |
| Uri hoverUriSeller = mMockWebServerRule.uriForPath(HOVER_SELLER_PATH); |
| Uri clickUriBuyer = mMockWebServerRule.uriForPath(CLICK_BUYER_PATH); |
| Uri hoverUriBuyer = mMockWebServerRule.uriForPath(HOVER_BUYER_PATH); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) " |
| + "{\n" |
| + " registerAdBeacon('click_seller', '" |
| + clickUriSeller |
| + "');\n" |
| + " registerAdBeacon('hover_seller', '" |
| + hoverUriSeller |
| + "');\n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer ," |
| + "contextual_signals, custom_audience_signals) {\n" |
| + " registerAdBeacon('click_buyer', '" |
| + clickUriBuyer |
| + "');\n" |
| + " registerAdBeacon('hover_buyer', '" |
| + hoverUriBuyer |
| + "');\n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(biddingLogicUri) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(biddingLogicUri) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| long maxRegisteredAdBeacons = 3; |
| |
| // Create new flag with overridden value so that only 3 entries can be registered |
| Flags flagsWithSmallerMaxEventUris = |
| new FlagsWithEnrollmentCheckEnabledSwitch(false) { |
| @Override |
| public long getFledgeReportImpressionMaxRegisteredAdBeaconsTotalCount() { |
| return maxRegisteredAdBeacons; |
| } |
| }; |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| flagsWithSmallerMaxEventUris, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| // Check that table starts as empty |
| assertEquals(0, mAdSelectionEntryDao.getTotalNumRegisteredAdInteractions()); |
| |
| // Count down callback + log interaction. |
| ReportImpressionTestCallback callback = |
| callReportImpression(adSelectionService, input, true); |
| |
| assertTrue(callback.mIsSuccess); |
| |
| // Check that only the first seller event uri pairing was registered |
| assertTrue( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, CLICK_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| assertEquals( |
| clickUriSeller, |
| mAdSelectionEntryDao.getRegisteredAdInteractionUri( |
| AD_SELECTION_ID, CLICK_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| |
| // Assert that only 3 entries were registered |
| assertEquals( |
| maxRegisteredAdBeacons, mAdSelectionEntryDao.getTotalNumRegisteredAdInteractions()); |
| |
| RecordedRequest fetchRequest = server.takeRequest(); |
| assertEquals(mFetchJavaScriptPathSeller, fetchRequest.getPath()); |
| |
| List<String> notifications = |
| ImmutableList.of(server.takeRequest().getPath(), server.takeRequest().getPath()); |
| |
| assertThat(notifications).containsExactly(mSellerReportingPath, mBuyerReportingPath); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void |
| testReportImpressionSucceedsButDesNotRegisterUrisWithInteractionKeySizeThatExceedsMax() |
| throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| Uri biddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| Uri clickUriSeller = mMockWebServerRule.uriForPath(CLICK_SELLER_PATH); |
| Uri hoverUriSeller = mMockWebServerRule.uriForPath(HOVER_SELLER_PATH); |
| Uri clickUriBuyer = mMockWebServerRule.uriForPath(CLICK_BUYER_PATH); |
| Uri hoverUriBuyer = mMockWebServerRule.uriForPath(HOVER_BUYER_PATH); |
| |
| // Override flags to return a smaller max interaction key size |
| Flags flagsWithSmallerMaxInteractionKeySize = |
| new FlagsWithEnrollmentCheckEnabledSwitch(false) { |
| @Override |
| public long |
| getFledgeReportImpressionRegisteredAdBeaconsMaxInteractionKeySizeB() { |
| return 15; |
| } |
| }; |
| |
| String longerClickEventSeller = "click_seller_12345"; |
| String longerHoverEventBuyer = "hover_buyer_12345"; |
| |
| // Instantiate JS with seller interaction longer than max size set in flags |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) " |
| + "{\n" |
| + " registerAdBeacon('" |
| + longerClickEventSeller |
| + "', '" |
| + clickUriSeller |
| + "');\n" |
| + " registerAdBeacon('hover_seller', '" |
| + hoverUriSeller |
| + "');\n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer ," |
| + "contextual_signals, custom_audience_signals) {\n" |
| + " registerAdBeacon('click_buyer', '" |
| + clickUriBuyer |
| + "');\n" |
| + " registerAdBeacon('" |
| + longerHoverEventBuyer |
| + "', '" |
| + hoverUriBuyer |
| + "');\n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(biddingLogicUri) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(biddingLogicUri) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| flagsWithSmallerMaxInteractionKeySize, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| // Count down callback + log interaction. |
| ReportImpressionTestCallback callback = |
| callReportImpression(adSelectionService, input, true); |
| |
| assertTrue(callback.mIsSuccess); |
| |
| // Check that seller click uri was not registered |
| assertFalse( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, |
| longerClickEventSeller, |
| FLAG_REPORTING_DESTINATION_SELLER)); |
| |
| // Check that seller hover uri was registered |
| assertTrue( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, HOVER_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| assertEquals( |
| hoverUriSeller, |
| mAdSelectionEntryDao.getRegisteredAdInteractionUri( |
| AD_SELECTION_ID, HOVER_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| |
| // Check that buyer click uri was registered |
| assertTrue( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, CLICK_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| assertEquals( |
| clickUriBuyer, |
| mAdSelectionEntryDao.getRegisteredAdInteractionUri( |
| AD_SELECTION_ID, CLICK_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| |
| // Check that buyer hover uri was not registered |
| assertFalse( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, longerHoverEventBuyer, FLAG_REPORTING_DESTINATION_BUYER)); |
| |
| RecordedRequest fetchRequest = server.takeRequest(); |
| assertEquals(mFetchJavaScriptPathSeller, fetchRequest.getPath()); |
| |
| List<String> notifications = |
| ImmutableList.of(server.takeRequest().getPath(), server.takeRequest().getPath()); |
| |
| assertThat(notifications).containsExactly(mSellerReportingPath, mBuyerReportingPath); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionWithRevokedUserConsentSuccess() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| doThrow(new FilterException(new ConsentManager.RevokedConsentException())) |
| .when(mAdSelectionServiceFilter) |
| .filterRequest( |
| mSeller, |
| TEST_PACKAGE_NAME, |
| true, |
| true, |
| CALLER_UID, |
| AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION, |
| Throttler.ApiKey.FLEDGE_API_REPORT_IMPRESSIONS); |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| new Dispatcher() { |
| @Override |
| public MockResponse dispatch(RecordedRequest request) { |
| throw new IllegalStateException( |
| "No calls should be made without user consent"); |
| } |
| }); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| ReportImpressionTestCallback callback = callReportImpression(adSelectionService, input); |
| |
| assertTrue(callback.mIsSuccess); |
| assertEquals(0, server.getRequestCount()); |
| |
| // Confirm a duplicate log entry does not exist. |
| // AdSelectionServiceFilter ensures the failing assertion is logged internally. |
| verify(mAdServicesLoggerMock, never()) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_USER_CONSENT_REVOKED), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionFailsWhenReportResultTakesTooLong() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| String jsWaitMoreThanAllowed = |
| insertJsWait(2 * mFlags.getReportImpressionOverallTimeoutMs()); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + jsWaitMoreThanAllowed |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| ReportImpressionTestCallback callback = callReportImpression(adSelectionService, input); |
| |
| assertFalse(callback.mIsSuccess); |
| assertEquals(callback.mFledgeErrorResponse.getStatusCode(), STATUS_INTERNAL_ERROR); |
| assertTrue(callback.mFledgeErrorResponse.getErrorMessage().contains(TIMEOUT_MESSAGE)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_INTERNAL_ERROR), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionFailsWhenReportWinTakesTooLong() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| String jsWaitMoreThanAllowed = |
| insertJsWait(2 * mFlags.getReportImpressionOverallTimeoutMs()); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + jsWaitMoreThanAllowed |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| ReportImpressionTestCallback callback = callReportImpression(adSelectionService, input); |
| |
| assertFalse(callback.mIsSuccess); |
| assertEquals(callback.mFledgeErrorResponse.getStatusCode(), STATUS_INTERNAL_ERROR); |
| assertTrue(callback.mFledgeErrorResponse.getErrorMessage().contains(TIMEOUT_MESSAGE)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_INTERNAL_ERROR), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionFailsWhenOverallJSTimesOut() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| String jsWaitMoreThanAllowed = |
| insertJsWait((long) (.25 * mFlags.getReportImpressionOverallTimeoutMs())); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + jsWaitMoreThanAllowed |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + jsWaitMoreThanAllowed |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse() |
| .setBody(sellerDecisionLogicJs) |
| .throttleBody( |
| mBytesPerPeriod, |
| (long) (.5 * mFlags.getReportImpressionOverallTimeoutMs()), |
| TimeUnit.MILLISECONDS), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| ReportImpressionTestCallback callback = callReportImpression(adSelectionService, input); |
| |
| assertFalse(callback.mIsSuccess); |
| assertEquals(callback.mFledgeErrorResponse.getStatusCode(), STATUS_INTERNAL_ERROR); |
| assertTrue(callback.mFledgeErrorResponse.getErrorMessage().contains(TIMEOUT_MESSAGE)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_INTERNAL_ERROR), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionFailsWhenJSFetchTakesTooLong() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse() |
| .setBody(sellerDecisionLogicJs) |
| .throttleBody( |
| mBytesPerPeriod, |
| mFlags.getReportImpressionOverallTimeoutMs(), |
| TimeUnit.MILLISECONDS), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| ReportImpressionTestCallback callback = callReportImpression(adSelectionService, input); |
| |
| assertFalse(callback.mIsSuccess); |
| assertEquals(callback.mFledgeErrorResponse.getStatusCode(), STATUS_INTERNAL_ERROR); |
| assertTrue(callback.mFledgeErrorResponse.getErrorMessage().contains(TIMEOUT_MESSAGE)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_INTERNAL_ERROR), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionFailsWithInvalidAdSelectionId() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput request = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(INCORRECT_AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| ReportImpressionTestCallback callback = callReportImpression(adSelectionService, request); |
| |
| assertFalse(callback.mIsSuccess); |
| assertEquals(callback.mFledgeErrorResponse.getStatusCode(), STATUS_INVALID_ARGUMENT); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_INVALID_ARGUMENT), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionBadSellerJavascriptFailsWithInternalError() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| String invalidSellerDecisionLogicJsMissingCurlyBracket = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': 'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(invalidSellerDecisionLogicJsMissingCurlyBracket), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput request = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| ReportImpressionTestCallback callback = callReportImpression(adSelectionService, request); |
| |
| assertFalse(callback.mIsSuccess); |
| assertEquals(callback.mFledgeErrorResponse.getStatusCode(), STATUS_INTERNAL_ERROR); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_INTERNAL_ERROR), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionBadBuyerJavascriptFailsWithInternalError() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String inValidBuyerDecisionLogicJsMissingCurlyBracket = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': 'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setBuyerDecisionLogicJs(inValidBuyerDecisionLogicJsMissingCurlyBracket) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput request = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| ReportImpressionTestCallback callback = callReportImpression(adSelectionService, request); |
| |
| assertFalse(callback.mIsSuccess); |
| assertEquals(callback.mFledgeErrorResponse.getStatusCode(), STATUS_INTERNAL_ERROR); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_INTERNAL_ERROR), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionUseDevOverrideForSellerJS() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| // There is no need to fetch JS |
| new MockResponse(), new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| // Set dev override for this AdSelection |
| |
| DBAdSelectionOverride adSelectionOverride = |
| DBAdSelectionOverride.builder() |
| .setAdSelectionConfigId( |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId( |
| adSelectionConfig)) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setDecisionLogicJS(sellerDecisionLogicJs) |
| .setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.toString()) |
| .build(); |
| mAdSelectionEntryDao.persistAdSelectionOverride(adSelectionOverride); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| // Count down callback + log interaction. |
| ReportImpressionTestCallback callback = |
| callReportImpression(adSelectionService, input, true); |
| |
| assertTrue(callback.mIsSuccess); |
| List<String> notifications = |
| ImmutableList.of(server.takeRequest().getPath(), server.takeRequest().getPath()); |
| |
| assertThat(notifications).containsExactly(mSellerReportingPath, mBuyerReportingPath); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionUseDevOverrideForSellerJSSuccessfullyRegistersEventUris() |
| throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| Uri clickUriSeller = mMockWebServerRule.uriForPath(CLICK_SELLER_PATH); |
| Uri hoverUriSeller = mMockWebServerRule.uriForPath(HOVER_SELLER_PATH); |
| Uri clickUriBuyer = mMockWebServerRule.uriForPath(CLICK_BUYER_PATH); |
| Uri hoverUriBuyer = mMockWebServerRule.uriForPath(HOVER_BUYER_PATH); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) " |
| + "{\n" |
| + " registerAdBeacon('click_seller', '" |
| + clickUriSeller |
| + "');\n" |
| + " registerAdBeacon('hover_seller', '" |
| + hoverUriSeller |
| + "');\n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer ," |
| + "contextual_signals, custom_audience_signals) {\n" |
| + " registerAdBeacon('click_buyer', '" |
| + clickUriBuyer |
| + "');\n" |
| + " registerAdBeacon('hover_buyer', '" |
| + hoverUriBuyer |
| + "');\n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| // There is no need to fetch JS |
| new MockResponse(), new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| // Set dev override for this AdSelection |
| |
| DBAdSelectionOverride adSelectionOverride = |
| DBAdSelectionOverride.builder() |
| .setAdSelectionConfigId( |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId( |
| adSelectionConfig)) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setDecisionLogicJS(sellerDecisionLogicJs) |
| .setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.toString()) |
| .build(); |
| mAdSelectionEntryDao.persistAdSelectionOverride(adSelectionOverride); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| // Count down callback + log interaction. |
| ReportImpressionTestCallback callback = |
| callReportImpression(adSelectionService, input, true); |
| |
| assertTrue(callback.mIsSuccess); |
| |
| // Check that database has correct seller registered events |
| assertTrue( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, CLICK_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| assertEquals( |
| clickUriSeller, |
| mAdSelectionEntryDao.getRegisteredAdInteractionUri( |
| AD_SELECTION_ID, CLICK_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, HOVER_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| assertEquals( |
| hoverUriSeller, |
| mAdSelectionEntryDao.getRegisteredAdInteractionUri( |
| AD_SELECTION_ID, HOVER_EVENT_SELLER, FLAG_REPORTING_DESTINATION_SELLER)); |
| |
| // Check that database has correct buyer registered events |
| assertTrue( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, CLICK_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| assertEquals( |
| clickUriBuyer, |
| mAdSelectionEntryDao.getRegisteredAdInteractionUri( |
| AD_SELECTION_ID, CLICK_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesRegisteredAdInteractionExist( |
| AD_SELECTION_ID, HOVER_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| assertEquals( |
| hoverUriBuyer, |
| mAdSelectionEntryDao.getRegisteredAdInteractionUri( |
| AD_SELECTION_ID, HOVER_EVENT_BUYER, FLAG_REPORTING_DESTINATION_BUYER)); |
| |
| List<String> notifications = |
| ImmutableList.of(server.takeRequest().getPath(), server.takeRequest().getPath()); |
| |
| assertThat(notifications).containsExactly(mSellerReportingPath, mBuyerReportingPath); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void testOverrideAdSelectionConfigRemoteInfoSuccess() throws Exception { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| AdSelectionOverrideTestCallback callback = |
| callAddOverrideForSelectAds( |
| adSelectionService, |
| adSelectionConfig, |
| DUMMY_DECISION_LOGIC_JS, |
| DUMMY_TRUSTED_SCORING_SIGNALS); |
| |
| assertTrue(callback.mIsSuccess); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId( |
| adSelectionConfig), |
| TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(eq(SHORT_API_NAME_OVERRIDE), eq(STATUS_SUCCESS), anyInt()); |
| } |
| |
| @Test |
| public void testOverrideAdSelectionConfigRemoteInfoWithRevokedUserConsentSuccess() |
| throws Exception { |
| doReturn(AdServicesApiConsent.REVOKED).when(mConsentManagerMock).getConsent(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| AdSelectionOverrideTestCallback callback = |
| callAddOverrideForSelectAds( |
| adSelectionService, |
| adSelectionConfig, |
| DUMMY_DECISION_LOGIC_JS, |
| DUMMY_TRUSTED_SCORING_SIGNALS); |
| |
| assertTrue(callback.mIsSuccess); |
| assertFalse( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId( |
| adSelectionConfig), |
| TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(SHORT_API_NAME_OVERRIDE), eq(STATUS_USER_CONSENT_REVOKED), anyInt()); |
| } |
| |
| @Test |
| public void testOverrideAdSelectionConfigRemoteInfoFailsWithDevOptionsDisabled() { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| assertThrows( |
| SecurityException.class, |
| () -> |
| callAddOverrideForSelectAds( |
| adSelectionService, |
| adSelectionConfig, |
| DUMMY_DECISION_LOGIC_JS, |
| DUMMY_TRUSTED_SCORING_SIGNALS)); |
| |
| assertFalse( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId( |
| adSelectionConfig), |
| TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(SHORT_API_NAME_OVERRIDE), eq(STATUS_INTERNAL_ERROR), anyInt()); |
| } |
| |
| @Test |
| public void testRemoveAdSelectionConfigRemoteInfoOverrideSuccess() throws Exception { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| String adSelectionConfigId = |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig); |
| |
| DBAdSelectionOverride dbAdSelectionOverride = |
| DBAdSelectionOverride.builder() |
| .setAdSelectionConfigId(adSelectionConfigId) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS) |
| .setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.toString()) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId, TEST_PACKAGE_NAME)); |
| |
| AdSelectionOverrideTestCallback callback = |
| callRemoveOverride(adSelectionService, adSelectionConfig); |
| |
| assertTrue(callback.mIsSuccess); |
| assertFalse( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId, TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(SHORT_API_NAME_REMOVE_OVERRIDE), eq(STATUS_SUCCESS), anyInt()); |
| } |
| |
| @Test |
| public void testRemoveAdSelectionConfigRemoteInfoOverrideWithRevokedUserConsentSuccess() |
| throws Exception { |
| doReturn(AdServicesApiConsent.REVOKED).when(mConsentManagerMock).getConsent(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| String adSelectionConfigId = |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig); |
| |
| DBAdSelectionOverride dbAdSelectionOverride = |
| DBAdSelectionOverride.builder() |
| .setAdSelectionConfigId(adSelectionConfigId) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS) |
| .setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.toString()) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId, TEST_PACKAGE_NAME)); |
| |
| AdSelectionOverrideTestCallback callback = |
| callRemoveOverride(adSelectionService, adSelectionConfig); |
| |
| assertTrue(callback.mIsSuccess); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId, TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(SHORT_API_NAME_REMOVE_OVERRIDE), |
| eq(STATUS_USER_CONSENT_REVOKED), |
| anyInt()); |
| } |
| |
| @Test |
| public void testRemoveAdSelectionConfigRemoteInfoOverrideFailsWithDevOptionsDisabled() { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| String adSelectionConfigId = |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig); |
| |
| DBAdSelectionOverride dbAdSelectionOverride = |
| DBAdSelectionOverride.builder() |
| .setAdSelectionConfigId(adSelectionConfigId) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS) |
| .setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.toString()) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId, TEST_PACKAGE_NAME)); |
| |
| assertThrows( |
| SecurityException.class, |
| () -> callRemoveOverride(adSelectionService, adSelectionConfig)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId, TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(SHORT_API_NAME_REMOVE_OVERRIDE), eq(STATUS_INTERNAL_ERROR), anyInt()); |
| } |
| |
| @Test |
| public void testRemoveAdSelectionConfigRemoteInfoOverrideDoesNotDeleteWithIncorrectPackageName() |
| throws Exception { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| String incorrectPackageName = "com.google.ppapi.test.incorrect"; |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(incorrectPackageName) |
| .build()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| String adSelectionConfigId = |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig); |
| |
| DBAdSelectionOverride dbAdSelectionOverride = |
| DBAdSelectionOverride.builder() |
| .setAdSelectionConfigId(adSelectionConfigId) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS) |
| .setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.toString()) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId, TEST_PACKAGE_NAME)); |
| |
| AdSelectionOverrideTestCallback callback = |
| callRemoveOverride(adSelectionService, adSelectionConfig); |
| |
| assertTrue(callback.mIsSuccess); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId, TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(SHORT_API_NAME_REMOVE_OVERRIDE), eq(STATUS_SUCCESS), anyInt()); |
| } |
| |
| @Test |
| public void testResetAllAdSelectionConfigRemoteOverridesDoesNotDeleteWithIncorrectPackageName() |
| throws Exception { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| String incorrectPackageName = "com.google.ppapi.test.incorrect"; |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(incorrectPackageName) |
| .build()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionConfig adSelectionConfig1 = mAdSelectionConfigBuilder.build(); |
| AdSelectionConfig adSelectionConfig2 = |
| mAdSelectionConfigBuilder |
| .setSeller(AdTechIdentifier.fromString("adidas.com")) |
| .setDecisionLogicUri(Uri.parse("https://adidas.com/decisoin_logic_uri")) |
| .build(); |
| AdSelectionConfig adSelectionConfig3 = |
| mAdSelectionConfigBuilder |
| .setSeller(AdTechIdentifier.fromString("nike.com")) |
| .setDecisionLogicUri(Uri.parse("https://nike.com/decisoin_logic_uri")) |
| .build(); |
| |
| String adSelectionConfigId1 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig1); |
| String adSelectionConfigId2 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig2); |
| String adSelectionConfigId3 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig3); |
| |
| DBAdSelectionOverride dbAdSelectionOverride1 = |
| DBAdSelectionOverride.builder() |
| .setAdSelectionConfigId(adSelectionConfigId1) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS) |
| .setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.toString()) |
| .build(); |
| |
| DBAdSelectionOverride dbAdSelectionOverride2 = |
| DBAdSelectionOverride.builder() |
| .setAdSelectionConfigId(adSelectionConfigId2) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS) |
| .setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.toString()) |
| .build(); |
| |
| DBAdSelectionOverride dbAdSelectionOverride3 = |
| DBAdSelectionOverride.builder() |
| .setAdSelectionConfigId(adSelectionConfigId3) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS) |
| .setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.toString()) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride1); |
| mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride2); |
| mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride3); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId1, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId2, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId3, TEST_PACKAGE_NAME)); |
| |
| AdSelectionOverrideTestCallback callback = callResetAllOverrides(adSelectionService); |
| |
| assertTrue(callback.mIsSuccess); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId1, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId2, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId3, TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(SHORT_API_NAME_RESET_ALL_OVERRIDES), eq(STATUS_SUCCESS), anyInt()); |
| } |
| |
| @Test |
| public void testResetAllAdSelectionConfigRemoteOverridesSuccess() throws Exception { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionConfig adSelectionConfig1 = mAdSelectionConfigBuilder.build(); |
| AdSelectionConfig adSelectionConfig2 = |
| mAdSelectionConfigBuilder |
| .setSeller(AdTechIdentifier.fromString("adidas.com")) |
| .setDecisionLogicUri(Uri.parse("https://adidas.com/decisoin_logic_uri")) |
| .build(); |
| AdSelectionConfig adSelectionConfig3 = |
| mAdSelectionConfigBuilder |
| .setSeller(AdTechIdentifier.fromString("nike.com")) |
| .setDecisionLogicUri(Uri.parse("https://nike.com/decisoin_logic_uri")) |
| .build(); |
| |
| String adSelectionConfigId1 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig1); |
| String adSelectionConfigId2 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig2); |
| String adSelectionConfigId3 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig3); |
| |
| DBAdSelectionOverride dbAdSelectionOverride1 = |
| DBAdSelectionOverride.builder() |
| .setAdSelectionConfigId(adSelectionConfigId1) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS) |
| .setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.toString()) |
| .build(); |
| |
| DBAdSelectionOverride dbAdSelectionOverride2 = |
| DBAdSelectionOverride.builder() |
| .setAdSelectionConfigId(adSelectionConfigId2) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS) |
| .setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.toString()) |
| .build(); |
| |
| DBAdSelectionOverride dbAdSelectionOverride3 = |
| DBAdSelectionOverride.builder() |
| .setAdSelectionConfigId(adSelectionConfigId3) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS) |
| .setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.toString()) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride1); |
| mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride2); |
| mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride3); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId1, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId2, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId3, TEST_PACKAGE_NAME)); |
| |
| AdSelectionOverrideTestCallback callback = callResetAllOverrides(adSelectionService); |
| |
| assertTrue(callback.mIsSuccess); |
| |
| assertFalse( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId1, TEST_PACKAGE_NAME)); |
| assertFalse( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId2, TEST_PACKAGE_NAME)); |
| assertFalse( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId3, TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(SHORT_API_NAME_RESET_ALL_OVERRIDES), eq(STATUS_SUCCESS), anyInt()); |
| } |
| |
| @Test |
| public void testResetAllAdSelectionConfigRemoteOverridesWithRevokedUserConsentSuccess() |
| throws Exception { |
| doReturn(AdServicesApiConsent.REVOKED).when(mConsentManagerMock).getConsent(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionConfig adSelectionConfig1 = mAdSelectionConfigBuilder.build(); |
| AdSelectionConfig adSelectionConfig2 = |
| mAdSelectionConfigBuilder |
| .setSeller(AdTechIdentifier.fromString("adidas.com")) |
| .setDecisionLogicUri(Uri.parse("https://adidas.com/decisoin_logic_uri")) |
| .build(); |
| AdSelectionConfig adSelectionConfig3 = |
| mAdSelectionConfigBuilder |
| .setSeller(AdTechIdentifier.fromString("nike.com")) |
| .setDecisionLogicUri(Uri.parse("https://nike.com/decisoin_logic_uri")) |
| .build(); |
| |
| String adSelectionConfigId1 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig1); |
| String adSelectionConfigId2 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig2); |
| String adSelectionConfigId3 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig3); |
| |
| DBAdSelectionOverride dbAdSelectionOverride1 = |
| DBAdSelectionOverride.builder() |
| .setAdSelectionConfigId(adSelectionConfigId1) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS) |
| .setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.toString()) |
| .build(); |
| |
| DBAdSelectionOverride dbAdSelectionOverride2 = |
| DBAdSelectionOverride.builder() |
| .setAdSelectionConfigId(adSelectionConfigId2) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS) |
| .setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.toString()) |
| .build(); |
| |
| DBAdSelectionOverride dbAdSelectionOverride3 = |
| DBAdSelectionOverride.builder() |
| .setAdSelectionConfigId(adSelectionConfigId3) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS) |
| .setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.toString()) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride1); |
| mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride2); |
| mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride3); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId1, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId2, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId3, TEST_PACKAGE_NAME)); |
| |
| AdSelectionOverrideTestCallback callback = callResetAllOverrides(adSelectionService); |
| |
| assertTrue(callback.mIsSuccess); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId1, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId2, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId3, TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(SHORT_API_NAME_RESET_ALL_OVERRIDES), |
| eq(STATUS_USER_CONSENT_REVOKED), |
| anyInt()); |
| } |
| |
| @Test |
| public void testResetAllAdSelectionConfigRemoteOverridesFailsWithDevOptionsDisabled() { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionConfig adSelectionConfig1 = mAdSelectionConfigBuilder.build(); |
| AdSelectionConfig adSelectionConfig2 = |
| mAdSelectionConfigBuilder |
| .setSeller(AdTechIdentifier.fromString("adidas.com")) |
| .setDecisionLogicUri(Uri.parse("https://adidas.com/decisoin_logic_uri")) |
| .build(); |
| AdSelectionConfig adSelectionConfig3 = |
| mAdSelectionConfigBuilder |
| .setSeller(AdTechIdentifier.fromString("nike.com")) |
| .setDecisionLogicUri(Uri.parse("https://nike.com/decisoin_logic_uri")) |
| .build(); |
| |
| String adSelectionConfigId1 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig1); |
| String adSelectionConfigId2 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig2); |
| String adSelectionConfigId3 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig3); |
| |
| DBAdSelectionOverride dbAdSelectionOverride1 = |
| DBAdSelectionOverride.builder() |
| .setAdSelectionConfigId(adSelectionConfigId1) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS) |
| .setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.toString()) |
| .build(); |
| |
| DBAdSelectionOverride dbAdSelectionOverride2 = |
| DBAdSelectionOverride.builder() |
| .setAdSelectionConfigId(adSelectionConfigId2) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS) |
| .setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.toString()) |
| .build(); |
| |
| DBAdSelectionOverride dbAdSelectionOverride3 = |
| DBAdSelectionOverride.builder() |
| .setAdSelectionConfigId(adSelectionConfigId3) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS) |
| .setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.toString()) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride1); |
| mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride2); |
| mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride3); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId1, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId2, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId3, TEST_PACKAGE_NAME)); |
| |
| assertThrows(SecurityException.class, () -> callResetAllOverrides(adSelectionService)); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId1, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId2, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| adSelectionConfigId3, TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(SHORT_API_NAME_RESET_ALL_OVERRIDES), |
| eq(STATUS_INTERNAL_ERROR), |
| anyInt()); |
| } |
| |
| @Test |
| public void testCloseJSScriptEngineConnectionAtShutDown() { |
| JSScriptEngine jsScriptEngineMock = mock(JSScriptEngine.class); |
| doReturn(jsScriptEngineMock).when(() -> JSScriptEngine.getInstance(any())); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| adSelectionService.destroy(); |
| verify(jsScriptEngineMock).shutdown(); |
| } |
| |
| @Test |
| public void testReportImpressionForegroundCheckEnabledFails_throwsException() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| doThrow(new FilterException(new WrongCallingApplicationStateException())) |
| .when(mAdSelectionServiceFilter) |
| .filterRequest( |
| mSeller, |
| TEST_PACKAGE_NAME, |
| true, |
| true, |
| CALLER_UID, |
| AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION, |
| Throttler.ApiKey.FLEDGE_API_REPORT_IMPRESSIONS); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput request = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(INCORRECT_AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| ReportImpressionTestCallback callback = callReportImpression(adSelectionService, request); |
| |
| // The call fails because there is no ad selection with the given ID |
| assertFalse(callback.mIsSuccess); |
| assertEquals( |
| AdServicesStatusUtils.STATUS_BACKGROUND_CALLER, |
| callback.mFledgeErrorResponse.getStatusCode()); |
| assertEquals( |
| AdServicesStatusUtils.ILLEGAL_STATE_BACKGROUND_CALLER_ERROR_MESSAGE, |
| callback.mFledgeErrorResponse.getErrorMessage()); |
| } |
| |
| @Test |
| public void testOverrideAdSelectionForegroundCheckEnabledFails_throwsException() |
| throws Exception { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| doThrow(new WrongCallingApplicationStateException()) |
| .when(mAppImportanceFilterMock) |
| .assertCallerIsInForeground( |
| Process.myUid(), |
| AD_SERVICES_API_CALLED__API_NAME__OVERRIDE_AD_SELECTION_CONFIG_REMOTE_INFO, |
| null); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| AdSelectionOverrideTestCallback callback = |
| callAddOverrideForSelectAds( |
| adSelectionService, |
| adSelectionConfig, |
| DUMMY_DECISION_LOGIC_JS, |
| DUMMY_TRUSTED_SCORING_SIGNALS); |
| |
| // The call fails because there is no ad selection with the given ID |
| assertFalse(callback.mIsSuccess); |
| assertEquals( |
| AdServicesStatusUtils.STATUS_BACKGROUND_CALLER, |
| callback.mFledgeErrorResponse.getStatusCode()); |
| assertEquals( |
| AdServicesStatusUtils.ILLEGAL_STATE_BACKGROUND_CALLER_ERROR_MESSAGE, |
| callback.mFledgeErrorResponse.getErrorMessage()); |
| } |
| |
| @Test |
| public void testOverrideAdSelectionForegroundCheckDisabled_acceptBackgroundApp() |
| throws Exception { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| doThrow(new WrongCallingApplicationStateException()) |
| .when(mAppImportanceFilterMock) |
| .assertCallerIsInForeground( |
| Process.myUid(), |
| AD_SERVICES_API_CALLED__API_NAME__OVERRIDE_AD_SELECTION_CONFIG_REMOTE_INFO, |
| null); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| FlagsWithOverriddenFledgeChecks.createFlagsWithFledgeChecksDisabled(), |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| AdSelectionOverrideTestCallback callback = |
| callAddOverrideForSelectAds( |
| adSelectionService, |
| adSelectionConfig, |
| DUMMY_DECISION_LOGIC_JS, |
| DUMMY_TRUSTED_SCORING_SIGNALS); |
| |
| assertTrue(callback.mIsSuccess); |
| } |
| |
| @Test |
| public void testRemoveOverrideForegroundCheckEnabledFails_throwsException() throws Exception { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| int apiName = |
| AD_SERVICES_API_CALLED__API_NAME__REMOVE_AD_SELECTION_CONFIG_REMOTE_INFO_OVERRIDE; |
| doThrow(new WrongCallingApplicationStateException()) |
| .when(mAppImportanceFilterMock) |
| .assertCallerIsInForeground(Process.myUid(), apiName, null); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| AdSelectionOverrideTestCallback callback = |
| callRemoveOverride(adSelectionService, adSelectionConfig); |
| |
| // The call fails because there is no ad selection with the given ID |
| assertFalse(callback.mIsSuccess); |
| assertEquals( |
| AdServicesStatusUtils.STATUS_BACKGROUND_CALLER, |
| callback.mFledgeErrorResponse.getStatusCode()); |
| assertEquals( |
| AdServicesStatusUtils.ILLEGAL_STATE_BACKGROUND_CALLER_ERROR_MESSAGE, |
| callback.mFledgeErrorResponse.getErrorMessage()); |
| } |
| |
| @Test |
| public void testRemoveOverrideForegroundCheckDisabled_acceptBackgroundApp() throws Exception { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| int apiName = |
| AD_SERVICES_API_CALLED__API_NAME__REMOVE_AD_SELECTION_CONFIG_REMOTE_INFO_OVERRIDE; |
| doThrow(new WrongCallingApplicationStateException()) |
| .when(mAppImportanceFilterMock) |
| .assertCallerIsInForeground(Process.myUid(), apiName, null); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| FlagsWithOverriddenFledgeChecks.createFlagsWithFledgeChecksDisabled(), |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| AdSelectionOverrideTestCallback callback = |
| callRemoveOverride(adSelectionService, adSelectionConfig); |
| |
| assertTrue(callback.mIsSuccess); |
| } |
| |
| @Test |
| public void testResetAllOverridesForegroundCheckEnabledFails_throwsException() |
| throws Exception { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| int apiName = |
| AD_SERVICES_API_CALLED__API_NAME__RESET_ALL_AD_SELECTION_CONFIG_REMOTE_OVERRIDES; |
| doThrow(new WrongCallingApplicationStateException()) |
| .when(mAppImportanceFilterMock) |
| .assertCallerIsInForeground(Process.myUid(), apiName, null); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionOverrideTestCallback callback = callResetAllOverrides(adSelectionService); |
| |
| // The call fails because there is no ad selection with the given ID |
| assertFalse(callback.mIsSuccess); |
| assertEquals( |
| AdServicesStatusUtils.STATUS_BACKGROUND_CALLER, |
| callback.mFledgeErrorResponse.getStatusCode()); |
| assertEquals( |
| AdServicesStatusUtils.ILLEGAL_STATE_BACKGROUND_CALLER_ERROR_MESSAGE, |
| callback.mFledgeErrorResponse.getErrorMessage()); |
| } |
| |
| @Test |
| public void testResetAllOverridesForegroundCheckDisabled_acceptBackgroundApp() |
| throws Exception { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| int apiName = |
| AD_SERVICES_API_CALLED__API_NAME__RESET_ALL_AD_SELECTION_CONFIG_REMOTE_OVERRIDES; |
| doThrow(new WrongCallingApplicationStateException()) |
| .when(mAppImportanceFilterMock) |
| .assertCallerIsInForeground(Process.myUid(), apiName, null); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| FlagsWithOverriddenFledgeChecks.createFlagsWithFledgeChecksDisabled(), |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionOverrideTestCallback callback = callResetAllOverrides(adSelectionService); |
| |
| assertTrue(callback.mIsSuccess); |
| } |
| |
| @Test |
| public void testReportImpressionFailsWithInvalidPackageName() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| String otherPackageName = CommonFixture.TEST_PACKAGE_NAME + "incorrectPackage"; |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| doThrow(new FilterException(new FledgeAuthorizationFilter.CallerMismatchException())) |
| .when(mAdSelectionServiceFilter) |
| .filterRequest( |
| mSeller, |
| otherPackageName, |
| true, |
| true, |
| CALLER_UID, |
| AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION, |
| Throttler.ApiKey.FLEDGE_API_REPORT_IMPRESSIONS); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(otherPackageName) |
| .build(); |
| |
| ReportImpressionTestCallback callback = callReportImpression(adSelectionService, input); |
| |
| assertFalse(callback.mIsSuccess); |
| assertEquals(callback.mFledgeErrorResponse.getStatusCode(), STATUS_UNAUTHORIZED); |
| assertEquals( |
| callback.mFledgeErrorResponse.getErrorMessage(), |
| AdServicesStatusUtils |
| .SECURITY_EXCEPTION_CALLER_NOT_ALLOWED_ON_BEHALF_ERROR_MESSAGE); |
| } |
| |
| @Test |
| public void testReportImpressionFailsWhenAppCannotUsePPApi() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| doThrow(new FilterException(new FledgeAuthorizationFilter.AdTechNotAllowedException())) |
| .when(mAdSelectionServiceFilter) |
| .filterRequest( |
| mSeller, |
| TEST_PACKAGE_NAME, |
| true, |
| true, |
| CALLER_UID, |
| AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION, |
| Throttler.ApiKey.FLEDGE_API_REPORT_IMPRESSIONS); |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| ReportImpressionTestCallback callback = callReportImpression(adSelectionService, input); |
| |
| assertFalse(callback.mIsSuccess); |
| assertEquals(STATUS_CALLER_NOT_ALLOWED, callback.mFledgeErrorResponse.getStatusCode()); |
| assertEquals( |
| AdServicesStatusUtils.SECURITY_EXCEPTION_CALLER_NOT_ALLOWED_ERROR_MESSAGE, |
| callback.mFledgeErrorResponse.getErrorMessage()); |
| |
| // Confirm a duplicate log entry does not exist. |
| // AdSelectionServiceFilter ensures the failing assertion is logged internally. |
| verify(mAdServicesLoggerMock, never()) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_CALLER_NOT_ALLOWED), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionFailsWhenAdTechFailsEnrollmentCheck() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| doThrow(new FilterException(new FledgeAuthorizationFilter.AdTechNotAllowedException())) |
| .when(mAdSelectionServiceFilter) |
| .filterRequest( |
| mSeller, |
| TEST_PACKAGE_NAME, |
| true, |
| true, |
| CALLER_UID, |
| AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION, |
| Throttler.ApiKey.FLEDGE_API_REPORT_IMPRESSIONS); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| ReportImpressionTestCallback callback = callReportImpression(adSelectionService, input); |
| |
| assertFalse(callback.mIsSuccess); |
| assertEquals(STATUS_CALLER_NOT_ALLOWED, callback.mFledgeErrorResponse.getStatusCode()); |
| assertEquals( |
| AdServicesStatusUtils.SECURITY_EXCEPTION_CALLER_NOT_ALLOWED_ERROR_MESSAGE, |
| callback.mFledgeErrorResponse.getErrorMessage()); |
| |
| // Confirm a duplicate log entry does not exist. |
| // AdSelectionServiceFilter ensures the failing assertion is logged internally. |
| Mockito.verify(mAdServicesLoggerMock, never()) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_CALLER_NOT_ALLOWED), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionSucceedsWhenAdTechPassesEnrollmentCheck() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| |
| // Reset flags to perform enrollment check |
| mFlags = new FlagsWithEnrollmentCheckEnabledSwitch(true); |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| doNothing() |
| .when(mAdSelectionServiceFilter) |
| .filterRequest( |
| mSeller, |
| TEST_PACKAGE_NAME, |
| true, |
| true, |
| CALLER_UID, |
| AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION, |
| Throttler.ApiKey.FLEDGE_API_REPORT_IMPRESSIONS); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| // Count down callback + log interaction. |
| ReportImpressionTestCallback callback = |
| callReportImpression(adSelectionService, input, true); |
| |
| assertTrue(callback.mIsSuccess); |
| RecordedRequest fetchRequest = server.takeRequest(); |
| assertEquals(mFetchJavaScriptPathSeller, fetchRequest.getPath()); |
| |
| List<String> notifications = |
| ImmutableList.of(server.takeRequest().getPath(), server.takeRequest().getPath()); |
| |
| assertThat(notifications).containsExactly(mSellerReportingPath, mBuyerReportingPath); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void testAdSelectionConfigInvalidSellerAndSellerUris() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| AdSelectionConfig invalidAdSelectionConfig = |
| AdSelectionConfigFixture.anAdSelectionConfigBuilder() |
| .setSeller(SELLER_VALID) |
| .setDecisionLogicUri(DECISION_LOGIC_URI_INCONSISTENT) |
| .build(); |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| ReportImpressionInput request = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(INCORRECT_AD_SELECTION_ID) |
| .setAdSelectionConfig(invalidAdSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| ReportImpressionTestCallback callback = callReportImpression(adSelectionService, request); |
| |
| assertFalse(callback.mIsSuccess); |
| |
| FledgeErrorResponse response = callback.mFledgeErrorResponse; |
| assertEquals( |
| "Error response code mismatch", STATUS_INVALID_ARGUMENT, response.getStatusCode()); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_INVALID_ARGUMENT), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionSuccessThrottledSubsequentCallFailure() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse(), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| Throttler.destroyExistingThrottler(); |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| // First call should succeed |
| // Count down callback + log interaction. |
| ReportImpressionTestCallback callbackFirstCall = |
| callReportImpression(adSelectionService, input, true); |
| |
| doThrow(new FilterException(new LimitExceededException(RATE_LIMIT_REACHED_ERROR_MESSAGE))) |
| .when(mAdSelectionServiceFilter) |
| .filterRequest( |
| mSeller, |
| TEST_PACKAGE_NAME, |
| true, |
| true, |
| CALLER_UID, |
| AdServicesStatsLog.AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION, |
| Throttler.ApiKey.FLEDGE_API_REPORT_IMPRESSIONS); |
| |
| // Immediately made subsequent call should fail |
| ReportImpressionTestCallback callbackSubsequentCall = |
| callReportImpression(adSelectionService, input); |
| |
| assertTrue(callbackFirstCall.mIsSuccess); |
| RecordedRequest fetchRequest = server.takeRequest(); |
| assertEquals(mFetchJavaScriptPathSeller, fetchRequest.getPath()); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| |
| assertFalse(callbackSubsequentCall.mIsSuccess); |
| assertEquals( |
| STATUS_RATE_LIMIT_REACHED, |
| callbackSubsequentCall.mFledgeErrorResponse.getStatusCode()); |
| assertEquals( |
| callbackSubsequentCall.mFledgeErrorResponse.getErrorMessage(), |
| RATE_LIMIT_REACHED_ERROR_MESSAGE); |
| resetThrottlerToNoRateLimits(); |
| } |
| |
| @Test |
| public void testReportImpressionDoestNotReportWhenUrisDoNotMatchDomain() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| // Instantiate a server with different domain from buyer and seller for reporting |
| MockWebServer reportingServer = new MockWebServer(); |
| reportingServer.play(); |
| Uri sellerReportingUri = Uri.parse(reportingServer.getUrl(mSellerReportingPath).toString()); |
| Uri buyerReportingUri = Uri.parse(reportingServer.getUrl(mBuyerReportingPath).toString()); |
| |
| Uri biddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of(new MockResponse().setBody(sellerDecisionLogicJs))); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(biddingLogicUri) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(biddingLogicUri) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| // Count down callback + log interaction. |
| ReportImpressionTestCallback callback = |
| callReportImpression(adSelectionService, input, true); |
| assertTrue(callback.mIsSuccess); |
| RecordedRequest fetchRequest = server.takeRequest(); |
| assertEquals(mFetchJavaScriptPathSeller, fetchRequest.getPath()); |
| |
| // Assert that reporting didn't happen |
| assertEquals(reportingServer.getRequestCount(), 0); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionOnlyReportsBuyerWhenSellerReportingUriDoesNotMatchDomain() |
| throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| |
| Uri buyerReportingUri = mMockWebServerRule.uriForPath(mBuyerReportingPath); |
| |
| // Instantiate a server with a different domain than seller |
| MockWebServer sellerServer = new MockWebServer(); |
| sellerServer.play(); |
| Uri sellerReportingUri = Uri.parse(sellerServer.getUrl(mSellerReportingPath).toString()); |
| |
| Uri biddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(biddingLogicUri) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(biddingLogicUri) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| // Count down callback + log interaction. |
| ReportImpressionTestCallback callback = |
| callReportImpression(adSelectionService, input, true); |
| assertTrue(callback.mIsSuccess); |
| RecordedRequest fetchRequest = server.takeRequest(); |
| assertEquals(mFetchJavaScriptPathSeller, fetchRequest.getPath()); |
| |
| assertEquals(mBuyerReportingPath, server.takeRequest().getPath()); |
| |
| // Assert that buyer reporting didn't happen |
| assertEquals(sellerServer.getRequestCount(), 0); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void testReportImpressionOnlyReportsSellerWhenBuyerReportingUriDoesNotMatchDomain() |
| throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| |
| Uri sellerReportingUri = mMockWebServerRule.uriForPath(mSellerReportingPath); |
| |
| // Instantiate a server with a different domain than buyer |
| MockWebServer buyerServer = new MockWebServer(); |
| buyerServer.play(); |
| Uri buyerReportingUri = Uri.parse(buyerServer.getUrl(mBuyerReportingPath).toString()); |
| |
| Uri biddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| String sellerDecisionLogicJs = |
| "function reportResult(ad_selection_config, render_uri, bid, contextual_signals) {" |
| + " \n" |
| + " return {'status': 0, 'results': {'signals_for_buyer':" |
| + " '{\"signals_for_buyer\":1}', 'reporting_uri': '" |
| + sellerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| String buyerDecisionLogicJs = |
| "function reportWin(ad_selection_signals, per_buyer_signals, signals_for_buyer," |
| + " contextual_signals, custom_audience_signals) { \n" |
| + " return {'status': 0, 'results': {'reporting_uri': '" |
| + buyerReportingUri |
| + "' } };\n" |
| + "}"; |
| |
| MockWebServer server = |
| mMockWebServerRule.startMockWebServer( |
| List.of( |
| new MockResponse().setBody(sellerDecisionLogicJs), |
| new MockResponse())); |
| |
| DBBuyerDecisionLogic dbBuyerDecisionLogic = |
| new DBBuyerDecisionLogic.Builder() |
| .setBiddingLogicUri(biddingLogicUri) |
| .setBuyerDecisionLogicJs(buyerDecisionLogicJs) |
| .build(); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(biddingLogicUri) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic); |
| |
| AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| ReportImpressionInput input = |
| new ReportImpressionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setAdSelectionConfig(adSelectionConfig) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| // Count down callback + log interaction. |
| ReportImpressionTestCallback callback = |
| callReportImpression(adSelectionService, input, true); |
| assertTrue(callback.mIsSuccess); |
| RecordedRequest fetchRequest = server.takeRequest(); |
| assertEquals(mFetchJavaScriptPathSeller, fetchRequest.getPath()); |
| |
| assertEquals(mSellerReportingPath, server.takeRequest().getPath()); |
| |
| // Assert that buyer reporting didn't happen |
| assertEquals(buyerServer.getRequestCount(), 0); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void testAddOverrideAdSelectionFromOutcomesConfigRemoteInfoSuccess() throws Exception { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionFromOutcomesConfig config = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig(); |
| |
| AdSelectionOverrideTestCallback callback = |
| callAddOverrideForSelectAds( |
| adSelectionService, |
| config, |
| DUMMY_SELECTION_LOGIC_JS, |
| DUMMY_SELECTION_SIGNALS); |
| |
| assertTrue(callback.mIsSuccess); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId( |
| config), |
| TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void testOverrideAdSelectionFromOutcomesConfigRemoteInfoWithRevokedUserConsentSuccess() |
| throws Exception { |
| doReturn(AdServicesApiConsent.REVOKED).when(mConsentManagerMock).getConsent(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionFromOutcomesConfig config = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig(); |
| |
| AdSelectionOverrideTestCallback callback = |
| callAddOverrideForSelectAds( |
| adSelectionService, |
| config, |
| DUMMY_SELECTION_LOGIC_JS, |
| DUMMY_SELECTION_SIGNALS); |
| |
| assertTrue(callback.mIsSuccess); |
| assertFalse( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId( |
| config), |
| TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN), |
| eq(STATUS_USER_CONSENT_REVOKED), |
| anyInt()); |
| } |
| |
| @Test |
| public void testOverrideAdSelectionFromOutcomesConfigRemoteInfoFailsWithDevOptionsDisabled() { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionFromOutcomesConfig config = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig(); |
| |
| assertThrows( |
| SecurityException.class, |
| () -> |
| callAddOverrideForSelectAds( |
| adSelectionService, |
| config, |
| DUMMY_DECISION_LOGIC_JS, |
| DUMMY_TRUSTED_SCORING_SIGNALS)); |
| |
| assertFalse( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId( |
| config), |
| TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN), |
| eq(STATUS_INTERNAL_ERROR), |
| anyInt()); |
| } |
| |
| @Test |
| public void testRemoveAdSelectionFromOutcomesConfigRemoteInfoOverrideSuccess() |
| throws Exception { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionFromOutcomesConfig config = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig(); |
| |
| String configId = |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId(config); |
| |
| DBAdSelectionFromOutcomesOverride dbAdSelectionFromOutcomesOverride = |
| DBAdSelectionFromOutcomesOverride.builder() |
| .setAdSelectionFromOutcomesConfigId(configId) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setSelectionLogicJs(DUMMY_SELECTION_LOGIC_JS) |
| .setSelectionSignals(DUMMY_SELECTION_SIGNALS.toString()) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelectionFromOutcomesOverride( |
| dbAdSelectionFromOutcomesOverride); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId, TEST_PACKAGE_NAME)); |
| |
| AdSelectionOverrideTestCallback callback = callRemoveOverride(adSelectionService, config); |
| |
| assertTrue(callback.mIsSuccess); |
| assertFalse( |
| mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName( |
| configId, TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void |
| testRemoveAdSelectionFromOutcomesConfigRemoteInfoOverrideWithRevokedUserConsentSuccess() |
| throws Exception { |
| doReturn(AdServicesApiConsent.REVOKED).when(mConsentManagerMock).getConsent(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionFromOutcomesConfig config = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig(); |
| |
| String adSelectionConfigId = |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId(config); |
| |
| DBAdSelectionFromOutcomesOverride dbAdSelectionFromOutcomesOverride = |
| DBAdSelectionFromOutcomesOverride.builder() |
| .setAdSelectionFromOutcomesConfigId(adSelectionConfigId) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setSelectionLogicJs(DUMMY_SELECTION_LOGIC_JS) |
| .setSelectionSignals(DUMMY_SELECTION_SIGNALS.toString()) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelectionFromOutcomesOverride( |
| dbAdSelectionFromOutcomesOverride); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| adSelectionConfigId, TEST_PACKAGE_NAME)); |
| |
| AdSelectionOverrideTestCallback callback = callRemoveOverride(adSelectionService, config); |
| |
| assertTrue(callback.mIsSuccess); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| adSelectionConfigId, TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN), |
| eq(STATUS_USER_CONSENT_REVOKED), |
| anyInt()); |
| } |
| |
| @Test |
| public void |
| testRemoveAdSelectionFromOutcomesConfigRemoteInfoOverrideFailsWithDevOptionsDisabled() { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionFromOutcomesConfig config = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig(); |
| |
| String adSelectionConfigId = |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId(config); |
| |
| DBAdSelectionFromOutcomesOverride dbAdSelectionFromOutcomesOverride = |
| DBAdSelectionFromOutcomesOverride.builder() |
| .setAdSelectionFromOutcomesConfigId(adSelectionConfigId) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setSelectionLogicJs(DUMMY_SELECTION_LOGIC_JS) |
| .setSelectionSignals(DUMMY_SELECTION_SIGNALS.toString()) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelectionFromOutcomesOverride( |
| dbAdSelectionFromOutcomesOverride); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| adSelectionConfigId, TEST_PACKAGE_NAME)); |
| |
| assertThrows(SecurityException.class, () -> callRemoveOverride(adSelectionService, config)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| adSelectionConfigId, TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN), |
| eq(STATUS_INTERNAL_ERROR), |
| anyInt()); |
| } |
| |
| @Test |
| public void testRemoveAdSelectionFromOutcomesConfigRemoteOverrideNotDeleteIncorrectPackageName() |
| throws Exception { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| String incorrectPackageName = "com.google.ppapi.test.incorrect"; |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(incorrectPackageName) |
| .build()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionFromOutcomesConfig config = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig(); |
| |
| String adSelectionConfigId = |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId(config); |
| |
| DBAdSelectionFromOutcomesOverride dbAdSelectionFromOutcomesOverride = |
| DBAdSelectionFromOutcomesOverride.builder() |
| .setAdSelectionFromOutcomesConfigId(adSelectionConfigId) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setSelectionLogicJs(DUMMY_SELECTION_LOGIC_JS) |
| .setSelectionSignals(DUMMY_SELECTION_SIGNALS.toString()) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelectionFromOutcomesOverride( |
| dbAdSelectionFromOutcomesOverride); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| adSelectionConfigId, TEST_PACKAGE_NAME)); |
| |
| AdSelectionOverrideTestCallback callback = callRemoveOverride(adSelectionService, config); |
| |
| assertTrue(callback.mIsSuccess); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| adSelectionConfigId, TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void testResetAllAdSelectionFromOutcomesConfigRemoteOverridesSuccess() throws Exception { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionFromOutcomesConfig config1 = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig(); |
| AdSelectionFromOutcomesConfig config2 = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig( |
| AdTechIdentifier.fromString("adidas.com"), |
| Uri.parse("https://adidas.com/decisoin_logic_uri")); |
| AdSelectionFromOutcomesConfig config3 = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig( |
| AdTechIdentifier.fromString("nike.com"), |
| Uri.parse("https://nike.com/decisoin_logic_uri")); |
| |
| String configId1 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId(config1); |
| String configId2 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId(config2); |
| String configId3 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId(config3); |
| |
| DBAdSelectionFromOutcomesOverride dbAdSelectionFromOutcomesOverride1 = |
| DBAdSelectionFromOutcomesOverride.builder() |
| .setAdSelectionFromOutcomesConfigId(configId1) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setSelectionLogicJs(DUMMY_SELECTION_LOGIC_JS) |
| .setSelectionSignals(DUMMY_SELECTION_SIGNALS.toString()) |
| .build(); |
| |
| DBAdSelectionFromOutcomesOverride dbAdSelectionFromOutcomesOverride2 = |
| DBAdSelectionFromOutcomesOverride.builder() |
| .setAdSelectionFromOutcomesConfigId(configId2) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setSelectionLogicJs(DUMMY_SELECTION_LOGIC_JS) |
| .setSelectionSignals(DUMMY_SELECTION_SIGNALS.toString()) |
| .build(); |
| |
| DBAdSelectionFromOutcomesOverride dbAdSelectionFromOutcomesOverride3 = |
| DBAdSelectionFromOutcomesOverride.builder() |
| .setAdSelectionFromOutcomesConfigId(configId3) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setSelectionLogicJs(DUMMY_SELECTION_LOGIC_JS) |
| .setSelectionSignals(DUMMY_SELECTION_SIGNALS.toString()) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelectionFromOutcomesOverride( |
| dbAdSelectionFromOutcomesOverride1); |
| mAdSelectionEntryDao.persistAdSelectionFromOutcomesOverride( |
| dbAdSelectionFromOutcomesOverride2); |
| mAdSelectionEntryDao.persistAdSelectionFromOutcomesOverride( |
| dbAdSelectionFromOutcomesOverride3); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId1, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId2, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId3, TEST_PACKAGE_NAME)); |
| |
| AdSelectionOverrideTestCallback callback = |
| callResetAllSelectionOutcomesOverrides(adSelectionService); |
| |
| assertTrue(callback.mIsSuccess); |
| |
| assertFalse( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId1, TEST_PACKAGE_NAME)); |
| assertFalse( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId2, TEST_PACKAGE_NAME)); |
| assertFalse( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId3, TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void |
| testResetAllAdSelectionFromOutcomesConfigRemoteOverridesWithRevokedUserConsentSuccess() |
| throws Exception { |
| doReturn(AdServicesApiConsent.REVOKED).when(mConsentManagerMock).getConsent(); |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionFromOutcomesConfig config1 = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig(); |
| AdSelectionFromOutcomesConfig config2 = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig( |
| AdTechIdentifier.fromString("adidas.com"), |
| Uri.parse("https://adidas.com/decisoin_logic_uri")); |
| AdSelectionFromOutcomesConfig config3 = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig( |
| AdTechIdentifier.fromString("nike.com"), |
| Uri.parse("https://nike.com/decisoin_logic_uri")); |
| |
| String configId1 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId(config1); |
| String configId2 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId(config2); |
| String configId3 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId(config3); |
| |
| DBAdSelectionFromOutcomesOverride dbAdSelectionFromOutcomesOverride1 = |
| DBAdSelectionFromOutcomesOverride.builder() |
| .setAdSelectionFromOutcomesConfigId(configId1) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setSelectionLogicJs(DUMMY_SELECTION_LOGIC_JS) |
| .setSelectionSignals(DUMMY_SELECTION_SIGNALS.toString()) |
| .build(); |
| |
| DBAdSelectionFromOutcomesOverride dbAdSelectionFromOutcomesOverride2 = |
| DBAdSelectionFromOutcomesOverride.builder() |
| .setAdSelectionFromOutcomesConfigId(configId2) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setSelectionLogicJs(DUMMY_SELECTION_LOGIC_JS) |
| .setSelectionSignals(DUMMY_SELECTION_SIGNALS.toString()) |
| .build(); |
| |
| DBAdSelectionFromOutcomesOverride dbAdSelectionFromOutcomesOverride3 = |
| DBAdSelectionFromOutcomesOverride.builder() |
| .setAdSelectionFromOutcomesConfigId(configId3) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setSelectionLogicJs(DUMMY_SELECTION_LOGIC_JS) |
| .setSelectionSignals(DUMMY_SELECTION_SIGNALS.toString()) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelectionFromOutcomesOverride( |
| dbAdSelectionFromOutcomesOverride1); |
| mAdSelectionEntryDao.persistAdSelectionFromOutcomesOverride( |
| dbAdSelectionFromOutcomesOverride2); |
| mAdSelectionEntryDao.persistAdSelectionFromOutcomesOverride( |
| dbAdSelectionFromOutcomesOverride3); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId1, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId2, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId3, TEST_PACKAGE_NAME)); |
| |
| AdSelectionOverrideTestCallback callback = |
| callResetAllSelectionOutcomesOverrides(adSelectionService); |
| |
| assertTrue(callback.mIsSuccess); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId1, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId2, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId3, TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN), |
| eq(STATUS_USER_CONSENT_REVOKED), |
| anyInt()); |
| } |
| |
| @Test |
| public void |
| testResetAllAdSelectionFromOutcomesConfigRemoteOverridesFailsWithDevOptionsDisabled() { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn(DevContext.createForDevOptionsDisabled()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionFromOutcomesConfig config1 = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig(); |
| AdSelectionFromOutcomesConfig config2 = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig( |
| AdTechIdentifier.fromString("adidas.com"), |
| Uri.parse("https://adidas.com/decisoin_logic_uri")); |
| AdSelectionFromOutcomesConfig config3 = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig( |
| AdTechIdentifier.fromString("nike.com"), |
| Uri.parse("https://nike.com/decisoin_logic_uri")); |
| |
| String configId1 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId(config1); |
| String configId2 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId(config2); |
| String configId3 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId(config3); |
| |
| DBAdSelectionFromOutcomesOverride dbAdSelectionFromOutcomesOverride1 = |
| DBAdSelectionFromOutcomesOverride.builder() |
| .setAdSelectionFromOutcomesConfigId(configId1) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setSelectionLogicJs(DUMMY_SELECTION_LOGIC_JS) |
| .setSelectionSignals(DUMMY_SELECTION_SIGNALS.toString()) |
| .build(); |
| |
| DBAdSelectionFromOutcomesOverride dbAdSelectionFromOutcomesOverride2 = |
| DBAdSelectionFromOutcomesOverride.builder() |
| .setAdSelectionFromOutcomesConfigId(configId2) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setSelectionLogicJs(DUMMY_SELECTION_LOGIC_JS) |
| .setSelectionSignals(DUMMY_SELECTION_SIGNALS.toString()) |
| .build(); |
| |
| DBAdSelectionFromOutcomesOverride dbAdSelectionFromOutcomesOverride3 = |
| DBAdSelectionFromOutcomesOverride.builder() |
| .setAdSelectionFromOutcomesConfigId(configId3) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setSelectionLogicJs(DUMMY_SELECTION_LOGIC_JS) |
| .setSelectionSignals(DUMMY_SELECTION_SIGNALS.toString()) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelectionFromOutcomesOverride( |
| dbAdSelectionFromOutcomesOverride1); |
| mAdSelectionEntryDao.persistAdSelectionFromOutcomesOverride( |
| dbAdSelectionFromOutcomesOverride2); |
| mAdSelectionEntryDao.persistAdSelectionFromOutcomesOverride( |
| dbAdSelectionFromOutcomesOverride3); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId1, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId2, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId3, TEST_PACKAGE_NAME)); |
| |
| assertThrows( |
| SecurityException.class, |
| () -> callResetAllSelectionOutcomesOverrides(adSelectionService)); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId1, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId2, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId3, TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN), |
| eq(STATUS_INTERNAL_ERROR), |
| anyInt()); |
| } |
| |
| @Test |
| public void testResetAllAdSelectionFromOutcomesConfigRemoteOverrideNotDeleteIncorrectPkgName() |
| throws Exception { |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| String incorrectPackageName = "com.google.ppapi.test.incorrect"; |
| |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(incorrectPackageName) |
| .build()); |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionFromOutcomesConfig config1 = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig(); |
| AdSelectionFromOutcomesConfig config2 = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig( |
| AdTechIdentifier.fromString("adidas.com"), |
| Uri.parse("https://adidas.com/decisoin_logic_uri")); |
| AdSelectionFromOutcomesConfig config3 = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig( |
| AdTechIdentifier.fromString("nike.com"), |
| Uri.parse("https://nike.com/decisoin_logic_uri")); |
| |
| String configId1 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId(config1); |
| String configId2 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId(config2); |
| String configId3 = |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId(config3); |
| |
| DBAdSelectionFromOutcomesOverride dbAdSelectionFromOutcomesOverride1 = |
| DBAdSelectionFromOutcomesOverride.builder() |
| .setAdSelectionFromOutcomesConfigId(configId1) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setSelectionLogicJs(DUMMY_SELECTION_LOGIC_JS) |
| .setSelectionSignals(DUMMY_SELECTION_SIGNALS.toString()) |
| .build(); |
| |
| DBAdSelectionFromOutcomesOverride dbAdSelectionFromOutcomesOverride2 = |
| DBAdSelectionFromOutcomesOverride.builder() |
| .setAdSelectionFromOutcomesConfigId(configId2) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setSelectionLogicJs(DUMMY_SELECTION_LOGIC_JS) |
| .setSelectionSignals(DUMMY_SELECTION_SIGNALS.toString()) |
| .build(); |
| |
| DBAdSelectionFromOutcomesOverride dbAdSelectionFromOutcomesOverride3 = |
| DBAdSelectionFromOutcomesOverride.builder() |
| .setAdSelectionFromOutcomesConfigId(configId3) |
| .setAppPackageName(TEST_PACKAGE_NAME) |
| .setSelectionLogicJs(DUMMY_SELECTION_LOGIC_JS) |
| .setSelectionSignals(DUMMY_SELECTION_SIGNALS.toString()) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelectionFromOutcomesOverride( |
| dbAdSelectionFromOutcomesOverride1); |
| mAdSelectionEntryDao.persistAdSelectionFromOutcomesOverride( |
| dbAdSelectionFromOutcomesOverride2); |
| mAdSelectionEntryDao.persistAdSelectionFromOutcomesOverride( |
| dbAdSelectionFromOutcomesOverride3); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId1, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId2, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId3, TEST_PACKAGE_NAME)); |
| |
| AdSelectionOverrideTestCallback callback = |
| callResetAllSelectionOutcomesOverrides(adSelectionService); |
| |
| assertTrue(callback.mIsSuccess); |
| |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId1, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId2, TEST_PACKAGE_NAME)); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| configId3, TEST_PACKAGE_NAME)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void testOverrideAdSelectionConfigRemoteOverridesSuccess() throws Exception { |
| Assume.assumeTrue(JSScriptEngine.AvailabilityChecker.isJSSandboxAvailable()); |
| doReturn(AdServicesApiConsent.GIVEN).when(mConsentManagerMock).getConsent(); |
| when(mDevContextFilter.createDevContext()) |
| .thenReturn( |
| DevContext.builder() |
| .setDevOptionsEnabled(true) |
| .setCallingAppPackageName(TEST_PACKAGE_NAME) |
| .build()); |
| |
| Map<Long, Double> adSelectionIdToBidMap = |
| Map.of( |
| AD_SELECTION_ID_1, 10.0, |
| AD_SELECTION_ID_2, 20.0, |
| AD_SELECTION_ID_3, 30.0); |
| persistAdSelectionEntryDaoResults(adSelectionIdToBidMap); |
| |
| AdSelectionFromOutcomesConfig config = |
| AdSelectionFromOutcomesConfigFixture.anAdSelectionFromOutcomesConfig( |
| List.of(AD_SELECTION_ID_1, AD_SELECTION_ID_2, AD_SELECTION_ID_3), |
| AdSelectionSignals.EMPTY, |
| Uri.parse("https://this.uri.isnt/called")); |
| |
| final String selectionPickSmallestAdSelectionIdLogicJs = |
| "function selectOutcome(outcomes, selection_signals) {\n" |
| + " outcomes.sort(function(a, b) { return a.id - b.id;});\n" |
| + " return {'status': 0, 'result': outcomes[0]};\n" |
| + "}"; |
| |
| AdSelectionServiceImpl adSelectionService = |
| new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| |
| AdSelectionOverrideTestCallback overridesCallback = |
| callAddOverrideForSelectAds( |
| adSelectionService, |
| config, |
| selectionPickSmallestAdSelectionIdLogicJs, |
| AdSelectionSignals.EMPTY); |
| |
| assertTrue(overridesCallback.mIsSuccess); |
| assertTrue( |
| mAdSelectionEntryDao.doesAdSelectionFromOutcomesOverrideExistForPackageName( |
| AdSelectionDevOverridesHelper.calculateAdSelectionFromOutcomesConfigId( |
| config), |
| TEST_PACKAGE_NAME)); |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| |
| AdSelectionFromOutcomesTestCallback selectionCallback = |
| invokeSelectAdsFromOutcomes(adSelectionService, config, TEST_PACKAGE_NAME); |
| |
| assertTrue(selectionCallback.mIsSuccess); |
| assertEquals(AD_SELECTION_ID_1, selectionCallback.mAdSelectionResponse.getAdSelectionId()); |
| } |
| |
| @Test |
| public void testSetAppInstallAdvertisersSuccess() throws Exception { |
| SetAppInstallAdvertisersInput input = |
| new SetAppInstallAdvertisersInput.Builder() |
| .setAdvertisers( |
| new HashSet<>( |
| Arrays.asList( |
| AdTechIdentifier.fromString("example1.com"), |
| AdTechIdentifier.fromString("example2.com")))) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| SetAppInstallAdvertisersTestCallback callback = |
| callSetAppInstallAdvertisers(generateAdSelectionServiceImpl(), input); |
| assertTrue(callback.mIsSuccess); |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__SET_APP_INSTALL_ADVERTISERS), |
| eq(STATUS_SUCCESS), |
| anyInt()); |
| } |
| |
| @Test |
| public void testSetAppInstallAdvertisersNullInput() { |
| assertThrows( |
| NullPointerException.class, |
| () -> callSetAppInstallAdvertisers(generateAdSelectionServiceImpl(), null)); |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__SET_APP_INSTALL_ADVERTISERS), |
| eq(STATUS_INVALID_ARGUMENT), |
| eq(0)); |
| } |
| |
| @Test |
| public void testUpdateAdCounterHistogramNullInputThrows() { |
| assertThrows( |
| NullPointerException.class, |
| () -> callUpdateAdCounterHistogram(generateAdSelectionServiceImpl(), null)); |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_CLASS__UNKNOWN), |
| eq(STATUS_INVALID_ARGUMENT), |
| eq(0)); |
| } |
| |
| @Test |
| public void testUpdateAdCounterHistogramNullCallbackThrows() throws InterruptedException { |
| AdSelectionServiceImpl adSelectionService = generateAdSelectionServiceImpl(); |
| UpdateAdCounterHistogramInput inputParams = |
| new UpdateAdCounterHistogramInput.Builder() |
| .setAdSelectionId(10) |
| .setAdEventType(FrequencyCapFilters.AD_EVENT_TYPE_VIEW) |
| .setCallerAdTech(CommonFixture.VALID_BUYER_1) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| // Wait for the logging call, which happens after the callback |
| CountDownLatch resultLatch = new CountDownLatch(1); |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| assertThrows( |
| NullPointerException.class, |
| () -> adSelectionService.updateAdCounterHistogram(inputParams, null)); |
| assertTrue( |
| "Timed out waiting for updateAdCounterHistogram call to complete", |
| resultLatch.await(5, TimeUnit.SECONDS)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_CLASS__UNKNOWN), |
| eq(STATUS_INVALID_ARGUMENT), |
| eq(0)); |
| } |
| |
| @Test |
| public void testUpdateAdCounterHistogramCallbackErrorReported() throws InterruptedException { |
| AdSelectionServiceImpl adSelectionService = generateAdSelectionServiceImpl(); |
| UpdateAdCounterHistogramInput inputParams = |
| new UpdateAdCounterHistogramInput.Builder() |
| .setAdSelectionId(10) |
| .setAdEventType(FrequencyCapFilters.AD_EVENT_TYPE_VIEW) |
| .setCallerAdTech(CommonFixture.VALID_BUYER_1) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| // Counted down in 1) callback and 2) logApiCall |
| CountDownLatch resultLatch = new CountDownLatch(2); |
| UpdateAdCounterHistogramCallback callback = |
| new UpdateAdCounterHistogramTestErrorCallback(resultLatch); |
| |
| // Wait for the logging call, which happens after the callback |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| adSelectionService.updateAdCounterHistogram(inputParams, callback); |
| assertTrue( |
| "Timed out waiting for updateAdCounterHistogram call to complete", |
| resultLatch.await(5, TimeUnit.SECONDS)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_CLASS__UNKNOWN), |
| eq(STATUS_INTERNAL_ERROR), |
| eq(0)); |
| } |
| |
| @Test |
| public void testUpdateAdCounterHistogramSuccess() throws InterruptedException { |
| UpdateAdCounterHistogramInput inputParams = |
| new UpdateAdCounterHistogramInput.Builder() |
| .setAdSelectionId(10) |
| .setAdEventType(FrequencyCapFilters.AD_EVENT_TYPE_VIEW) |
| .setCallerAdTech(CommonFixture.VALID_BUYER_1) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .build(); |
| |
| UpdateAdCounterHistogramTestCallback callback = |
| callUpdateAdCounterHistogram(generateAdSelectionServiceImpl(), inputParams); |
| assertTrue("updateAdCounterHistogram() callback was unsuccessful", callback.mIsSuccess); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_CLASS__UNKNOWN), eq(STATUS_SUCCESS), eq(0)); |
| } |
| |
| @Test |
| public void testReportInteractionNullInputThrows() { |
| assertThrows( |
| NullPointerException.class, |
| () -> callReportInteraction(generateAdSelectionServiceImpl(), null)); |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_CLASS__UNKNOWN), |
| eq(STATUS_INVALID_ARGUMENT), |
| eq(0)); |
| } |
| |
| @Test |
| public void testReportInteractionNullCallbackThrows() throws InterruptedException { |
| AdSelectionServiceImpl adSelectionService = generateAdSelectionServiceImpl(); |
| |
| ReportInteractionInput inputParams = |
| new ReportInteractionInput.Builder() |
| .setAdSelectionId(10) |
| .setInteractionData(INTERACTION_DATA) |
| .setInteractionKey(CLICK_EVENT_BUYER) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .setReportingDestinations(FLAG_REPORTING_DESTINATION_BUYER) |
| .build(); |
| |
| // Wait for the logging call, which happens after the callback |
| CountDownLatch resultLatch = new CountDownLatch(1); |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| assertThrows( |
| NullPointerException.class, |
| () -> adSelectionService.reportInteraction(inputParams, null)); |
| assertTrue( |
| "Timed out waiting for reportInteraction call to complete", |
| resultLatch.await(5, TimeUnit.SECONDS)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN), |
| eq(STATUS_INVALID_ARGUMENT), |
| eq(0)); |
| } |
| |
| // TODO(b/271652362): Investigate logging and testing of failures during callback reporting |
| @Ignore("b/271652362") |
| @Test |
| public void testReportInteractionCallbackErrorReported() throws Exception { |
| Uri biddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(biddingLogicUri) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| |
| AdSelectionServiceImpl adSelectionService = generateAdSelectionServiceImpl(); |
| |
| ReportInteractionInput inputParams = |
| new ReportInteractionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setInteractionData(INTERACTION_DATA) |
| .setInteractionKey(CLICK_EVENT_BUYER) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .setReportingDestinations(FLAG_REPORTING_DESTINATION_BUYER) |
| .build(); |
| |
| // Counted down in 1) callback and 2) logApiCall |
| CountDownLatch resultLatch = new CountDownLatch(2); |
| ReportInteractionTestErrorCallback callback = |
| new ReportInteractionTestErrorCallback(resultLatch); |
| |
| // Wait for the logging call, which happens after the callback |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| adSelectionService.reportInteraction(inputParams, callback); |
| assertTrue( |
| "Timed out waiting for reportInteraction call to complete", |
| resultLatch.await(5, TimeUnit.SECONDS)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN), |
| eq(STATUS_INTERNAL_ERROR), |
| eq(0)); |
| } |
| |
| @Test |
| public void testReportInteractionSuccess() throws Exception { |
| Uri biddingLogicUri = (mMockWebServerRule.uriForPath(mFetchJavaScriptPathBuyer)); |
| |
| DBAdSelection dbAdSelection = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setCustomAudienceSignals(mCustomAudienceSignals) |
| .setContextualSignals(mContextualSignals.toString()) |
| .setBiddingLogicUri(biddingLogicUri) |
| .setWinningAdRenderUri(RENDER_URI) |
| .setWinningAdBid(BID) |
| .setCreationTimestamp(ACTIVATION_TIME) |
| .setCallerPackageName(CommonFixture.TEST_PACKAGE_NAME) |
| .build(); |
| |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelection); |
| |
| ReportInteractionInput inputParams = |
| new ReportInteractionInput.Builder() |
| .setAdSelectionId(AD_SELECTION_ID) |
| .setInteractionData(INTERACTION_DATA) |
| .setInteractionKey(CLICK_EVENT_BUYER) |
| .setCallerPackageName(TEST_PACKAGE_NAME) |
| .setReportingDestinations(FLAG_REPORTING_DESTINATION_BUYER) |
| .build(); |
| |
| // Count down callback + log interaction. |
| ReportInteractionTestCallback callback = |
| callReportInteraction(generateAdSelectionServiceImpl(), inputParams, true); |
| assertTrue("reportInteraction() callback was unsuccessful", callback.mIsSuccess); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_NAME__API_NAME_UNKNOWN), |
| eq(STATUS_SUCCESS), |
| eq(0)); |
| } |
| |
| @Test |
| public void testSetAdCounterHistogramOverrideNullInputThrows() { |
| assertThrows( |
| NullPointerException.class, |
| () -> callSetAdCounterHistogramOverride(generateAdSelectionServiceImpl(), null)); |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_CLASS__UNKNOWN), |
| eq(STATUS_INVALID_ARGUMENT), |
| eq(0)); |
| } |
| |
| @Test |
| public void testSetAdCounterHistogramOverrideNullCallbackThrows() throws InterruptedException { |
| AdSelectionServiceImpl adSelectionService = generateAdSelectionServiceImpl(); |
| SetAdCounterHistogramOverrideInput inputParams = |
| new SetAdCounterHistogramOverrideInput.Builder() |
| .setAdEventType(FrequencyCapFilters.AD_EVENT_TYPE_CLICK) |
| .setAdCounterKey(KeyedFrequencyCapFixture.KEY1) |
| .setBuyer(CommonFixture.VALID_BUYER_1) |
| .setCustomAudienceOwner(CommonFixture.TEST_PACKAGE_NAME) |
| .setCustomAudienceName("testName") |
| .build(); |
| |
| // Wait for the logging call, which happens after the callback |
| CountDownLatch resultLatch = new CountDownLatch(1); |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| assertThrows( |
| NullPointerException.class, |
| () -> adSelectionService.setAdCounterHistogramOverride(inputParams, null)); |
| assertTrue( |
| "Timed out waiting for setAdCounterHistogramOverride call to complete", |
| resultLatch.await(5, TimeUnit.SECONDS)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_CLASS__UNKNOWN), |
| eq(STATUS_INVALID_ARGUMENT), |
| eq(0)); |
| } |
| |
| @Test |
| public void testSetAdCounterHistogramOverrideCallbackErrorReported() |
| throws InterruptedException { |
| AdSelectionServiceImpl adSelectionService = generateAdSelectionServiceImpl(); |
| SetAdCounterHistogramOverrideInput inputParams = |
| new SetAdCounterHistogramOverrideInput.Builder() |
| .setAdEventType(FrequencyCapFilters.AD_EVENT_TYPE_CLICK) |
| .setAdCounterKey(KeyedFrequencyCapFixture.KEY1) |
| .setBuyer(CommonFixture.VALID_BUYER_1) |
| .setCustomAudienceOwner(CommonFixture.TEST_PACKAGE_NAME) |
| .setCustomAudienceName("testName") |
| .build(); |
| |
| // Counted down in 1) callback and 2) logApiCall |
| CountDownLatch resultLatch = new CountDownLatch(2); |
| AdSelectionOverrideTestCallback callback = |
| new AdSelectionOverrideTestErrorCallback(resultLatch); |
| |
| // Wait for the logging call, which happens after the callback |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| adSelectionService.setAdCounterHistogramOverride(inputParams, callback); |
| assertTrue( |
| "Timed out waiting for setAdCounterHistogramOverride call to complete", |
| resultLatch.await(5, TimeUnit.SECONDS)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_CLASS__UNKNOWN), |
| eq(STATUS_INTERNAL_ERROR), |
| eq(0)); |
| } |
| |
| @Test |
| public void testSetAdCounterHistogramOverrideSuccess() throws InterruptedException { |
| SetAdCounterHistogramOverrideInput inputParams = |
| new SetAdCounterHistogramOverrideInput.Builder() |
| .setAdEventType(FrequencyCapFilters.AD_EVENT_TYPE_CLICK) |
| .setAdCounterKey(KeyedFrequencyCapFixture.KEY1) |
| .setBuyer(CommonFixture.VALID_BUYER_1) |
| .setCustomAudienceOwner(CommonFixture.TEST_PACKAGE_NAME) |
| .setCustomAudienceName("testName") |
| .build(); |
| |
| AdSelectionOverrideTestCallback callback = |
| callSetAdCounterHistogramOverride(generateAdSelectionServiceImpl(), inputParams); |
| assertTrue( |
| "setAdCounterHistogramOverride() callback should have been successful", |
| callback.mIsSuccess); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_CLASS__UNKNOWN), eq(STATUS_SUCCESS), eq(0)); |
| } |
| |
| @Test |
| public void testRemoveAdCounterHistogramOverrideNullInputThrows() { |
| assertThrows( |
| NullPointerException.class, |
| () -> callRemoveAdCounterHistogramOverride(generateAdSelectionServiceImpl(), null)); |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_CLASS__UNKNOWN), |
| eq(STATUS_INVALID_ARGUMENT), |
| eq(0)); |
| } |
| |
| @Test |
| public void testRemoveAdCounterHistogramOverrideNullCallbackThrows() |
| throws InterruptedException { |
| AdSelectionServiceImpl adSelectionService = generateAdSelectionServiceImpl(); |
| RemoveAdCounterHistogramOverrideInput inputParams = |
| new RemoveAdCounterHistogramOverrideInput.Builder() |
| .setAdEventType(FrequencyCapFilters.AD_EVENT_TYPE_CLICK) |
| .setAdCounterKey(KeyedFrequencyCapFixture.KEY1) |
| .setBuyer(CommonFixture.VALID_BUYER_1) |
| .build(); |
| |
| // Wait for the logging call, which happens after the callback |
| CountDownLatch resultLatch = new CountDownLatch(1); |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| assertThrows( |
| NullPointerException.class, |
| () -> adSelectionService.removeAdCounterHistogramOverride(inputParams, null)); |
| assertTrue( |
| "Timed out waiting for removeAdCounterHistogramOverride call to complete", |
| resultLatch.await(5, TimeUnit.SECONDS)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_CLASS__UNKNOWN), |
| eq(STATUS_INVALID_ARGUMENT), |
| eq(0)); |
| } |
| |
| @Test |
| public void testRemoveAdCounterHistogramOverrideCallbackErrorReported() |
| throws InterruptedException { |
| AdSelectionServiceImpl adSelectionService = generateAdSelectionServiceImpl(); |
| RemoveAdCounterHistogramOverrideInput inputParams = |
| new RemoveAdCounterHistogramOverrideInput.Builder() |
| .setAdEventType(FrequencyCapFilters.AD_EVENT_TYPE_CLICK) |
| .setAdCounterKey(KeyedFrequencyCapFixture.KEY1) |
| .setBuyer(CommonFixture.VALID_BUYER_1) |
| .build(); |
| |
| // Counted down in 1) callback and 2) logApiCall |
| CountDownLatch resultLatch = new CountDownLatch(2); |
| AdSelectionOverrideTestCallback callback = |
| new AdSelectionOverrideTestErrorCallback(resultLatch); |
| |
| // Wait for the logging call, which happens after the callback |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| adSelectionService.removeAdCounterHistogramOverride(inputParams, callback); |
| assertTrue( |
| "Timed out waiting for removeAdCounterHistogramOverride call to complete", |
| resultLatch.await(5, TimeUnit.SECONDS)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_CLASS__UNKNOWN), |
| eq(STATUS_INTERNAL_ERROR), |
| eq(0)); |
| } |
| |
| @Test |
| public void testRemoveAdCounterHistogramOverrideSuccess() throws InterruptedException { |
| RemoveAdCounterHistogramOverrideInput inputParams = |
| new RemoveAdCounterHistogramOverrideInput.Builder() |
| .setAdEventType(FrequencyCapFilters.AD_EVENT_TYPE_CLICK) |
| .setAdCounterKey(KeyedFrequencyCapFixture.KEY1) |
| .setBuyer(CommonFixture.VALID_BUYER_1) |
| .build(); |
| |
| AdSelectionOverrideTestCallback callback = |
| callRemoveAdCounterHistogramOverride(generateAdSelectionServiceImpl(), inputParams); |
| assertTrue( |
| "removeAdCounterHistogramOverride() callback should have been successful", |
| callback.mIsSuccess); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_CLASS__UNKNOWN), eq(STATUS_SUCCESS), eq(0)); |
| } |
| |
| @Test |
| public void testResetAllAdCounterHistogramOverridesNullCallbackThrows() |
| throws InterruptedException { |
| AdSelectionServiceImpl adSelectionService = generateAdSelectionServiceImpl(); |
| |
| // Wait for the logging call, which happens after the callback |
| CountDownLatch resultLatch = new CountDownLatch(1); |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| assertThrows( |
| NullPointerException.class, |
| () -> adSelectionService.resetAllAdCounterHistogramOverrides(null)); |
| assertTrue( |
| "Timed out waiting for resetAllAdCounterHistogramOverrides call to complete", |
| resultLatch.await(5, TimeUnit.SECONDS)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_CLASS__UNKNOWN), |
| eq(STATUS_INVALID_ARGUMENT), |
| eq(0)); |
| } |
| |
| @Test |
| public void testResetAllAdCounterHistogramOverridesCallbackErrorReported() |
| throws InterruptedException { |
| AdSelectionServiceImpl adSelectionService = generateAdSelectionServiceImpl(); |
| |
| // Counted down in 1) callback and 2) logApiCall |
| CountDownLatch resultLatch = new CountDownLatch(2); |
| AdSelectionOverrideTestCallback callback = |
| new AdSelectionOverrideTestErrorCallback(resultLatch); |
| |
| // Wait for the logging call, which happens after the callback |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| adSelectionService.resetAllAdCounterHistogramOverrides(callback); |
| assertTrue( |
| "Timed out waiting for resetAllAdCounterHistogramOverrides call to complete", |
| resultLatch.await(5, TimeUnit.SECONDS)); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_CLASS__UNKNOWN), |
| eq(STATUS_INTERNAL_ERROR), |
| eq(0)); |
| } |
| |
| @Test |
| public void testResetAllAdCounterHistogramOverridesSuccess() throws InterruptedException { |
| AdSelectionOverrideTestCallback callback = |
| callResetAllAdCounterHistogramOverrides(generateAdSelectionServiceImpl()); |
| assertTrue( |
| "resetAllAdCounterHistogramOverrides() callback should have been successful", |
| callback.mIsSuccess); |
| |
| verify(mAdServicesLoggerMock) |
| .logFledgeApiCallStats( |
| eq(AD_SERVICES_API_CALLED__API_CLASS__UNKNOWN), eq(STATUS_SUCCESS), eq(0)); |
| } |
| |
| private AdSelectionServiceImpl generateAdSelectionServiceImpl() { |
| return new AdSelectionServiceImpl( |
| mAdSelectionEntryDao, |
| mAppInstallDao, |
| mCustomAudienceDao, |
| mClient, |
| mDevContextFilter, |
| mLightweightExecutorService, |
| mBackgroundExecutorService, |
| mScheduledExecutor, |
| CONTEXT, |
| mAdServicesLoggerMock, |
| mFlags, |
| CallingAppUidSupplierProcessImpl.create(), |
| mFledgeAuthorizationFilterSpy, |
| mAdSelectionServiceFilter, |
| mAdFilteringFeatureFactory, |
| mConsentManagerMock); |
| } |
| |
| private void persistAdSelectionEntryDaoResults(Map<Long, Double> adSelectionIdToBidMap) { |
| persistAdSelectionEntryDaoResults(adSelectionIdToBidMap, TEST_PACKAGE_NAME); |
| } |
| |
| private void persistAdSelectionEntryDaoResults( |
| Map<Long, Double> adSelectionIdToBidMap, String callerPackageName) { |
| final Uri biddingLogicUri1 = Uri.parse("https://www.domain.com/logic/1"); |
| final Uri renderUri = Uri.parse("https://www.domain.com/advert/"); |
| final Instant activationTime = Instant.now(); |
| final String contextualSignals = "contextual_signals"; |
| final CustomAudienceSignals customAudienceSignals = |
| CustomAudienceSignalsFixture.aCustomAudienceSignals(); |
| |
| for (Map.Entry<Long, Double> entry : adSelectionIdToBidMap.entrySet()) { |
| final DBAdSelection dbAdSelectionEntry = |
| new DBAdSelection.Builder() |
| .setAdSelectionId(entry.getKey()) |
| .setCustomAudienceSignals(customAudienceSignals) |
| .setContextualSignals(contextualSignals) |
| .setBiddingLogicUri(biddingLogicUri1) |
| .setWinningAdRenderUri(renderUri) |
| .setWinningAdBid(entry.getValue()) |
| .setCreationTimestamp(activationTime) |
| .setCallerPackageName(callerPackageName) |
| .build(); |
| mAdSelectionEntryDao.persistAdSelection(dbAdSelectionEntry); |
| } |
| } |
| |
| /** |
| * Given Throttler is singleton, & shared across tests, this method should be invoked after |
| * tests that impose restrictive rate limits. |
| */ |
| private void resetThrottlerToNoRateLimits() { |
| Throttler.destroyExistingThrottler(); |
| final float noRateLimit = -1; |
| Flags mockNoRateLimitFlags = mock(Flags.class); |
| doReturn(noRateLimit).when(mockNoRateLimitFlags).getSdkRequestPermitsPerSecond(); |
| Throttler.getInstance(mockNoRateLimitFlags); |
| } |
| |
| private AdSelectionOverrideTestCallback callAddOverrideForSelectAds( |
| AdSelectionServiceImpl adSelectionService, |
| AdSelectionConfig adSelectionConfig, |
| String decisionLogicJS, |
| AdSelectionSignals trustedScoringSignals) |
| throws Exception { |
| // Counted down in 1) callback and 2) logApiCall |
| CountDownLatch resultLatch = new CountDownLatch(2); |
| AdSelectionOverrideTestCallback callback = new AdSelectionOverrideTestCallback(resultLatch); |
| |
| // Wait for the logging call, which happens after the callback |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| adSelectionService.overrideAdSelectionConfigRemoteInfo( |
| adSelectionConfig, decisionLogicJS, trustedScoringSignals, callback); |
| resultLatch.await(); |
| return callback; |
| } |
| |
| private AdSelectionOverrideTestCallback callAddOverrideForSelectAds( |
| AdSelectionServiceImpl adSelectionService, |
| AdSelectionFromOutcomesConfig adSelectionFromOutcomesConfig, |
| String selectionLogic, |
| AdSelectionSignals selectionSignals) |
| throws Exception { |
| // Counted down in 1) callback and 2) logApiCall |
| CountDownLatch resultLatch = new CountDownLatch(2); |
| AdSelectionOverrideTestCallback callback = new AdSelectionOverrideTestCallback(resultLatch); |
| |
| // Wait for the logging call, which happens after the callback |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| adSelectionService.overrideAdSelectionFromOutcomesConfigRemoteInfo( |
| adSelectionFromOutcomesConfig, selectionLogic, selectionSignals, callback); |
| resultLatch.await(); |
| return callback; |
| } |
| |
| private AdSelectionOverrideTestCallback callRemoveOverride( |
| AdSelectionServiceImpl adSelectionService, AdSelectionConfig adSelectionConfig) |
| throws Exception { |
| // Counted down in 1) callback and 2) logApiCall |
| CountDownLatch resultLatch = new CountDownLatch(2); |
| AdSelectionOverrideTestCallback callback = new AdSelectionOverrideTestCallback(resultLatch); |
| |
| // Wait for the logging call, which happens after the callback |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| adSelectionService.removeAdSelectionConfigRemoteInfoOverride(adSelectionConfig, callback); |
| resultLatch.await(); |
| return callback; |
| } |
| |
| private AdSelectionOverrideTestCallback callRemoveOverride( |
| AdSelectionServiceImpl adSelectionService, AdSelectionFromOutcomesConfig config) |
| throws Exception { |
| // Counted down in 1) callback and 2) logApiCall |
| CountDownLatch resultLatch = new CountDownLatch(2); |
| AdSelectionOverrideTestCallback callback = new AdSelectionOverrideTestCallback(resultLatch); |
| |
| // Wait for the logging call, which happens after the callback |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| adSelectionService.removeAdSelectionFromOutcomesConfigRemoteInfoOverride(config, callback); |
| resultLatch.await(); |
| return callback; |
| } |
| |
| private AdSelectionOverrideTestCallback callResetAllOverrides( |
| AdSelectionServiceImpl adSelectionService) throws Exception { |
| // Counted down in 1) callback and 2) logApiCall |
| CountDownLatch resultLatch = new CountDownLatch(2); |
| AdSelectionOverrideTestCallback callback = new AdSelectionOverrideTestCallback(resultLatch); |
| |
| // Wait for the logging call, which happens after the callback |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| adSelectionService.resetAllAdSelectionConfigRemoteOverrides(callback); |
| resultLatch.await(); |
| return callback; |
| } |
| |
| private AdSelectionOverrideTestCallback callResetAllSelectionOutcomesOverrides( |
| AdSelectionServiceImpl adSelectionService) throws Exception { |
| // Counted down in 1) callback and 2) logApiCall |
| CountDownLatch resultLatch = new CountDownLatch(2); |
| AdSelectionOverrideTestCallback callback = new AdSelectionOverrideTestCallback(resultLatch); |
| |
| // Wait for the logging call, which happens after the callback |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| adSelectionService.resetAllAdSelectionFromOutcomesConfigRemoteOverrides(callback); |
| resultLatch.await(); |
| return callback; |
| } |
| |
| private AdSelectionFromOutcomesTestCallback invokeSelectAdsFromOutcomes( |
| AdSelectionServiceImpl adSelectionService, |
| AdSelectionFromOutcomesConfig adSelectionFromOutcomesConfig, |
| String callerPackageName) |
| throws InterruptedException, RemoteException { |
| |
| CountDownLatch countdownLatch = new CountDownLatch(1); |
| AdSelectionFromOutcomesTestCallback adSelectionTestCallback = |
| new AdSelectionFromOutcomesTestCallback(countdownLatch); |
| |
| AdSelectionFromOutcomesInput input = |
| new AdSelectionFromOutcomesInput.Builder() |
| .setAdSelectionFromOutcomesConfig(adSelectionFromOutcomesConfig) |
| .setCallerPackageName(callerPackageName) |
| .build(); |
| |
| adSelectionService.selectAdsFromOutcomes(input, null, adSelectionTestCallback); |
| adSelectionTestCallback.mCountDownLatch.await(); |
| return adSelectionTestCallback; |
| } |
| |
| private ReportImpressionTestCallback callReportImpression( |
| AdSelectionServiceImpl adSelectionService, ReportImpressionInput requestParams) |
| throws Exception { |
| return callReportImpression(adSelectionService, requestParams, false); |
| } |
| |
| /** @param shouldCountLog if true, adds a latch to the log interaction as well. */ |
| private ReportImpressionTestCallback callReportImpression( |
| AdSelectionServiceImpl adSelectionService, |
| ReportImpressionInput requestParams, |
| boolean shouldCountLog) |
| throws Exception { |
| CountDownLatch resultLatch = new CountDownLatch(shouldCountLog ? 2 : 1); |
| |
| if (shouldCountLog) { |
| // Wait for the logging call, which happens after the callback |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| sLogger.i("Log called."); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| } |
| |
| ReportImpressionTestCallback callback = new ReportImpressionTestCallback(resultLatch); |
| adSelectionService.reportImpression(requestParams, callback); |
| resultLatch.await(); |
| return callback; |
| } |
| |
| private AppInstallAdvertisersSetterTest.SetAppInstallAdvertisersTestCallback |
| callSetAppInstallAdvertisers( |
| AdSelectionServiceImpl adSelectionService, |
| SetAppInstallAdvertisersInput request) |
| throws Exception { |
| // Counted down in callback |
| CountDownLatch resultLatch = new CountDownLatch(1); |
| AppInstallAdvertisersSetterTest.SetAppInstallAdvertisersTestCallback callback = |
| new AppInstallAdvertisersSetterTest.SetAppInstallAdvertisersTestCallback( |
| resultLatch); |
| |
| adSelectionService.setAppInstallAdvertisers(request, callback); |
| resultLatch.await(); |
| return callback; |
| } |
| |
| private UpdateAdCounterHistogramTestCallback callUpdateAdCounterHistogram( |
| AdSelectionServiceImpl adSelectionService, UpdateAdCounterHistogramInput inputParams) |
| throws InterruptedException { |
| // Counted down in 1) callback and 2) logApiCall |
| CountDownLatch resultLatch = new CountDownLatch(2); |
| UpdateAdCounterHistogramTestCallback callback = |
| new UpdateAdCounterHistogramTestCallback(resultLatch); |
| |
| // Wait for the logging call, which happens after the callback |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| adSelectionService.updateAdCounterHistogram(inputParams, callback); |
| assertTrue( |
| "Timed out waiting for updateAdCounterHistogram call to complete", |
| resultLatch.await(5, TimeUnit.SECONDS)); |
| return callback; |
| } |
| |
| private AdSelectionOverrideTestCallback callSetAdCounterHistogramOverride( |
| AdSelectionServiceImpl adSelectionService, |
| SetAdCounterHistogramOverrideInput inputParams) |
| throws InterruptedException { |
| // Counted down in 1) callback and 2) logApiCall |
| CountDownLatch resultLatch = new CountDownLatch(2); |
| AdSelectionOverrideTestCallback callback = new AdSelectionOverrideTestCallback(resultLatch); |
| |
| // Wait for the logging call, which happens after the callback |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| adSelectionService.setAdCounterHistogramOverride(inputParams, callback); |
| assertTrue( |
| "Timed out waiting for setAdCounterHistogramOverride call to complete", |
| resultLatch.await(5, TimeUnit.SECONDS)); |
| return callback; |
| } |
| |
| private AdSelectionOverrideTestCallback callRemoveAdCounterHistogramOverride( |
| AdSelectionServiceImpl adSelectionService, |
| RemoveAdCounterHistogramOverrideInput inputParams) |
| throws InterruptedException { |
| // Counted down in 1) callback and 2) logApiCall |
| CountDownLatch resultLatch = new CountDownLatch(2); |
| AdSelectionOverrideTestCallback callback = new AdSelectionOverrideTestCallback(resultLatch); |
| |
| // Wait for the logging call, which happens after the callback |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| adSelectionService.removeAdCounterHistogramOverride(inputParams, callback); |
| assertTrue( |
| "Timed out waiting for removeAdCounterHistogramOverride call to complete", |
| resultLatch.await(5, TimeUnit.SECONDS)); |
| return callback; |
| } |
| |
| private AdSelectionOverrideTestCallback callResetAllAdCounterHistogramOverrides( |
| AdSelectionServiceImpl adSelectionService) throws InterruptedException { |
| // Counted down in 1) callback and 2) logApiCall |
| CountDownLatch resultLatch = new CountDownLatch(2); |
| AdSelectionOverrideTestCallback callback = new AdSelectionOverrideTestCallback(resultLatch); |
| |
| // Wait for the logging call, which happens after the callback |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| |
| adSelectionService.resetAllAdCounterHistogramOverrides(callback); |
| assertTrue( |
| "Timed out waiting for resetAllAdCounterHistogramOverrides call to complete", |
| resultLatch.await(5, TimeUnit.SECONDS)); |
| return callback; |
| } |
| |
| private ReportInteractionTestCallback callReportInteraction( |
| AdSelectionServiceImpl adSelectionService, ReportInteractionInput inputParams) |
| throws Exception { |
| return callReportInteraction(adSelectionService, inputParams, false); |
| } |
| |
| /** @param shouldCountLog if true, adds a latch to the log interaction as well. */ |
| private ReportInteractionTestCallback callReportInteraction( |
| AdSelectionServiceImpl adSelectionService, |
| ReportInteractionInput inputParams, |
| boolean shouldCountLog) |
| throws Exception { |
| CountDownLatch resultLatch = new CountDownLatch(shouldCountLog ? 2 : 1); |
| |
| if (shouldCountLog) { |
| // Wait for the logging call, which happens after the callback |
| Answer<Void> countDownAnswer = |
| unused -> { |
| resultLatch.countDown(); |
| return null; |
| }; |
| doAnswer(countDownAnswer) |
| .when(mAdServicesLoggerMock) |
| .logFledgeApiCallStats(anyInt(), anyInt(), anyInt()); |
| } |
| |
| ReportInteractionTestCallback callback = new ReportInteractionTestCallback(resultLatch); |
| adSelectionService.reportInteraction(inputParams, callback); |
| resultLatch.await(); |
| return callback; |
| } |
| |
| private String insertJsWait(long waitTime) { |
| return " const wait = (ms) => {\n" |
| + " var start = new Date().getTime();\n" |
| + " var end = start;\n" |
| + " while(end < start + ms) {\n" |
| + " end = new Date().getTime();\n" |
| + " }\n" |
| + " }\n" |
| + String.format(Locale.ENGLISH, " wait(\"%d\");\n", waitTime); |
| } |
| |
| public static class ReportImpressionTestCallback extends ReportImpressionCallback.Stub { |
| private final CountDownLatch mCountDownLatch; |
| boolean mIsSuccess = false; |
| FledgeErrorResponse mFledgeErrorResponse; |
| |
| public ReportImpressionTestCallback(CountDownLatch countDownLatch) { |
| mCountDownLatch = countDownLatch; |
| } |
| |
| @Override |
| public void onSuccess() throws RemoteException { |
| mIsSuccess = true; |
| mCountDownLatch.countDown(); |
| } |
| |
| @Override |
| public void onFailure(FledgeErrorResponse fledgeErrorResponse) throws RemoteException { |
| mFledgeErrorResponse = fledgeErrorResponse; |
| mCountDownLatch.countDown(); |
| } |
| } |
| |
| public static class UpdateAdCounterHistogramTestCallback |
| extends UpdateAdCounterHistogramCallback.Stub { |
| protected final CountDownLatch mCountDownLatch; |
| boolean mIsSuccess = false; |
| FledgeErrorResponse mFledgeErrorResponse; |
| |
| public UpdateAdCounterHistogramTestCallback(CountDownLatch countDownLatch) { |
| mCountDownLatch = countDownLatch; |
| } |
| |
| @Override |
| public void onSuccess() throws RemoteException { |
| mIsSuccess = true; |
| mCountDownLatch.countDown(); |
| } |
| |
| @Override |
| public void onFailure(FledgeErrorResponse fledgeErrorResponse) throws RemoteException { |
| mFledgeErrorResponse = fledgeErrorResponse; |
| mCountDownLatch.countDown(); |
| } |
| } |
| |
| public static class UpdateAdCounterHistogramTestErrorCallback |
| extends UpdateAdCounterHistogramTestCallback { |
| public UpdateAdCounterHistogramTestErrorCallback(CountDownLatch countDownLatch) { |
| super(countDownLatch); |
| } |
| |
| @Override |
| public void onSuccess() throws RemoteException { |
| mIsSuccess = true; |
| mCountDownLatch.countDown(); |
| throw new RemoteException(); |
| } |
| } |
| |
| public static class AdSelectionOverrideTestCallback extends AdSelectionOverrideCallback.Stub { |
| protected final CountDownLatch mCountDownLatch; |
| boolean mIsSuccess = false; |
| FledgeErrorResponse mFledgeErrorResponse; |
| |
| public AdSelectionOverrideTestCallback(CountDownLatch countDownLatch) { |
| mCountDownLatch = countDownLatch; |
| } |
| |
| @Override |
| public void onSuccess() throws RemoteException { |
| mIsSuccess = true; |
| mCountDownLatch.countDown(); |
| } |
| |
| @Override |
| public void onFailure(FledgeErrorResponse fledgeErrorResponse) throws RemoteException { |
| mFledgeErrorResponse = fledgeErrorResponse; |
| mCountDownLatch.countDown(); |
| } |
| } |
| |
| static class AdSelectionFromOutcomesTestCallback extends AdSelectionCallback.Stub { |
| |
| final CountDownLatch mCountDownLatch; |
| boolean mIsSuccess = false; |
| AdSelectionResponse mAdSelectionResponse; |
| FledgeErrorResponse mFledgeErrorResponse; |
| |
| AdSelectionFromOutcomesTestCallback(CountDownLatch countDownLatch) { |
| mCountDownLatch = countDownLatch; |
| mAdSelectionResponse = null; |
| mFledgeErrorResponse = null; |
| } |
| |
| @Override |
| public void onSuccess(AdSelectionResponse adSelectionResponse) throws RemoteException { |
| mIsSuccess = true; |
| mAdSelectionResponse = adSelectionResponse; |
| mCountDownLatch.countDown(); |
| } |
| |
| @Override |
| public void onFailure(FledgeErrorResponse fledgeErrorResponse) throws RemoteException { |
| mIsSuccess = false; |
| mFledgeErrorResponse = fledgeErrorResponse; |
| mCountDownLatch.countDown(); |
| } |
| } |
| |
| static class ReportInteractionTestCallback extends ReportInteractionCallback.Stub { |
| protected final CountDownLatch mCountDownLatch; |
| boolean mIsSuccess = false; |
| FledgeErrorResponse mFledgeErrorResponse; |
| |
| ReportInteractionTestCallback(CountDownLatch countDownLatch) { |
| mCountDownLatch = countDownLatch; |
| } |
| |
| @Override |
| public void onSuccess() throws RemoteException { |
| mIsSuccess = true; |
| mCountDownLatch.countDown(); |
| } |
| |
| @Override |
| public void onFailure(FledgeErrorResponse fledgeErrorResponse) throws RemoteException { |
| mFledgeErrorResponse = fledgeErrorResponse; |
| mCountDownLatch.countDown(); |
| } |
| } |
| |
| public static class ReportInteractionTestErrorCallback extends ReportInteractionTestCallback { |
| public ReportInteractionTestErrorCallback(CountDownLatch countDownLatch) { |
| super(countDownLatch); |
| } |
| |
| @Override |
| public void onSuccess() throws RemoteException { |
| mIsSuccess = true; |
| mCountDownLatch.countDown(); |
| throw new RemoteException(); |
| } |
| } |
| |
| public static class AdSelectionOverrideTestErrorCallback |
| extends AdSelectionOverrideTestCallback { |
| public AdSelectionOverrideTestErrorCallback(CountDownLatch countDownLatch) { |
| super(countDownLatch); |
| } |
| |
| @Override |
| public void onSuccess() throws RemoteException { |
| mIsSuccess = true; |
| mCountDownLatch.countDown(); |
| throw new RemoteException(); |
| } |
| } |
| |
| private static class FlagsWithEnrollmentCheckEnabledSwitch implements Flags { |
| private final boolean mEnrollmentCheckEnabled; |
| |
| FlagsWithEnrollmentCheckEnabledSwitch(boolean enrollmentCheckEnabled) { |
| mEnrollmentCheckEnabled = enrollmentCheckEnabled; |
| } |
| |
| @Override |
| public boolean getDisableFledgeEnrollmentCheck() { |
| return !mEnrollmentCheckEnabled; |
| } |
| |
| @Override |
| public boolean getEnforceForegroundStatusForFledgeRunAdSelection() { |
| return true; |
| } |
| |
| @Override |
| public boolean getEnforceForegroundStatusForFledgeReportImpression() { |
| return true; |
| } |
| |
| @Override |
| public boolean getEnforceForegroundStatusForFledgeOverrides() { |
| return true; |
| } |
| |
| @Override |
| public long getReportImpressionOverallTimeoutMs() { |
| return 1000; |
| } |
| |
| @Override |
| public boolean getEnforceIsolateMaxHeapSize() { |
| return false; |
| } |
| |
| @Override |
| public float getSdkRequestPermitsPerSecond() { |
| // Unlimited rate for unit tests to avoid flake in tests due to rate limiting |
| return -1; |
| } |
| |
| @Override |
| public boolean getFledgeRegisterAdBeaconEnabled() { |
| return true; |
| } |
| |
| @Override |
| public boolean getFledgeAdSelectionFilteringEnabled() { |
| return false; |
| } |
| } |
| } |