• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.adservices.test.scenario.adservices.fledge;
18 
19 import android.Manifest;
20 import android.adservices.adselection.AdSelectionConfig;
21 import android.adservices.clients.adselection.AdSelectionClient;
22 import android.adservices.clients.customaudience.AdvertisingCustomAudienceClient;
23 import android.adservices.common.AdData;
24 import android.adservices.common.AdSelectionSignals;
25 import android.adservices.common.AdTechIdentifier;
26 import android.adservices.customaudience.CustomAudience;
27 import android.adservices.customaudience.TrustedBiddingData;
28 import android.adservices.test.scenario.adservices.utils.MockWebServerRule;
29 import android.adservices.test.scenario.adservices.utils.MockWebServerRuleFactory;
30 import android.adservices.test.scenario.adservices.utils.SelectAdsFlagRule;
31 import android.content.Context;
32 import android.net.Uri;
33 import android.platform.test.rule.CleanPackageRule;
34 import android.platform.test.rule.KillAppsRule;
35 import android.platform.test.scenario.annotation.Scenario;
36 import android.provider.DeviceConfig;
37 
38 import androidx.test.core.app.ApplicationProvider;
39 import androidx.test.platform.app.InstrumentationRegistry;
40 
41 import com.android.adservices.common.AdservicesTestHelper;
42 import com.android.adservices.common.CompatAdServicesTestUtils;
43 import com.android.modules.utils.build.SdkLevel;
44 
45 import com.google.mockwebserver.Dispatcher;
46 import com.google.mockwebserver.MockResponse;
47 import com.google.mockwebserver.RecordedRequest;
48 
49 import org.junit.AfterClass;
50 import org.junit.Before;
51 import org.junit.BeforeClass;
52 import org.junit.Rule;
53 import org.junit.rules.RuleChain;
54 import org.junit.runner.RunWith;
55 import org.junit.runners.JUnit4;
56 
57 import java.time.Duration;
58 import java.time.Instant;
59 import java.util.ArrayList;
60 import java.util.Arrays;
61 import java.util.Collections;
62 import java.util.List;
63 import java.util.Map;
64 import java.util.concurrent.Executor;
65 import java.util.concurrent.Executors;
66 
67 @Scenario
68 @RunWith(JUnit4.class)
69 public class AbstractPerfTest {
70 
71     public static final Duration CUSTOM_AUDIENCE_EXPIRE_IN = Duration.ofDays(1);
72     public static final Instant VALID_ACTIVATION_TIME = Instant.now();
73     public static final Instant VALID_EXPIRATION_TIME =
74             VALID_ACTIVATION_TIME.plus(CUSTOM_AUDIENCE_EXPIRE_IN);
75     public static final String VALID_NAME = "testCustomAudienceName";
76     public static final AdSelectionSignals VALID_USER_BIDDING_SIGNALS =
77             AdSelectionSignals.fromString("{'valid': 'yep', 'opaque': 'definitely'}");
78     public static final String VALID_TRUSTED_BIDDING_URI_PATH = "/trusted/bidding/";
79     public static final ArrayList<String> VALID_TRUSTED_BIDDING_KEYS =
80             new ArrayList<>(Arrays.asList("example", "valid", "list", "of", "keys"));
81     public static final AdTechIdentifier SELLER = AdTechIdentifier.fromString("localhost");
82     // Uri Constants
83     public static final String DECISION_LOGIC_PATH = "/decisionFragment";
84     public static final String TRUSTED_SCORING_SIGNAL_PATH = "/trustedScoringSignalsFragment";
85     public static final String CUSTOM_AUDIENCE_SHIRT = "ca_shirt";
86     public static final String CUSTOM_AUDIENCE_SHOES = "ca_shoe";
87     // TODO(b/244530379) Make compatible with multiple buyers
88     public static final AdTechIdentifier BUYER_1 = AdTechIdentifier.fromString("localhost");
89     public static final List<AdTechIdentifier> CUSTOM_AUDIENCE_BUYERS =
90             Collections.singletonList(BUYER_1);
91     public static final AdSelectionSignals AD_SELECTION_SIGNALS =
92             AdSelectionSignals.fromString("{\"ad_selection_signals\":1}");
93     public static final AdSelectionSignals SELLER_SIGNALS =
94             AdSelectionSignals.fromString("{\"test_seller_signals\":1}");
95     public static final Map<AdTechIdentifier, AdSelectionSignals> PER_BUYER_SIGNALS =
96             Map.of(BUYER_1, AdSelectionSignals.fromString("{\"buyer_signals\":1}"));
97     protected static final Executor CALLBACK_EXECUTOR = Executors.newCachedThreadPool();
98     // Time allowed by current test setup for APIs to respond
99     // setting a large value for perf testing, to avoid failing for large datasets
100     protected static final int API_RESPONSE_TIMEOUT_SECONDS = 100;
101     protected static final String BUYER_BIDDING_LOGIC_URI_PATH = "/buyer/bidding/logic/";
102     protected static final String SELLER_REPORTING_PATH = "/reporting/seller";
103     protected static final String BUYER_REPORTING_PATH = "/reporting/buyer";
104     protected static final String DEFAULT_DECISION_LOGIC_JS =
105             "function scoreAd(ad, bid, auction_config, seller_signals,"
106                     + " trusted_scoring_signals, contextual_signal, user_signal,"
107                     + " custom_audience_signal) { \n"
108                     + "  return {'status': 0, 'score': bid };\n"
109                     + "}\n"
110                     + "function reportResult(ad_selection_config, render_uri, bid,"
111                     + " contextual_signals) { \n"
112                     + " return {'status': 0, 'results': {'signals_for_buyer':"
113                     + " '{\"signals_for_buyer\":1}', 'reporting_uri': '"
114                     + SELLER_REPORTING_PATH
115                     + "' } };\n"
116                     + "}";
117     protected static final String DEFAULT_BIDDING_LOGIC_JS =
118             "function generateBid(ad, auction_signals, per_buyer_signals,"
119                     + " trusted_bidding_signals, contextual_signals,"
120                     + " custom_audience_signals) { \n"
121                     + "  return {'status': 0, 'ad': ad, 'bid': ad.metadata.result };\n"
122                     + "}\n"
123                     + "function reportWin(ad_selection_signals, per_buyer_signals,"
124                     + " signals_for_buyer, contextual_signals, custom_audience_signals) { \n"
125                     + " return {'status': 0, 'results': {'reporting_uri': '"
126                     + BUYER_REPORTING_PATH
127                     + "' } };\n"
128                     + "}";
129     protected static final String CALCULATION_INTENSE_JS =
130             "for (let i = 1; i < 1000000000; i++) {\n" + "  Math.sqrt(i);\n" + "}";
131     protected static final String MEMORY_INTENSE_JS =
132             "var a = []\n" + "for (let i = 0; i < 10000; i++) {\n" + " a.push(i);" + "}";
133 
134     protected static final AdSelectionSignals TRUSTED_SCORING_SIGNALS =
135             AdSelectionSignals.fromString(
136                     "{\n"
137                             + "\t\"render_uri_1\": \"signals_for_1\",\n"
138                             + "\t\"render_uri_2\": \"signals_for_2\"\n"
139                             + "}");
140     protected static final AdSelectionSignals TRUSTED_BIDDING_SIGNALS =
141             AdSelectionSignals.fromString(
142                     "{\n"
143                             + "\t\"example\": \"example\",\n"
144                             + "\t\"valid\": \"Also valid\",\n"
145                             + "\t\"list\": \"list\",\n"
146                             + "\t\"of\": \"of\",\n"
147                             + "\t\"keys\": \"trusted bidding signal Values\"\n"
148                             + "}");
149     protected static final String AD_URI_PREFIX = "/adverts/123/";
150     protected static final int DELAY_TO_AVOID_THROTTLE_MS = 1001;
151     protected final Context mContext = ApplicationProvider.getApplicationContext();
152     protected final AdSelectionClient mAdSelectionClient =
153             new AdSelectionClient.Builder()
154                     .setContext(mContext)
155                     .setExecutor(CALLBACK_EXECUTOR)
156                     .build();
157     protected final AdvertisingCustomAudienceClient mCustomAudienceClient =
158             new AdvertisingCustomAudienceClient.Builder()
159                     .setContext(mContext)
160                     .setExecutor(CALLBACK_EXECUTOR)
161                     .build();
162     @Rule public MockWebServerRule mMockWebServerRule = MockWebServerRuleFactory.createForHttps();
163     protected Dispatcher mDefaultDispatcher;
164 
165     // Per-test method rules, run in the given order.
166     @Rule
167     public RuleChain rules =
168             RuleChain.outerRule(
169                             new KillAppsRule(
170                                     AdservicesTestHelper.getAdServicesPackageName(mContext)))
171                     .around(
172                             // CleanPackageRule should not execute after each test method because
173                             // there's a chance it interferes with ShowmapSnapshotListener snapshot
174                             // at the end of the test, impacting collection of memory metrics for
175                             // AdServices process.
176                             new CleanPackageRule(
177                                     AdservicesTestHelper.getAdServicesPackageName(mContext),
178                                     /* clearOnStarting = */ true,
179                                     /* clearOnFinished = */ false))
180                     .around(new SelectAdsFlagRule());
181 
182     @BeforeClass
setupBeforeClass()183     public static void setupBeforeClass() {
184         InstrumentationRegistry.getInstrumentation()
185                 .getUiAutomation()
186                 .adoptShellPermissionIdentity(Manifest.permission.WRITE_DEVICE_CONFIG);
187         // TODO(b/245585645) Mark true for the heap size enforcement after installing M105 library
188         DeviceConfig.setProperty(
189                 DeviceConfig.NAMESPACE_ADSERVICES,
190                 "fledge_js_isolate_enforce_max_heap_size",
191                 "false",
192                 true);
193     }
194 
195     @AfterClass
tearDownAfterClass()196     public static void tearDownAfterClass() {
197         if (!SdkLevel.isAtLeastT()) {
198             CompatAdServicesTestUtils.resetFlagsToDefault();
199         }
200     }
201 
getUri(String name, String path)202     public static Uri getUri(String name, String path) {
203         return Uri.parse("https://" + name + path);
204     }
205 
206     @Before
setup()207     public void setup() throws InterruptedException {
208         mDefaultDispatcher =
209                 new Dispatcher() {
210                     @Override
211                     public MockResponse dispatch(RecordedRequest request) {
212                         if (DECISION_LOGIC_PATH.equals(request.getPath())) {
213                             return new MockResponse().setBody(DEFAULT_DECISION_LOGIC_JS);
214                         } else if (BUYER_BIDDING_LOGIC_URI_PATH.equals(request.getPath())) {
215                             return new MockResponse().setBody(DEFAULT_BIDDING_LOGIC_JS);
216                         } else if (BUYER_REPORTING_PATH.equals(request.getPath())
217                                 || SELLER_REPORTING_PATH.equals(request.getPath())) {
218                             return new MockResponse().setBody("");
219                         } else if (request.getPath().startsWith(TRUSTED_SCORING_SIGNAL_PATH)) {
220                             return new MockResponse().setBody(TRUSTED_SCORING_SIGNALS.toString());
221                         } else if (request.getPath().startsWith(VALID_TRUSTED_BIDDING_URI_PATH)) {
222                             return new MockResponse().setBody(TRUSTED_BIDDING_SIGNALS.toString());
223                         }
224                         return new MockResponse().setResponseCode(404);
225                     }
226                 };
227     }
228 
createCustomAudience( final AdTechIdentifier buyer, String name, List<Double> bids, Instant activationTime, Instant expirationTime)229     protected CustomAudience createCustomAudience(
230             final AdTechIdentifier buyer,
231             String name,
232             List<Double> bids,
233             Instant activationTime,
234             Instant expirationTime) {
235         // Generate ads for with bids provided
236         List<AdData> ads = new ArrayList<>();
237 
238         // Create ads with the custom audience name and bid number as the ad URI
239         // Add the bid value to the metadata
240         for (int i = 0; i < bids.size(); i++) {
241             ads.add(
242                     new AdData.Builder()
243                             .setRenderUri(
244                                     getUri(
245                                             buyer.toString(),
246                                             AD_URI_PREFIX + name + "/ad" + (i + 1)))
247                             .setMetadata("{\"result\":" + bids.get(i) + "}")
248                             .build());
249         }
250 
251         return new CustomAudience.Builder()
252                 .setBuyer(buyer)
253                 .setName(name)
254                 .setActivationTime(activationTime)
255                 .setExpirationTime(expirationTime)
256                 .setDailyUpdateUri(getValidDailyUpdateUriByBuyer(buyer))
257                 .setUserBiddingSignals(VALID_USER_BIDDING_SIGNALS)
258                 .setTrustedBiddingData(getValidTrustedBiddingDataByBuyer(buyer))
259                 .setBiddingLogicUri(mMockWebServerRule.uriForPath(BUYER_BIDDING_LOGIC_URI_PATH))
260                 .setAds(ads)
261                 .build();
262     }
263 
createCustomAudience( final AdTechIdentifier buyer, String name, List<Double> bids)264     protected CustomAudience createCustomAudience(
265             final AdTechIdentifier buyer, String name, List<Double> bids) {
266         return createCustomAudience(
267                 buyer, name, bids, VALID_ACTIVATION_TIME, VALID_EXPIRATION_TIME);
268     }
269 
createAdSelectionConfig()270     protected AdSelectionConfig createAdSelectionConfig() {
271         return new AdSelectionConfig.Builder()
272                 .setSeller(SELLER)
273                 .setDecisionLogicUri(mMockWebServerRule.uriForPath(DECISION_LOGIC_PATH))
274                 .setCustomAudienceBuyers(CUSTOM_AUDIENCE_BUYERS)
275                 .setAdSelectionSignals(AD_SELECTION_SIGNALS)
276                 .setSellerSignals(SELLER_SIGNALS)
277                 .setPerBuyerSignals(PER_BUYER_SIGNALS)
278                 .setTrustedScoringSignalsUri(
279                         mMockWebServerRule.uriForPath(TRUSTED_SCORING_SIGNAL_PATH))
280                 // TODO(b/244530379) Make compatible with multiple buyers
281                 .setCustomAudienceBuyers(Collections.singletonList(BUYER_1))
282                 .build();
283     }
284 
createExpectedWinningUri( AdTechIdentifier buyer, String customAudienceName, int adNumber)285     protected Uri createExpectedWinningUri(
286             AdTechIdentifier buyer, String customAudienceName, int adNumber) {
287         return getUri(buyer.toString(), AD_URI_PREFIX + customAudienceName + "/ad" + adNumber);
288     }
289 
290     // TODO(b/244530379) Make compatible with multiple buyers
getValidDailyUpdateUriByBuyer(AdTechIdentifier buyer)291     protected Uri getValidDailyUpdateUriByBuyer(AdTechIdentifier buyer) {
292         return mMockWebServerRule.uriForPath("/update");
293     }
294 
getValidTrustedBiddingDataByBuyer(AdTechIdentifier buyer)295     protected TrustedBiddingData getValidTrustedBiddingDataByBuyer(AdTechIdentifier buyer) {
296         return new TrustedBiddingData.Builder()
297                 .setTrustedBiddingKeys(VALID_TRUSTED_BIDDING_KEYS)
298                 .setTrustedBiddingUri(getValidTrustedBiddingUriByBuyer(buyer))
299                 .build();
300     }
301 
302     // TODO(b/244530379) Make compatible with multiple buyers
getValidTrustedBiddingUriByBuyer(AdTechIdentifier buyer)303     protected Uri getValidTrustedBiddingUriByBuyer(AdTechIdentifier buyer) {
304         return mMockWebServerRule.uriForPath(VALID_TRUSTED_BIDDING_URI_PATH);
305     }
306 
addDelayToAvoidThrottle()307     protected void addDelayToAvoidThrottle() throws InterruptedException {
308         Thread.sleep(DELAY_TO_AVOID_THROTTLE_MS);
309     }
310 }
311