• 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.adservices.adselection.AdSelectionOutcome;
20 import android.adservices.adselection.ReportImpressionRequest;
21 import android.adservices.common.AdData;
22 import android.adservices.common.AdSelectionSignals;
23 import android.adservices.common.AdTechIdentifier;
24 import android.adservices.customaudience.CustomAudience;
25 import android.adservices.customaudience.TrustedBiddingData;
26 import android.net.Uri;
27 import android.platform.test.scenario.annotation.Scenario;
28 
29 import org.junit.Assert;
30 import org.junit.Test;
31 import org.junit.runner.RunWith;
32 import org.junit.runners.JUnit4;
33 
34 import java.time.Duration;
35 import java.time.Instant;
36 import java.util.ArrayList;
37 import java.util.Collections;
38 import java.util.List;
39 import java.util.concurrent.TimeUnit;
40 
41 @Scenario
42 @RunWith(JUnit4.class)
43 public class LimitPerfTests extends AbstractPerfTest {
44 
45     private static final String URL_PREFIX = "https://";
46     private static final String BUYER = "localhost";
47 
48     @Test
test_joinBigCustomAudience()49     public void test_joinBigCustomAudience() throws Exception {
50         joinAndLeaveNBigCas(1);
51     }
52 
53     @Test
test_join100BigCustomAudiences()54     public void test_join100BigCustomAudiences() throws Exception {
55         // Will take 3+ minutes to run
56         joinAndLeaveNBigCas(100);
57     }
58 
59     @Test
test_auctionBigCa()60     public void test_auctionBigCa() throws Exception {
61         auctionNBigCas(1);
62     }
63 
64     @Test
test_auction10BigCas()65     public void test_auction10BigCas() throws Exception {
66         auctionNBigCas(10);
67     }
68 
69     @Test
test_auction100BigCas()70     public void test_auction100BigCas() throws Exception {
71         // Will take 3+ minutes to run
72         auctionNBigCas(100);
73     }
74 
75     @Test
test_100Auctions100BigCas()76     public void test_100Auctions100BigCas() throws Exception {
77         // Will take 5+ minutes to run
78         nAuctionsMBigCas(100, 100);
79     }
80 
81 
auctionNBigCas(int n)82     private void auctionNBigCas(int n) throws Exception {
83         nAuctionsMBigCas(1, n);
84     }
85 
nAuctionsMBigCas(int n, int m)86     private void nAuctionsMBigCas(int n, int m) throws Exception {
87         List<CustomAudience> caList = createNBigCas(m);
88         mMockWebServerRule.startMockWebServer(mDefaultDispatcher);
89         joinAll(caList);
90 
91         for (int i = 0; i < n; i++) {
92             AdSelectionOutcome outcome =
93                     mAdSelectionClient
94                             .selectAds(createAdSelectionConfig())
95                             .get(API_RESPONSE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
96 
97             // Check that a valid URL won
98             Assert.assertEquals(BUYER, outcome.getRenderUri().getHost());
99 
100             ReportImpressionRequest reportImpressionRequest =
101                     new ReportImpressionRequest(
102                             outcome.getAdSelectionId(), createAdSelectionConfig());
103             // Performing reporting, and asserting that no exception is thrown
104             mAdSelectionClient
105                     .reportImpression(reportImpressionRequest)
106                     .get(API_RESPONSE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
107         }
108 
109         leaveAll(caList);
110     }
111 
joinAndLeaveNBigCas(int n)112     private void joinAndLeaveNBigCas(int n) throws Exception {
113         List<CustomAudience> caList = createNBigCas(n);
114         joinAll(caList);
115         leaveAll(caList);
116     }
117 
joinAll(List<CustomAudience> caList)118     private void joinAll(List<CustomAudience> caList) throws Exception {
119         for (CustomAudience ca : caList) {
120             mCustomAudienceClient
121                     .joinCustomAudience(ca)
122                     .get(API_RESPONSE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
123         }
124     }
125 
leaveAll(List<CustomAudience> caList)126     private void leaveAll(List<CustomAudience> caList) throws Exception {
127         for (CustomAudience ca : caList) {
128             mCustomAudienceClient
129                     .leaveCustomAudience(ca.getBuyer(), ca.getName())
130                     .get(API_RESPONSE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
131         }
132     }
133 
createNBigCas(int n)134     private List<CustomAudience> createNBigCas(int n) {
135         List<CustomAudience> caList = new ArrayList<>();
136         for (int i = 0; i < n; i++) {
137             caList.add(createBigCustomAudience("" + i, i + 1));
138         }
139         return caList;
140     }
141     /**
142      * Creates as large of a CA as possible with a name prefixed by nameStart
143      *
144      * @param nameStart The start of the CA name, the name will be padded out the maximum length
145      * @param bid How much all the ads in the CA should bid
146      * @return The large CA.
147      */
createBigCustomAudience(String nameStart, int bid)148     private CustomAudience createBigCustomAudience(String nameStart, int bid) {
149         int minUrlSize = URL_PREFIX.length() + BUYER.length();
150         Uri trustedBiddingUri =
151                 getValidTrustedBiddingUriByBuyer(AdTechIdentifier.fromString(BUYER));
152         return new CustomAudience.Builder()
153                 // CA names are limited to 200 bytes
154                 .setName(nameStart + repeatCompatImpl("a", 200 - nameStart.length()))
155                 .setActivationTime(Instant.now())
156                 .setExpirationTime(Instant.now().plus(Duration.ofDays(1)))
157                 // Daily update and bidding URLS are limited to 400 bytes
158                 .setDailyUpdateUri(nBitUriFromAdtech(BUYER, 400))
159                 .setBiddingLogicUri(
160                         nBitUriFromUri(
161                                 mMockWebServerRule.uriForPath(BUYER_BIDDING_LOGIC_URI_PATH), 400))
162                 // User bidding signals are limited to 10,000 bytes
163                 .setUserBiddingSignals(nBitAdSelectionSignals(10000))
164                 /* TrustedBidding signals are limited to 10 KiB. We're adding as many keys objects
165                  * as possible to increase object overhead.
166                  */
167                 .setTrustedBiddingData(
168                         new TrustedBiddingData.Builder()
169                                 .setTrustedBiddingUri(trustedBiddingUri)
170                                 .setTrustedBiddingKeys(
171                                         Collections.nCopies(
172                                                 10000 - trustedBiddingUri.toString().length(), "a"))
173                                 .build())
174                 .setBuyer(AdTechIdentifier.fromString(BUYER))
175                 // Maximum size is 10,000 bytes for each ad and 100 ads. Making 100 ads of size 100.
176                 .setAds(
177                         Collections.nCopies(
178                                 100,
179                                 new AdData.Builder()
180                                         .setRenderUri(nBitUriFromAdtech(BUYER, minUrlSize))
181                                         .setMetadata(
182                                                 nBitJsonWithFields(
183                                                         100 - minUrlSize, "\"result\": " + bid))
184                                         .build()))
185                 .build();
186     }
187 
nBitAdSelectionSignals(int n)188     private AdSelectionSignals nBitAdSelectionSignals(int n) {
189         return AdSelectionSignals.fromString(nBitJson(n));
190     }
191 
nBitJson(int n)192     private String nBitJson(int n) {
193         if (n < 8) {
194             throw new IllegalArgumentException("n too small");
195         }
196         return "{\"a\":\"" + repeatCompatImpl("a", n - 8) + "\"}";
197     }
198 
nBitJsonWithFields(int n, String fields)199     private String nBitJsonWithFields(int n, String fields) {
200         if (n < 8) {
201             throw new IllegalArgumentException("n too small");
202         }
203 
204         return "{"
205                 + fields
206                 + ",\"a\":\""
207                 + repeatCompatImpl("a", n - (9 + fields.length()))
208                 + "\"}";
209     }
210 
nBitUriFromAdtech(String adtech, int n)211     private Uri nBitUriFromAdtech(String adtech, int n) {
212         String uriStart = URL_PREFIX + adtech;
213         if (n < uriStart.length()) {
214             throw new IllegalArgumentException("n too small ");
215         } else if (n == uriStart.length()) {
216             return Uri.parse(uriStart);
217         } else {
218             return Uri.parse(uriStart + "#" + repeatCompatImpl("a", n - 3 - uriStart.length()));
219         }
220     }
221 
nBitUriFromUri(Uri uri, int n)222     private Uri nBitUriFromUri(Uri uri, int n) {
223         if (n < uri.toString().length()) {
224             throw new IllegalArgumentException("n too small ");
225         } else if (n == uri.toString().length()) {
226             return uri;
227         } else {
228             return Uri.parse(uri + "#" + repeatCompatImpl("a", n - 3 - uri.toString().length()));
229         }
230     }
231 
232     /**
233      * Since we run the test on both Android S and T, this util method provides a
234      * backward-compatible way to concatenate a string N times without using Java 11 repeat String
235      * method.
236      */
repeatCompatImpl(String str, int numTimes)237     private static String repeatCompatImpl(String str, int numTimes) {
238         StringBuilder sb = new StringBuilder();
239 
240         for (int num = 0; num < numTimes; num++) {
241             sb.append(str);
242         }
243 
244         return sb.toString();
245     }
246 }
247