• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.utils;
18 
19 import android.adservices.clients.customaudience.AdvertisingCustomAudienceClient;
20 import android.adservices.common.AdData;
21 import android.adservices.common.AdTechIdentifier;
22 import android.adservices.common.CommonFixture;
23 import android.adservices.customaudience.CustomAudience;
24 import android.adservices.customaudience.CustomAudienceFixture;
25 import android.adservices.customaudience.TrustedBiddingDataFixture;
26 import android.content.Context;
27 import android.util.Log;
28 
29 import java.time.Instant;
30 import java.util.ArrayList;
31 import java.util.List;
32 import java.util.concurrent.ExecutionException;
33 import java.util.concurrent.ExecutorService;
34 import java.util.concurrent.Executors;
35 import java.util.concurrent.TimeUnit;
36 import java.util.concurrent.TimeoutException;
37 
38 public class CustomAudienceTestFixture {
39     private static final String TAG = CustomAudienceTestFixture.class.getPackageName();
40     // Timeout for joining or leaving a custom audience.
41     private static final int API_RESPONSE_TIMEOUT_SECONDS = 5;
42     public static final String AD_URI_PREFIX = "/adverts/123/";
43     public static final String BUYER_BIDDING_LOGIC_URI_PATH = "/buyer/bidding/logic/";
44 
45     private final ArrayList<CustomAudience> mCustomAudiencesToCleanUp = new ArrayList<>();
46     private AdvertisingCustomAudienceClient mCustomAudienceClient;
47 
CustomAudienceTestFixture(Context context)48     public CustomAudienceTestFixture(Context context) {
49         ExecutorService executor = Executors.newCachedThreadPool();
50         mCustomAudienceClient =
51                 new AdvertisingCustomAudienceClient.Builder()
52                         .setContext(context)
53                         .setExecutor(executor)
54                         .build();
55     }
56 
CustomAudienceTestFixture(AdvertisingCustomAudienceClient customAudienceClient)57     public CustomAudienceTestFixture(AdvertisingCustomAudienceClient customAudienceClient) {
58         mCustomAudienceClient = customAudienceClient;
59     }
60 
61     /** Return the custom audience client being used. */
getClient()62     public AdvertisingCustomAudienceClient getClient() {
63         return mCustomAudienceClient;
64     }
65 
66     /**
67      * @param buyer The name of the buyer for this Custom Audience
68      * @param bids these bids, are added to its metadata. Our JS logic then picks this value and
69      *     creates ad with the provided value as bid
70      * @return a real Custom Audience object that can be persisted and used in bidding and scoring
71      */
createCustomAudience(final AdTechIdentifier buyer, List<Double> bids)72     public CustomAudience createCustomAudience(final AdTechIdentifier buyer, List<Double> bids) {
73         return createCustomAudience(
74                 buyer,
75                 bids,
76                 CustomAudienceFixture.VALID_ACTIVATION_TIME,
77                 CustomAudienceFixture.VALID_EXPIRATION_TIME);
78     }
79 
80     /**
81      * @param buyer The name of the buyer for this Custom Audience
82      * @param bids these bids, are added to its metadata. Our JS logic then picks this value and
83      *     creates ad with the provided value as bid
84      * @return a real Custom Audience object that can be persisted and used in bidding and scoring
85      */
createCustomAudienceWithAdCost( final AdTechIdentifier buyer, List<Double> bids, double adCost)86     public CustomAudience createCustomAudienceWithAdCost(
87             final AdTechIdentifier buyer, List<Double> bids, double adCost) {
88         return createCustomAudienceWithAdCost(
89                 buyer,
90                 bids,
91                 CustomAudienceFixture.VALID_ACTIVATION_TIME,
92                 CustomAudienceFixture.VALID_EXPIRATION_TIME,
93                 adCost);
94     }
95 
96     /** Create a custom audience. */
createCustomAudience( final AdTechIdentifier buyer, List<Double> bids, Instant activationTime, Instant expirationTime)97     public CustomAudience createCustomAudience(
98             final AdTechIdentifier buyer,
99             List<Double> bids,
100             Instant activationTime,
101             Instant expirationTime) {
102         return createCustomAudience(
103                 buyer + CustomAudienceFixture.VALID_NAME,
104                 buyer,
105                 bids,
106                 activationTime,
107                 expirationTime);
108     }
109 
110     /** Create a custom audience. */
createCustomAudience( String name, final AdTechIdentifier buyer, List<Double> bids, Instant activationTime, Instant expirationTime)111     public CustomAudience createCustomAudience(
112             String name,
113             final AdTechIdentifier buyer,
114             List<Double> bids,
115             Instant activationTime,
116             Instant expirationTime) {
117         // Generate ads for with bids provided
118         List<AdData> ads = new ArrayList<>();
119 
120         // Create ads with the buyer name and bid number as the ad URI
121         // Add the bid value to the metadata
122         for (int i = 0; i < bids.size(); i++) {
123             ads.add(
124                     new AdData.Builder()
125                             .setRenderUri(
126                                     CommonFixture.getUri(buyer, AD_URI_PREFIX + "/ad" + (i + 1)))
127                             .setMetadata("{\"result\":" + bids.get(i) + "}")
128                             .build());
129         }
130 
131         return new CustomAudience.Builder()
132                 .setBuyer(buyer)
133                 .setName(name)
134                 .setActivationTime(activationTime)
135                 .setExpirationTime(expirationTime)
136                 .setDailyUpdateUri(CustomAudienceFixture.getValidDailyUpdateUriByBuyer(buyer))
137                 .setUserBiddingSignals(CustomAudienceFixture.VALID_USER_BIDDING_SIGNALS)
138                 .setTrustedBiddingData(
139                         TrustedBiddingDataFixture.getValidTrustedBiddingDataByBuyer(buyer))
140                 .setBiddingLogicUri(CommonFixture.getUri(buyer, BUYER_BIDDING_LOGIC_URI_PATH))
141                 .setAds(ads)
142                 .build();
143     }
144 
145     /** Create a custom audience with a given ad cost. */
createCustomAudienceWithAdCost( final AdTechIdentifier buyer, List<Double> bids, Instant activationTime, Instant expirationTime, double adCost)146     public CustomAudience createCustomAudienceWithAdCost(
147             final AdTechIdentifier buyer,
148             List<Double> bids,
149             Instant activationTime,
150             Instant expirationTime,
151             double adCost) {
152         // Generate ads for with bids provided
153         List<AdData> ads = new ArrayList<>();
154 
155         // Create ads with the buyer name and bid number as the ad URI
156         // Add the bid value to the metadata
157         for (int i = 0; i < bids.size(); i++) {
158             ads.add(
159                     new AdData.Builder()
160                             .setRenderUri(
161                                     CommonFixture.getUri(buyer, AD_URI_PREFIX + "/ad" + (i + 1)))
162                             .setMetadata(
163                                     "{\"result\":" + bids.get(i) + ",\"adCost\":" + adCost + "}")
164                             .build());
165         }
166 
167         return new CustomAudience.Builder()
168                 .setBuyer(buyer)
169                 .setName(buyer + CustomAudienceFixture.VALID_NAME)
170                 .setActivationTime(activationTime)
171                 .setExpirationTime(expirationTime)
172                 .setDailyUpdateUri(CustomAudienceFixture.getValidDailyUpdateUriByBuyer(buyer))
173                 .setUserBiddingSignals(CustomAudienceFixture.VALID_USER_BIDDING_SIGNALS)
174                 .setTrustedBiddingData(
175                         TrustedBiddingDataFixture.getValidTrustedBiddingDataByBuyer(buyer))
176                 .setBiddingLogicUri(CommonFixture.getUri(buyer, BUYER_BIDDING_LOGIC_URI_PATH))
177                 .setAds(ads)
178                 .build();
179     }
180 
181     /** Create a custom audience with a list of ads with a generated ad render id. */
createCustomAudienceWithAdRenderId( String name, final AdTechIdentifier buyer, List<Double> bids, Instant activationTime, Instant expirationTime)182     public CustomAudience createCustomAudienceWithAdRenderId(
183             String name,
184             final AdTechIdentifier buyer,
185             List<Double> bids,
186             Instant activationTime,
187             Instant expirationTime) {
188         // Generate ads for with bids provided
189         List<AdData> ads = new ArrayList<>();
190 
191         // Create ads with the buyer name and bid number as the ad URI
192         // Add the bid value to the metadata
193         for (int i = 0; i < bids.size(); i++) {
194             ads.add(
195                     new AdData.Builder()
196                             .setRenderUri(
197                                     CommonFixture.getUri(buyer, AD_URI_PREFIX + "/ad" + (i + 1)))
198                             .setMetadata("{\"result\":" + bids.get(i) + "}")
199                             .setAdRenderId(String.format("%s", i))
200                             .build());
201         }
202 
203         return new CustomAudience.Builder()
204                 .setBuyer(buyer)
205                 .setName(name)
206                 .setActivationTime(activationTime)
207                 .setExpirationTime(expirationTime)
208                 .setDailyUpdateUri(CustomAudienceFixture.getValidDailyUpdateUriByBuyer(buyer))
209                 .setUserBiddingSignals(CustomAudienceFixture.VALID_USER_BIDDING_SIGNALS)
210                 .setTrustedBiddingData(
211                         TrustedBiddingDataFixture.getValidTrustedBiddingDataByBuyer(buyer))
212                 .setBiddingLogicUri(CommonFixture.getUri(buyer, BUYER_BIDDING_LOGIC_URI_PATH))
213                 .setAds(ads)
214                 .build();
215     }
216 
217     /** Create a custom audience with given domains. */
createCustomAudienceWithSubdomains( final AdTechIdentifier buyer, List<Double> bids)218     public CustomAudience createCustomAudienceWithSubdomains(
219             final AdTechIdentifier buyer, List<Double> bids) {
220         // Generate ads for with bids provided
221         List<AdData> ads = new ArrayList<>();
222 
223         // Create ads with the buyer name and bid number as the ad URI
224         // Add the bid value to the metadata
225         for (int i = 0; i < bids.size(); i++) {
226             ads.add(
227                     new AdData.Builder()
228                             .setRenderUri(
229                                     CommonFixture.getUriWithValidSubdomain(
230                                             buyer.toString(), AD_URI_PREFIX + "/ad" + (i + 1)))
231                             .setMetadata("{\"result\":" + bids.get(i) + "}")
232                             .build());
233         }
234 
235         return CustomAudienceFixture.getValidBuilderWithSubdomainsForBuyer(buyer)
236                 .setAds(ads)
237                 .build();
238     }
239 
240     /** Join a custom audience. */
joinCustomAudience(CustomAudience customAudience)241     public void joinCustomAudience(CustomAudience customAudience)
242             throws ExecutionException, InterruptedException, TimeoutException {
243         mCustomAudiencesToCleanUp.add(customAudience);
244         Log.i(
245                 TAG,
246                 "Joining custom audience "
247                         + customAudience.getName()
248                         + " for buyer "
249                         + customAudience.getBuyer());
250         mCustomAudienceClient
251                 .joinCustomAudience(customAudience)
252                 .get(API_RESPONSE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
253     }
254 
255     /** Leave a custom audience. */
leaveCustomAudience(CustomAudience customAudience)256     public void leaveCustomAudience(CustomAudience customAudience)
257             throws ExecutionException, InterruptedException, TimeoutException {
258         mCustomAudienceClient
259                 .leaveCustomAudience(customAudience.getBuyer(), customAudience.getName())
260                 .get(API_RESPONSE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
261         Log.d(TAG, "Left Custom Audience: " + customAudience.getName());
262     }
263 
264     /** Leave a custom audience. */
leaveJoinedCustomAudiences()265     public void leaveJoinedCustomAudiences()
266             throws ExecutionException, InterruptedException, TimeoutException {
267         try {
268             for (CustomAudience customAudience : mCustomAudiencesToCleanUp) {
269                 Log.i(
270                         TAG,
271                         "Cleanup: leaving custom audience "
272                                 + customAudience.getName()
273                                 + " for buyer"
274                                 + customAudience.getBuyer());
275                 mCustomAudienceClient
276                         .leaveCustomAudience(customAudience.getBuyer(), customAudience.getName())
277                         .get(API_RESPONSE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
278             }
279         } finally {
280             mCustomAudiencesToCleanUp.clear();
281         }
282     }
283 }
284