blob: ca7368f6b323ee38ecaa3294558821b40b643ba1 [file] [log] [blame]
/*
* 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.common.AdServicesStatusUtils.STATUS_INTERNAL_ERROR;
import static android.adservices.common.AdServicesStatusUtils.STATUS_INVALID_ARGUMENT;
import static android.adservices.common.AdServicesStatusUtils.STATUS_SUCCESS;
import static com.android.adservices.service.adselection.AdSelectionConfigValidator.DECISION_LOGIC_URI_TYPE;
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.stats.FledgeApiCallStatsMatcher.aCallStatForFledgeApiWithStatus;
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.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.adservices.adselection.AdSelectionConfig;
import android.adservices.adselection.AdSelectionConfigFixture;
import android.adservices.adselection.AdSelectionOverrideCallback;
import android.adservices.adselection.CustomAudienceSignalsFixture;
import android.adservices.adselection.ReportImpressionCallback;
import android.adservices.adselection.ReportImpressionInput;
import android.adservices.common.AdSelectionSignals;
import android.adservices.common.AdTechIdentifier;
import android.adservices.common.FledgeErrorResponse;
import android.adservices.http.MockWebServerRule;
import android.content.Context;
import android.net.Uri;
import android.os.RemoteException;
import androidx.room.Room;
import androidx.test.core.app.ApplicationProvider;
import com.android.adservices.MockWebServerRuleFactory;
import com.android.adservices.data.adselection.AdSelectionDatabase;
import com.android.adservices.data.adselection.AdSelectionEntryDao;
import com.android.adservices.data.adselection.CustomAudienceSignals;
import com.android.adservices.data.adselection.DBAdSelection;
import com.android.adservices.data.adselection.DBAdSelectionOverride;
import com.android.adservices.data.adselection.DBBuyerDecisionLogic;
import com.android.adservices.data.customaudience.CustomAudienceDao;
import com.android.adservices.data.customaudience.CustomAudienceDatabase;
import com.android.adservices.service.Flags;
import com.android.adservices.service.common.AdServicesHttpsClient;
import com.android.adservices.service.common.ValidatorTestUtil;
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.js.JSScriptEngine;
import com.android.adservices.service.stats.AdServicesLogger;
import com.android.adservices.service.stats.AdServicesLoggerImpl;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.google.common.collect.ImmutableList;
import com.google.mockwebserver.MockResponse;
import com.google.mockwebserver.MockWebServer;
import com.google.mockwebserver.RecordedRequest;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoSession;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
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.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class AdSelectionServiceImplTest {
private static final Context CONTEXT = ApplicationProvider.getApplicationContext();
private static final Clock CLOCK = Clock.fixed(Instant.now(), ZoneOffset.UTC);
private static final Uri RENDER_URL = Uri.parse("http://www.domain.com/advert/");
private static final Instant ACTIVATION_TIME = CLOCK.instant().truncatedTo(ChronoUnit.MILLIS);
private static final Uri BUYER_BIDDING_LOGIC_URI = Uri.parse("http://www.seller.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("developer.android.com");
private static final Uri DECISION_LOGIC_URI_INCONSISTENT =
Uri.parse("https://developer%$android.com/test/decisions_logic_urls");
private static final String DUMMY_DECISION_LOGIC_JS =
"function test() { return \"hello world\"; }";
private static final AdSelectionSignals DUMMY_TRUSTED_SCORING_SIGNALS =
AdSelectionSignals.fromString(
"{\n"
+ "\t\"render_url_1\": \"signals_for_1\",\n"
+ "\t\"render_url_2\": \"signals_for_2\"\n"
+ "}");
// 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 final ExecutorService mExecutorService = Executors.newFixedThreadPool(20);
private final String mSellerReportingPath = "/reporting/seller";
private final String mBuyerReportingPath = "/reporting/buyer";
private final String mFetchJavaScriptPath = "/fetchJavascript/";
private final String mFetchTrustedScoringSignalsPath = "/fetchTrustedSignals/";
private final AdTechIdentifier mContextualSignals =
AdTechIdentifier.fromString("{\"contextual_signals\":1}");
private static final String TIMEOUT_MESSAGE = "Timed out:";
private final int mBytesPerPeriod = 1;
private final AdServicesHttpsClient mClient = new AdServicesHttpsClient(mExecutorService);
private final Flags mFlags =
new Flags() {
@Override
public long getReportImpressionOverallTimeoutMs() {
return 500;
}
};
private MockitoSession mStaticMockSession = null;
@Spy private final AdServicesLogger mAdServicesLoggerSpy = AdServicesLoggerImpl.getInstance();
@Rule public MockWebServerRule mMockWebServerRule = MockWebServerRuleFactory.createForHttps();
@Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
// This object access some system APIs
@Mock public DevContextFilter mDevContextFilter;
private CustomAudienceDao mCustomAudienceDao;
private AdSelectionEntryDao mAdSelectionEntryDao;
private AdSelectionConfig.Builder mAdSelectionConfigBuilder;
@Before
public void setUp() {
mCustomAudienceDao =
Room.inMemoryDatabaseBuilder(CONTEXT, CustomAudienceDatabase.class)
.build()
.customAudienceDao();
mAdSelectionEntryDao =
Room.inMemoryDatabaseBuilder(
ApplicationProvider.getApplicationContext(),
AdSelectionDatabase.class)
.build()
.adSelectionEntryDao();
mAdSelectionConfigBuilder =
AdSelectionConfigFixture.anAdSelectionConfigBuilder()
.setSeller(
AdTechIdentifier.fromString(
mMockWebServerRule
.uriForPath(mFetchJavaScriptPath)
.getHost()))
.setDecisionLogicUri(mMockWebServerRule.uriForPath(mFetchJavaScriptPath))
.setTrustedScoringSignalsUri(
mMockWebServerRule.uriForPath(mFetchTrustedScoringSignalsPath));
}
@Test
public void testReportImpressionSuccess() throws Exception {
Uri sellerReportingUrl = mMockWebServerRule.uriForPath(mSellerReportingPath);
Uri buyerReportingUrl = mMockWebServerRule.uriForPath(mBuyerReportingPath);
String sellerDecisionLogicJs =
"function reportResult(ad_selection_config, render_url, bid, contextual_signals) {"
+ " \n"
+ " return {'status': 0, 'results': {'signals_for_buyer':"
+ " '{\"signals_for_buyer\":1}', 'reporting_url': '"
+ sellerReportingUrl
+ "' } };\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_url': '"
+ buyerReportingUrl
+ "' } };\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();
CustomAudienceSignals customAudienceSignals =
CustomAudienceSignalsFixture.aCustomAudienceSignals();
DBAdSelection dbAdSelection =
new DBAdSelection.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setCustomAudienceSignals(customAudienceSignals)
.setContextualSignals(mContextualSignals.getStringForm())
.setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI)
.setWinningAdRenderUri(RENDER_URL)
.setWinningAdBid(BID)
.setCreationTimestamp(ACTIVATION_TIME)
.build();
mAdSelectionEntryDao.persistAdSelection(dbAdSelection);
mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic);
AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build();
when(mDevContextFilter.createDevContext())
.thenReturn(DevContext.createForDevOptionsDisabled());
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
ReportImpressionInput input =
new ReportImpressionInput.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setAdSelectionConfig(adSelectionConfig)
.build();
ReportImpressionTestCallback callback = callReportImpression(adSelectionService, input);
assertTrue(callback.mIsSuccess);
RecordedRequest fetchRequest = server.takeRequest();
assertEquals(mFetchJavaScriptPath, fetchRequest.getPath());
List<String> notifications =
ImmutableList.of(server.takeRequest().getPath(), server.takeRequest().getPath());
assertThat(notifications).containsExactly(mSellerReportingPath, mBuyerReportingPath);
verify(mAdServicesLoggerSpy)
.logFledgeApiCallStats(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION, STATUS_SUCCESS);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION,
STATUS_SUCCESS));
}
@Test
public void testReportImpressionFailsWhenReportResultTakesTooLong() throws Exception {
Uri sellerReportingUrl = mMockWebServerRule.uriForPath(mSellerReportingPath);
Uri buyerReportingUrl = mMockWebServerRule.uriForPath(mBuyerReportingPath);
String jsWaitMoreThanAllowed =
insertJsWait(2 * mFlags.getReportImpressionOverallTimeoutMs());
String sellerDecisionLogicJs =
"function reportResult(ad_selection_config, render_url, bid, contextual_signals) {"
+ " \n"
+ jsWaitMoreThanAllowed
+ " return {'status': 0, 'results': {'signals_for_buyer':"
+ " '{\"signals_for_buyer\":1}', 'reporting_url': '"
+ sellerReportingUrl
+ "' } };\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_url': '"
+ buyerReportingUrl
+ "' } };\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();
CustomAudienceSignals customAudienceSignals =
CustomAudienceSignalsFixture.aCustomAudienceSignals();
DBAdSelection dbAdSelection =
new DBAdSelection.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setCustomAudienceSignals(customAudienceSignals)
.setContextualSignals(mContextualSignals.getStringForm())
.setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI)
.setWinningAdRenderUri(RENDER_URL)
.setWinningAdBid(BID)
.setCreationTimestamp(ACTIVATION_TIME)
.build();
mAdSelectionEntryDao.persistAdSelection(dbAdSelection);
mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic);
AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build();
when(mDevContextFilter.createDevContext())
.thenReturn(DevContext.createForDevOptionsDisabled());
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
ReportImpressionInput input =
new ReportImpressionInput.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setAdSelectionConfig(adSelectionConfig)
.build();
ReportImpressionTestCallback callback = callReportImpression(adSelectionService, input);
assertFalse(callback.mIsSuccess);
assertEquals(callback.mFledgeErrorResponse.getStatusCode(), STATUS_INTERNAL_ERROR);
assertTrue(callback.mFledgeErrorResponse.getErrorMessage().contains(TIMEOUT_MESSAGE));
verify(mAdServicesLoggerSpy)
.logFledgeApiCallStats(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION, STATUS_INTERNAL_ERROR);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION,
STATUS_INTERNAL_ERROR));
}
@Test
public void testReportImpressionFailsWhenReportWinTakesTooLong() throws Exception {
Uri sellerReportingUrl = mMockWebServerRule.uriForPath(mSellerReportingPath);
Uri buyerReportingUrl = mMockWebServerRule.uriForPath(mBuyerReportingPath);
String jsWaitMoreThanAllowed =
insertJsWait(2 * mFlags.getReportImpressionOverallTimeoutMs());
String sellerDecisionLogicJs =
"function reportResult(ad_selection_config, render_url, bid, contextual_signals) {"
+ " \n"
+ " return {'status': 0, 'results': {'signals_for_buyer':"
+ " '{\"signals_for_buyer\":1}', 'reporting_url': '"
+ sellerReportingUrl
+ "' } };\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_url': '"
+ buyerReportingUrl
+ "' } };\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();
CustomAudienceSignals customAudienceSignals =
CustomAudienceSignalsFixture.aCustomAudienceSignals();
DBAdSelection dbAdSelection =
new DBAdSelection.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setCustomAudienceSignals(customAudienceSignals)
.setContextualSignals(mContextualSignals.getStringForm())
.setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI)
.setWinningAdRenderUri(RENDER_URL)
.setWinningAdBid(BID)
.setCreationTimestamp(ACTIVATION_TIME)
.build();
mAdSelectionEntryDao.persistAdSelection(dbAdSelection);
mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic);
AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build();
when(mDevContextFilter.createDevContext())
.thenReturn(DevContext.createForDevOptionsDisabled());
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
ReportImpressionInput input =
new ReportImpressionInput.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setAdSelectionConfig(adSelectionConfig)
.build();
ReportImpressionTestCallback callback = callReportImpression(adSelectionService, input);
assertFalse(callback.mIsSuccess);
assertEquals(callback.mFledgeErrorResponse.getStatusCode(), STATUS_INTERNAL_ERROR);
assertTrue(callback.mFledgeErrorResponse.getErrorMessage().contains(TIMEOUT_MESSAGE));
verify(mAdServicesLoggerSpy)
.logFledgeApiCallStats(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION, STATUS_INTERNAL_ERROR);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION,
STATUS_INTERNAL_ERROR));
}
@Test
public void testReportImpressionFailsWhenOverallJSTimesOut() throws Exception {
Uri sellerReportingUrl = mMockWebServerRule.uriForPath(mSellerReportingPath);
Uri buyerReportingUrl = mMockWebServerRule.uriForPath(mBuyerReportingPath);
String jsWaitMoreThanAllowed =
insertJsWait((long) (.25 * mFlags.getReportImpressionOverallTimeoutMs()));
String sellerDecisionLogicJs =
"function reportResult(ad_selection_config, render_url, bid, contextual_signals) {"
+ " \n"
+ jsWaitMoreThanAllowed
+ " return {'status': 0, 'results': {'signals_for_buyer':"
+ " '{\"signals_for_buyer\":1}', 'reporting_url': '"
+ sellerReportingUrl
+ "' } };\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_url': '"
+ buyerReportingUrl
+ "' } };\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();
CustomAudienceSignals customAudienceSignals =
CustomAudienceSignalsFixture.aCustomAudienceSignals();
DBAdSelection dbAdSelection =
new DBAdSelection.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setCustomAudienceSignals(customAudienceSignals)
.setContextualSignals(mContextualSignals.getStringForm())
.setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI)
.setWinningAdRenderUri(RENDER_URL)
.setWinningAdBid(BID)
.setCreationTimestamp(ACTIVATION_TIME)
.build();
mAdSelectionEntryDao.persistAdSelection(dbAdSelection);
mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic);
AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build();
when(mDevContextFilter.createDevContext())
.thenReturn(DevContext.createForDevOptionsDisabled());
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
ReportImpressionInput input =
new ReportImpressionInput.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setAdSelectionConfig(adSelectionConfig)
.build();
ReportImpressionTestCallback callback = callReportImpression(adSelectionService, input);
assertFalse(callback.mIsSuccess);
assertEquals(callback.mFledgeErrorResponse.getStatusCode(), STATUS_INTERNAL_ERROR);
assertTrue(callback.mFledgeErrorResponse.getErrorMessage().contains(TIMEOUT_MESSAGE));
verify(mAdServicesLoggerSpy)
.logFledgeApiCallStats(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION, STATUS_INTERNAL_ERROR);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION,
STATUS_INTERNAL_ERROR));
}
@Test
public void testReportImpressionFailsWhenJSFetchTakesTooLong() throws Exception {
Uri sellerReportingUrl = mMockWebServerRule.uriForPath(mSellerReportingPath);
Uri buyerReportingUrl = mMockWebServerRule.uriForPath(mBuyerReportingPath);
String sellerDecisionLogicJs =
"function reportResult(ad_selection_config, render_url, bid, contextual_signals) {"
+ " \n"
+ " return {'status': 0, 'results': {'signals_for_buyer':"
+ " '{\"signals_for_buyer\":1}', 'reporting_url': '"
+ sellerReportingUrl
+ "' } };\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_url': '"
+ buyerReportingUrl
+ "' } };\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();
CustomAudienceSignals customAudienceSignals =
CustomAudienceSignalsFixture.aCustomAudienceSignals();
DBAdSelection dbAdSelection =
new DBAdSelection.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setCustomAudienceSignals(customAudienceSignals)
.setContextualSignals(mContextualSignals.getStringForm())
.setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI)
.setWinningAdRenderUri(RENDER_URL)
.setWinningAdBid(BID)
.setCreationTimestamp(ACTIVATION_TIME)
.build();
mAdSelectionEntryDao.persistAdSelection(dbAdSelection);
mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic);
AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build();
when(mDevContextFilter.createDevContext())
.thenReturn(DevContext.createForDevOptionsDisabled());
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
ReportImpressionInput input =
new ReportImpressionInput.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setAdSelectionConfig(adSelectionConfig)
.build();
ReportImpressionTestCallback callback = callReportImpression(adSelectionService, input);
assertFalse(callback.mIsSuccess);
assertEquals(callback.mFledgeErrorResponse.getStatusCode(), STATUS_INTERNAL_ERROR);
assertTrue(callback.mFledgeErrorResponse.getErrorMessage().contains(TIMEOUT_MESSAGE));
verify(mAdServicesLoggerSpy)
.logFledgeApiCallStats(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION, STATUS_INTERNAL_ERROR);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION,
STATUS_INTERNAL_ERROR));
}
@Test
public void testReportImpressionFailsWithInvalidAdSelectionId() throws Exception {
Uri sellerReportingUrl = mMockWebServerRule.uriForPath(mSellerReportingPath);
Uri buyerReportingUrl = mMockWebServerRule.uriForPath(mBuyerReportingPath);
String sellerDecisionLogicJs =
"function reportResult(ad_selection_config, render_url, bid, contextual_signals) {"
+ " \n"
+ " return {'status': 0, 'results': {'signals_for_buyer':"
+ " '{\"signals_for_buyer\":1}', 'reporting_url': '"
+ sellerReportingUrl
+ "' } };\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_url': '"
+ buyerReportingUrl
+ "' } };\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();
CustomAudienceSignals customAudienceSignals =
CustomAudienceSignalsFixture.aCustomAudienceSignals();
DBAdSelection dbAdSelection =
new DBAdSelection.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setCustomAudienceSignals(customAudienceSignals)
.setContextualSignals(mContextualSignals.getStringForm())
.setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI)
.setWinningAdRenderUri(RENDER_URL)
.setWinningAdBid(BID)
.setCreationTimestamp(ACTIVATION_TIME)
.build();
mAdSelectionEntryDao.persistAdSelection(dbAdSelection);
mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic);
when(mDevContextFilter.createDevContext())
.thenReturn(DevContext.createForDevOptionsDisabled());
AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build();
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
ReportImpressionInput request =
new ReportImpressionInput.Builder()
.setAdSelectionId(INCORRECT_AD_SELECTION_ID)
.setAdSelectionConfig(adSelectionConfig)
.build();
ReportImpressionTestCallback callback = callReportImpression(adSelectionService, request);
assertFalse(callback.mIsSuccess);
assertEquals(callback.mFledgeErrorResponse.getStatusCode(), STATUS_INVALID_ARGUMENT);
verify(mAdServicesLoggerSpy)
.logFledgeApiCallStats(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION,
STATUS_INVALID_ARGUMENT);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION,
STATUS_INVALID_ARGUMENT));
}
@Test
public void testReportImpressionBadSellerJavascriptFailsWithInternalError() throws Exception {
Uri sellerReportingUrl = mMockWebServerRule.uriForPath(mSellerReportingPath);
Uri buyerReportingUrl = mMockWebServerRule.uriForPath(mBuyerReportingPath);
String invalidSellerDecisionLogicJsMissingCurlyBracket =
"function reportResult(ad_selection_config, render_url, bid, contextual_signals) {"
+ " \n"
+ " return {'status': 0, 'results': 'signals_for_buyer':"
+ " '{\"signals_for_buyer\":1}', 'reporting_url': '"
+ sellerReportingUrl
+ "' } };\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_url': '"
+ buyerReportingUrl
+ "' } };\n"
+ "}";
MockWebServer server =
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();
CustomAudienceSignals customAudienceSignals =
CustomAudienceSignalsFixture.aCustomAudienceSignals();
DBAdSelection dbAdSelection =
new DBAdSelection.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setCustomAudienceSignals(customAudienceSignals)
.setContextualSignals(mContextualSignals.getStringForm())
.setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI)
.setWinningAdRenderUri(RENDER_URL)
.setWinningAdBid(BID)
.setCreationTimestamp(ACTIVATION_TIME)
.build();
mAdSelectionEntryDao.persistAdSelection(dbAdSelection);
mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic);
when(mDevContextFilter.createDevContext())
.thenReturn(DevContext.createForDevOptionsDisabled());
AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build();
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
ReportImpressionInput request =
new ReportImpressionInput.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setAdSelectionConfig(adSelectionConfig)
.build();
ReportImpressionTestCallback callback = callReportImpression(adSelectionService, request);
assertFalse(callback.mIsSuccess);
assertEquals(callback.mFledgeErrorResponse.getStatusCode(), STATUS_INTERNAL_ERROR);
verify(mAdServicesLoggerSpy)
.logFledgeApiCallStats(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION, STATUS_INTERNAL_ERROR);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION,
STATUS_INTERNAL_ERROR));
}
@Test
public void testReportImpressionBadBuyerJavascriptFailsWithInternalError() throws Exception {
Uri sellerReportingUrl = mMockWebServerRule.uriForPath(mSellerReportingPath);
Uri buyerReportingUrl = mMockWebServerRule.uriForPath(mBuyerReportingPath);
String sellerDecisionLogicJs =
"function reportResult(ad_selection_config, render_url, bid, contextual_signals) {"
+ " \n"
+ " return {'status': 0, 'results': {'signals_for_buyer':"
+ " '{\"signals_for_buyer\":1}', 'reporting_url': '"
+ sellerReportingUrl
+ "' } };\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_url': '"
+ buyerReportingUrl
+ "' } };\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(inValidBuyerDecisionLogicJsMissingCurlyBracket)
.build();
CustomAudienceSignals customAudienceSignals =
CustomAudienceSignalsFixture.aCustomAudienceSignals();
DBAdSelection dbAdSelection =
new DBAdSelection.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setCustomAudienceSignals(customAudienceSignals)
.setContextualSignals(mContextualSignals.getStringForm())
.setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI)
.setWinningAdRenderUri(RENDER_URL)
.setWinningAdBid(BID)
.setCreationTimestamp(ACTIVATION_TIME)
.build();
mAdSelectionEntryDao.persistAdSelection(dbAdSelection);
mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic);
when(mDevContextFilter.createDevContext())
.thenReturn(DevContext.createForDevOptionsDisabled());
AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build();
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
ReportImpressionInput request =
new ReportImpressionInput.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setAdSelectionConfig(adSelectionConfig)
.build();
ReportImpressionTestCallback callback = callReportImpression(adSelectionService, request);
assertFalse(callback.mIsSuccess);
assertEquals(callback.mFledgeErrorResponse.getStatusCode(), STATUS_INTERNAL_ERROR);
verify(mAdServicesLoggerSpy)
.logFledgeApiCallStats(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION, STATUS_INTERNAL_ERROR);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION,
STATUS_INTERNAL_ERROR));
}
@Test
public void testReportImpressionContextualAdSuccess() throws Exception {
Uri sellerReportingUrl = mMockWebServerRule.uriForPath(mSellerReportingPath);
String sellerDecisionLogicJs =
"function reportResult(ad_selection_config, render_url, bid, contextual_signals) {"
+ " \n"
+ " return {'status': 0, 'results': {'signals_for_buyer':"
+ " '{\"signals_for_buyer\":1}', 'reporting_url': '"
+ sellerReportingUrl
+ "' } };\n"
+ "}";
MockWebServer server =
mMockWebServerRule.startMockWebServer(
List.of(
new MockResponse().setBody(sellerDecisionLogicJs),
new MockResponse()));
DBAdSelection dbAdSelection =
new DBAdSelection.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setContextualSignals(mContextualSignals.getStringForm())
.setWinningAdRenderUri(RENDER_URL)
.setWinningAdBid(BID)
.setCreationTimestamp(ACTIVATION_TIME)
.build();
mAdSelectionEntryDao.persistAdSelection(dbAdSelection);
when(mDevContextFilter.createDevContext())
.thenReturn(DevContext.createForDevOptionsDisabled());
AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build();
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
ReportImpressionInput request =
new ReportImpressionInput.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setAdSelectionConfig(adSelectionConfig)
.build();
ReportImpressionTestCallback callback = callReportImpression(adSelectionService, request);
assertTrue(callback.mIsSuccess);
RecordedRequest fetchRequest = server.takeRequest();
assertEquals(mFetchJavaScriptPath, fetchRequest.getPath());
RecordedRequest reportRequest = server.takeRequest();
assertEquals(mSellerReportingPath, reportRequest.getPath());
verify(mAdServicesLoggerSpy)
.logFledgeApiCallStats(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION, STATUS_SUCCESS);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION,
STATUS_SUCCESS));
}
@Test
public void testReportImpressionUseDevOverrideForSellerJS() throws Exception {
Uri sellerReportingUrl = mMockWebServerRule.uriForPath(mSellerReportingPath);
Uri buyerReportingUrl = mMockWebServerRule.uriForPath(mBuyerReportingPath);
String sellerDecisionLogicJs =
"function reportResult(ad_selection_config, render_url, bid, contextual_signals) {"
+ " \n"
+ " return {'status': 0, 'results': {'signals_for_buyer':"
+ " '{\"signals_for_buyer\":1}', 'reporting_url': '"
+ sellerReportingUrl
+ "' } };\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_url': '"
+ buyerReportingUrl
+ "' } };\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();
CustomAudienceSignals customAudienceSignals =
CustomAudienceSignalsFixture.aCustomAudienceSignals();
DBAdSelection dbAdSelection =
new DBAdSelection.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setCustomAudienceSignals(customAudienceSignals)
.setContextualSignals(mContextualSignals.getStringForm())
.setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI)
.setWinningAdRenderUri(RENDER_URL)
.setWinningAdBid(BID)
.setCreationTimestamp(ACTIVATION_TIME)
.build();
mAdSelectionEntryDao.persistAdSelection(dbAdSelection);
mAdSelectionEntryDao.persistBuyerDecisionLogic(dbBuyerDecisionLogic);
AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build();
when(mDevContextFilter.createDevContext())
.thenReturn(DevContext.createForDevOptionsDisabled());
// Set dev override for this AdSelection
String myAppPackageName = "com.google.ppapi.test";
DBAdSelectionOverride adSelectionOverride =
DBAdSelectionOverride.builder()
.setAdSelectionConfigId(
AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(
adSelectionConfig))
.setAppPackageName(myAppPackageName)
.setDecisionLogicJS(sellerDecisionLogicJs)
.setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.getStringForm())
.build();
mAdSelectionEntryDao.persistAdSelectionOverride(adSelectionOverride);
when(mDevContextFilter.createDevContext())
.thenReturn(
DevContext.builder()
.setDevOptionsEnabled(true)
.setCallingAppPackageName(myAppPackageName)
.build());
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
ReportImpressionInput input =
new ReportImpressionInput.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setAdSelectionConfig(adSelectionConfig)
.build();
ReportImpressionTestCallback callback = callReportImpression(adSelectionService, input);
assertTrue(callback.mIsSuccess);
List<String> notifications =
ImmutableList.of(server.takeRequest().getPath(), server.takeRequest().getPath());
assertThat(notifications).containsExactly(mSellerReportingPath, mBuyerReportingPath);
verify(mAdServicesLoggerSpy)
.logFledgeApiCallStats(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION, STATUS_SUCCESS);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION,
STATUS_SUCCESS));
}
@Test
public void testOverrideAdSelectionConfigRemoteInfoSuccess() throws Exception {
String myAppPackageName = "com.google.ppapi.test";
when(mDevContextFilter.createDevContext())
.thenReturn(
DevContext.builder()
.setDevOptionsEnabled(true)
.setCallingAppPackageName(myAppPackageName)
.build());
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build();
AdSelectionOverrideTestCallback callback =
callAddOverride(
adSelectionService,
adSelectionConfig,
DUMMY_DECISION_LOGIC_JS,
DUMMY_TRUSTED_SCORING_SIGNALS);
assertTrue(callback.mIsSuccess);
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(
adSelectionConfig),
myAppPackageName));
verify(mAdServicesLoggerSpy).logFledgeApiCallStats(SHORT_API_NAME_OVERRIDE, STATUS_SUCCESS);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(SHORT_API_NAME_OVERRIDE, STATUS_SUCCESS));
}
@Test
public void testOverrideAdSelectionConfigRemoteInfoFailsWithDevOptionsDisabled()
throws Exception {
String myAppPackageName = "com.google.ppapi.test";
when(mDevContextFilter.createDevContext())
.thenReturn(DevContext.createForDevOptionsDisabled());
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build();
assertThrows(
SecurityException.class,
() ->
callAddOverride(
adSelectionService,
adSelectionConfig,
DUMMY_DECISION_LOGIC_JS,
DUMMY_TRUSTED_SCORING_SIGNALS));
assertFalse(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(
adSelectionConfig),
myAppPackageName));
verify(mAdServicesLoggerSpy)
.logFledgeApiCallStats(SHORT_API_NAME_OVERRIDE, STATUS_INTERNAL_ERROR);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(
SHORT_API_NAME_OVERRIDE, STATUS_INTERNAL_ERROR));
}
@Test
public void testRemoveAdSelectionConfigRemoteInfoOverrideSuccess() throws Exception {
String myAppPackageName = "com.google.ppapi.test";
when(mDevContextFilter.createDevContext())
.thenReturn(
DevContext.builder()
.setDevOptionsEnabled(true)
.setCallingAppPackageName(myAppPackageName)
.build());
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build();
String adSelectionConfigId =
AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig);
DBAdSelectionOverride dbAdSelectionOverride =
DBAdSelectionOverride.builder()
.setAdSelectionConfigId(adSelectionConfigId)
.setAppPackageName(myAppPackageName)
.setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS)
.setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.getStringForm())
.build();
mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride);
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId, myAppPackageName));
AdSelectionOverrideTestCallback callback =
callRemoveOverride(adSelectionService, adSelectionConfig);
assertTrue(callback.mIsSuccess);
assertFalse(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId, myAppPackageName));
verify(mAdServicesLoggerSpy)
.logFledgeApiCallStats(SHORT_API_NAME_REMOVE_OVERRIDE, STATUS_SUCCESS);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(
SHORT_API_NAME_REMOVE_OVERRIDE, STATUS_SUCCESS));
}
@Test
public void testRemoveAdSelectionConfigRemoteInfoOverrideFailsWithDevOptionsDisabled()
throws Exception {
String myAppPackageName = "com.google.ppapi.test";
when(mDevContextFilter.createDevContext())
.thenReturn(DevContext.createForDevOptionsDisabled());
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build();
String adSelectionConfigId =
AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig);
DBAdSelectionOverride dbAdSelectionOverride =
DBAdSelectionOverride.builder()
.setAdSelectionConfigId(adSelectionConfigId)
.setAppPackageName(myAppPackageName)
.setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS)
.setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.getStringForm())
.build();
mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride);
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId, myAppPackageName));
assertThrows(
SecurityException.class,
() -> callRemoveOverride(adSelectionService, adSelectionConfig));
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId, myAppPackageName));
verify(mAdServicesLoggerSpy)
.logFledgeApiCallStats(SHORT_API_NAME_REMOVE_OVERRIDE, STATUS_INTERNAL_ERROR);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(
SHORT_API_NAME_REMOVE_OVERRIDE, STATUS_INTERNAL_ERROR));
}
@Test
public void testRemoveAdSelectionConfigRemoteInfoOverrideDoesNotDeleteWithIncorrectPackageName()
throws Exception {
String myAppPackageName = "com.google.ppapi.test";
String incorrectPackageName = "com.google.ppapi.test.incorrect";
when(mDevContextFilter.createDevContext())
.thenReturn(
DevContext.builder()
.setDevOptionsEnabled(true)
.setCallingAppPackageName(incorrectPackageName)
.build());
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
AdSelectionConfig adSelectionConfig = mAdSelectionConfigBuilder.build();
String adSelectionConfigId =
AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig);
DBAdSelectionOverride dbAdSelectionOverride =
DBAdSelectionOverride.builder()
.setAdSelectionConfigId(adSelectionConfigId)
.setAppPackageName(myAppPackageName)
.setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS)
.setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.getStringForm())
.build();
mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride);
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId, myAppPackageName));
AdSelectionOverrideTestCallback callback =
callRemoveOverride(adSelectionService, adSelectionConfig);
assertTrue(callback.mIsSuccess);
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId, myAppPackageName));
verify(mAdServicesLoggerSpy)
.logFledgeApiCallStats(SHORT_API_NAME_REMOVE_OVERRIDE, STATUS_SUCCESS);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(
SHORT_API_NAME_REMOVE_OVERRIDE, STATUS_SUCCESS));
}
@Test
public void testResetAllAdSelectionConfigRemoteOverridesDoesNotDeleteWithIncorrectPackageName()
throws Exception {
String myAppPackageName = "com.google.ppapi.test";
String incorrectPackageName = "com.google.ppapi.test.incorrect";
when(mDevContextFilter.createDevContext())
.thenReturn(
DevContext.builder()
.setDevOptionsEnabled(true)
.setCallingAppPackageName(incorrectPackageName)
.build());
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
AdSelectionConfig adSelectionConfig1 = mAdSelectionConfigBuilder.build();
AdSelectionConfig adSelectionConfig2 =
mAdSelectionConfigBuilder
.setSeller(AdTechIdentifier.fromString("adidas.com"))
.setDecisionLogicUri(Uri.parse("https://adidas.com/decisoin_logic_url"))
.build();
AdSelectionConfig adSelectionConfig3 =
mAdSelectionConfigBuilder
.setSeller(AdTechIdentifier.fromString("nike.com"))
.setDecisionLogicUri(Uri.parse("https://nike.com/decisoin_logic_url"))
.build();
String adSelectionConfigId1 =
AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig1);
String adSelectionConfigId2 =
AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig2);
String adSelectionConfigId3 =
AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig3);
DBAdSelectionOverride dbAdSelectionOverride1 =
DBAdSelectionOverride.builder()
.setAdSelectionConfigId(adSelectionConfigId1)
.setAppPackageName(myAppPackageName)
.setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS)
.setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.getStringForm())
.build();
DBAdSelectionOverride dbAdSelectionOverride2 =
DBAdSelectionOverride.builder()
.setAdSelectionConfigId(adSelectionConfigId2)
.setAppPackageName(myAppPackageName)
.setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS)
.setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.getStringForm())
.build();
DBAdSelectionOverride dbAdSelectionOverride3 =
DBAdSelectionOverride.builder()
.setAdSelectionConfigId(adSelectionConfigId3)
.setAppPackageName(myAppPackageName)
.setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS)
.setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.getStringForm())
.build();
mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride1);
mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride2);
mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride3);
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId1, myAppPackageName));
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId2, myAppPackageName));
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId3, myAppPackageName));
AdSelectionOverrideTestCallback callback = callResetAllOverrides(adSelectionService);
assertTrue(callback.mIsSuccess);
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId1, myAppPackageName));
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId2, myAppPackageName));
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId3, myAppPackageName));
verify(mAdServicesLoggerSpy)
.logFledgeApiCallStats(SHORT_API_NAME_RESET_ALL_OVERRIDES, STATUS_SUCCESS);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(
SHORT_API_NAME_RESET_ALL_OVERRIDES, STATUS_SUCCESS));
}
@Test
public void testResetAllAdSelectionConfigRemoteOverridesSuccess() throws Exception {
String myAppPackageName = "com.google.ppapi.test";
when(mDevContextFilter.createDevContext())
.thenReturn(
DevContext.builder()
.setDevOptionsEnabled(true)
.setCallingAppPackageName(myAppPackageName)
.build());
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
AdSelectionConfig adSelectionConfig1 = mAdSelectionConfigBuilder.build();
AdSelectionConfig adSelectionConfig2 =
mAdSelectionConfigBuilder
.setSeller(AdTechIdentifier.fromString("adidas.com"))
.setDecisionLogicUri(Uri.parse("https://adidas.com/decisoin_logic_url"))
.build();
AdSelectionConfig adSelectionConfig3 =
mAdSelectionConfigBuilder
.setSeller(AdTechIdentifier.fromString("nike.com"))
.setDecisionLogicUri(Uri.parse("https://nike.com/decisoin_logic_url"))
.build();
String adSelectionConfigId1 =
AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig1);
String adSelectionConfigId2 =
AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig2);
String adSelectionConfigId3 =
AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig3);
DBAdSelectionOverride dbAdSelectionOverride1 =
DBAdSelectionOverride.builder()
.setAdSelectionConfigId(adSelectionConfigId1)
.setAppPackageName(myAppPackageName)
.setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS)
.setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.getStringForm())
.build();
DBAdSelectionOverride dbAdSelectionOverride2 =
DBAdSelectionOverride.builder()
.setAdSelectionConfigId(adSelectionConfigId2)
.setAppPackageName(myAppPackageName)
.setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS)
.setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.getStringForm())
.build();
DBAdSelectionOverride dbAdSelectionOverride3 =
DBAdSelectionOverride.builder()
.setAdSelectionConfigId(adSelectionConfigId3)
.setAppPackageName(myAppPackageName)
.setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS)
.setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.getStringForm())
.build();
mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride1);
mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride2);
mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride3);
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId1, myAppPackageName));
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId2, myAppPackageName));
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId3, myAppPackageName));
AdSelectionOverrideTestCallback callback = callResetAllOverrides(adSelectionService);
assertTrue(callback.mIsSuccess);
assertFalse(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId1, myAppPackageName));
assertFalse(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId2, myAppPackageName));
assertFalse(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId3, myAppPackageName));
verify(mAdServicesLoggerSpy)
.logFledgeApiCallStats(SHORT_API_NAME_RESET_ALL_OVERRIDES, STATUS_SUCCESS);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(
SHORT_API_NAME_RESET_ALL_OVERRIDES, STATUS_SUCCESS));
}
@Test
public void testResetAllAdSelectionConfigRemoteOverridesFailsWithDevOptionsDisabled()
throws Exception {
String myAppPackageName = "com.google.ppapi.test";
when(mDevContextFilter.createDevContext())
.thenReturn(DevContext.createForDevOptionsDisabled());
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
AdSelectionConfig adSelectionConfig1 = mAdSelectionConfigBuilder.build();
AdSelectionConfig adSelectionConfig2 =
mAdSelectionConfigBuilder
.setSeller(AdTechIdentifier.fromString("adidas.com"))
.setDecisionLogicUri(Uri.parse("https://adidas.com/decisoin_logic_url"))
.build();
AdSelectionConfig adSelectionConfig3 =
mAdSelectionConfigBuilder
.setSeller(AdTechIdentifier.fromString("nike.com"))
.setDecisionLogicUri(Uri.parse("https://nike.com/decisoin_logic_url"))
.build();
String adSelectionConfigId1 =
AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig1);
String adSelectionConfigId2 =
AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig2);
String adSelectionConfigId3 =
AdSelectionDevOverridesHelper.calculateAdSelectionConfigId(adSelectionConfig3);
DBAdSelectionOverride dbAdSelectionOverride1 =
DBAdSelectionOverride.builder()
.setAdSelectionConfigId(adSelectionConfigId1)
.setAppPackageName(myAppPackageName)
.setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS)
.setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.getStringForm())
.build();
DBAdSelectionOverride dbAdSelectionOverride2 =
DBAdSelectionOverride.builder()
.setAdSelectionConfigId(adSelectionConfigId2)
.setAppPackageName(myAppPackageName)
.setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS)
.setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.getStringForm())
.build();
DBAdSelectionOverride dbAdSelectionOverride3 =
DBAdSelectionOverride.builder()
.setAdSelectionConfigId(adSelectionConfigId3)
.setAppPackageName(myAppPackageName)
.setDecisionLogicJS(DUMMY_DECISION_LOGIC_JS)
.setTrustedScoringSignals(DUMMY_TRUSTED_SCORING_SIGNALS.getStringForm())
.build();
mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride1);
mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride2);
mAdSelectionEntryDao.persistAdSelectionOverride(dbAdSelectionOverride3);
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId1, myAppPackageName));
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId2, myAppPackageName));
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId3, myAppPackageName));
assertThrows(SecurityException.class, () -> callResetAllOverrides(adSelectionService));
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId1, myAppPackageName));
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId2, myAppPackageName));
assertTrue(
mAdSelectionEntryDao.doesAdSelectionOverrideExistForPackageName(
adSelectionConfigId3, myAppPackageName));
verify(mAdServicesLoggerSpy)
.logFledgeApiCallStats(SHORT_API_NAME_RESET_ALL_OVERRIDES, STATUS_INTERNAL_ERROR);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(
SHORT_API_NAME_RESET_ALL_OVERRIDES, STATUS_INTERNAL_ERROR));
}
@Test
public void testCloseJSScriptEngineConnectionAtShutDown() {
mStaticMockSession =
ExtendedMockito.mockitoSession().spyStatic(JSScriptEngine.class).startMocking();
JSScriptEngine jsScriptEngineMock = mock(JSScriptEngine.class);
when(JSScriptEngine.getInstance(any())).thenReturn(jsScriptEngineMock);
AdSelectionServiceImpl adSelectionService =
new AdSelectionServiceImpl(
mAdSelectionEntryDao,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
adSelectionService.destroy();
verify(jsScriptEngineMock).shutdown();
}
private AdSelectionOverrideTestCallback callAddOverride(
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(mAdServicesLoggerSpy).logApiCallStats(any());
adSelectionService.overrideAdSelectionConfigRemoteInfo(
adSelectionConfig, decisionLogicJS, trustedScoringSignals, 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(mAdServicesLoggerSpy).logApiCallStats(any());
adSelectionService.removeAdSelectionConfigRemoteInfoOverride(adSelectionConfig, callback);
resultLatch.await();
return callback;
}
@Test
public void testAdSelectionConfigInvalidSellerAndSellerUrls() throws Exception {
Uri sellerReportingUrl = mMockWebServerRule.uriForPath(mSellerReportingPath);
Uri buyerReportingUrl = mMockWebServerRule.uriForPath(mBuyerReportingPath);
String sellerDecisionLogicJs =
"function reportResult(ad_selection_config, render_url, bid, contextual_signals) {"
+ " \n"
+ " return {'status': 0, 'results': {'signals_for_buyer':"
+ " '{\"signals_for_buyer\":1}', 'reporting_url': '"
+ sellerReportingUrl
+ "' } };\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_url': '"
+ buyerReportingUrl
+ "' } };\n"
+ "}";
DBBuyerDecisionLogic dbBuyerDecisionLogic =
new DBBuyerDecisionLogic.Builder()
.setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI)
.setBuyerDecisionLogicJs(buyerDecisionLogicJs)
.build();
CustomAudienceSignals customAudienceSignals =
CustomAudienceSignalsFixture.aCustomAudienceSignals();
DBAdSelection dbAdSelection =
new DBAdSelection.Builder()
.setAdSelectionId(AD_SELECTION_ID)
.setCustomAudienceSignals(customAudienceSignals)
.setContextualSignals(mContextualSignals.getStringForm())
.setBiddingLogicUri(BUYER_BIDDING_LOGIC_URI)
.setWinningAdRenderUri(RENDER_URL)
.setWinningAdBid(BID)
.setCreationTimestamp(ACTIVATION_TIME)
.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,
mCustomAudienceDao,
mClient,
mDevContextFilter,
mExecutorService,
CONTEXT,
mAdServicesLoggerSpy,
mFlags);
ReportImpressionInput request =
new ReportImpressionInput.Builder()
.setAdSelectionId(INCORRECT_AD_SELECTION_ID)
.setAdSelectionConfig(invalidAdSelectionConfig)
.build();
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> callReportImpression(adSelectionService, request));
ValidatorTestUtil.assertValidationFailuresMatch(
thrown,
String.format(
"Invalid object of type %s. The violations are:",
AdSelectionConfig.class.getName()),
ImmutableList.of(
String.format(
AdSelectionConfigValidator.SELLER_AND_URI_HOST_ARE_INCONSISTENT,
Uri.parse("https://" + SELLER_VALID).getHost(),
DECISION_LOGIC_URI_INCONSISTENT.getHost(),
DECISION_LOGIC_URI_TYPE)));
verify(mAdServicesLoggerSpy)
.logFledgeApiCallStats(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION,
STATUS_INVALID_ARGUMENT);
verify(mAdServicesLoggerSpy)
.logApiCallStats(
aCallStatForFledgeApiWithStatus(
AD_SERVICES_API_CALLED__API_NAME__REPORT_IMPRESSION,
STATUS_INVALID_ARGUMENT));
}
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(mAdServicesLoggerSpy).logApiCallStats(any());
adSelectionService.resetAllAdSelectionConfigRemoteOverrides(callback);
resultLatch.await();
return callback;
}
private ReportImpressionTestCallback callReportImpression(
AdSelectionServiceImpl adSelectionService, ReportImpressionInput requestParams)
throws Exception {
// Counted down in 1) callback and 2) logApiCall
CountDownLatch resultLatch = new CountDownLatch(2);
ReportImpressionTestCallback callback = new ReportImpressionTestCallback(resultLatch);
// Wait for the logging call, which happens after the callback
Answer<Void> countDownAnswer =
unused -> {
resultLatch.countDown();
return null;
};
doAnswer(countDownAnswer).when(mAdServicesLoggerSpy).logApiCallStats(any());
adSelectionService.reportImpression(requestParams, 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(" wait(\"%d\");\n", waitTime);
}
@After
public void tearDown() {
if (mStaticMockSession != null) {
mStaticMockSession.finishMocking();
}
}
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 AdSelectionOverrideTestCallback extends AdSelectionOverrideCallback.Stub {
private 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();
}
}
}