1 /*
2  * Copyright (C) 2023 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 com.android.adservices.service.customaudience;
18 
19 import static com.android.adservices.service.customaudience.CustomAudienceBlob.AUCTION_SERVER_REQUEST_FLAGS_KEY;
20 import static com.android.adservices.service.customaudience.CustomAudienceBlob.BUYER_KEY;
21 import static com.android.adservices.service.customaudience.CustomAudienceBlob.OWNER_KEY;
22 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.ADS_KEY;
23 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.AD_COUNTERS_KEY;
24 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.AD_FILTERS_KEY;
25 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.AD_RENDER_ID_KEY;
26 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.METADATA_KEY;
27 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.RENDER_URI_KEY;
28 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.TRUSTED_BIDDING_DATA_KEY;
29 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.TRUSTED_BIDDING_KEYS_KEY;
30 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.TRUSTED_BIDDING_URI_KEY;
31 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.USER_BIDDING_SIGNALS_KEY;
32 import static com.android.adservices.service.customaudience.FetchCustomAudienceReader.ACTIVATION_TIME_KEY;
33 import static com.android.adservices.service.customaudience.FetchCustomAudienceReader.BIDDING_LOGIC_URI_KEY;
34 import static com.android.adservices.service.customaudience.FetchCustomAudienceReader.DAILY_UPDATE_URI_KEY;
35 import static com.android.adservices.service.customaudience.FetchCustomAudienceReader.EXPIRATION_TIME_KEY;
36 import static com.android.adservices.service.customaudience.FetchCustomAudienceReader.NAME_KEY;
37 
38 import android.adservices.common.AdTechIdentifier;
39 import android.net.Uri;
40 
41 import com.android.adservices.LoggerFactory;
42 import com.android.adservices.common.JsonFixture;
43 import com.android.adservices.data.common.DBAdData;
44 import com.android.adservices.data.customaudience.DBTrustedBiddingData;
45 
46 import org.json.JSONArray;
47 import org.json.JSONException;
48 import org.json.JSONObject;
49 
50 import java.time.Instant;
51 import java.util.List;
52 
53 public class CustomAudienceBlobFixture {
54     private static final LoggerFactory.Logger sLogger = LoggerFactory.getFledgeLogger();
55 
56     /** Converts the input to a valid JSON object and returns it as a serialized string. */
asJSONObjectString( String owner, AdTechIdentifier buyer, String name, Instant activationTime, Instant expirationTime, Uri dailyUpdateUri, Uri biddingLogicUri, String userBiddingSignals, DBTrustedBiddingData trustedBiddingData, List<DBAdData> ads)57     public static String asJSONObjectString(
58             String owner,
59             AdTechIdentifier buyer,
60             String name,
61             Instant activationTime,
62             Instant expirationTime,
63             Uri dailyUpdateUri,
64             Uri biddingLogicUri,
65             String userBiddingSignals,
66             DBTrustedBiddingData trustedBiddingData,
67             List<DBAdData> ads)
68             throws JSONException {
69         return asJSONObject(
70                         owner,
71                         buyer,
72                         name,
73                         activationTime,
74                         expirationTime,
75                         dailyUpdateUri,
76                         biddingLogicUri,
77                         userBiddingSignals,
78                         trustedBiddingData,
79                         ads,
80                         false)
81                 .toString();
82     }
83 
84     /**
85      * Converts the inputs to a valid JSON object and returns it as a serialized string.
86      *
87      * <p>Optionally adds harmless junk to the response by adding unexpected fields.
88      */
asJSONObject( String owner, AdTechIdentifier buyer, String name, Instant activationTime, Instant expirationTime, Uri dailyUpdateUri, Uri biddingLogicUri, String userBiddingSignals, DBTrustedBiddingData trustedBiddingData, List<DBAdData> ads, boolean shouldAddHarmlessJunk)89     public static JSONObject asJSONObject(
90             String owner,
91             AdTechIdentifier buyer,
92             String name,
93             Instant activationTime,
94             Instant expirationTime,
95             Uri dailyUpdateUri,
96             Uri biddingLogicUri,
97             String userBiddingSignals,
98             DBTrustedBiddingData trustedBiddingData,
99             List<DBAdData> ads,
100             boolean shouldAddHarmlessJunk)
101             throws JSONException {
102         JSONObject json = new JSONObject();
103 
104         json = addOwner(json, owner, shouldAddHarmlessJunk);
105         json = addBuyer(json, buyer, shouldAddHarmlessJunk);
106         json = addName(json, name, shouldAddHarmlessJunk);
107         json = addActivationTime(json, activationTime, shouldAddHarmlessJunk);
108         json = addExpirationTime(json, expirationTime, shouldAddHarmlessJunk);
109         json = addDailyUpdateUri(json, dailyUpdateUri, shouldAddHarmlessJunk);
110         json = addBiddingLogicUri(json, biddingLogicUri, shouldAddHarmlessJunk);
111         json = addUserBiddingSignals(json, userBiddingSignals, shouldAddHarmlessJunk);
112         json = addTrustedBiddingData(json, trustedBiddingData, shouldAddHarmlessJunk);
113         json = addAds(json, ads, shouldAddHarmlessJunk);
114 
115         return json;
116     }
117 
118     /**
119      * Converts a string representation of a JSON object into a JSONObject with a keyed field for
120      * owner.
121      *
122      * <p>Optionally adds harmless junk to the object by adding unexpected fields.
123      */
addOwner(JSONObject json, String owner, boolean shouldAddHarmlessJunk)124     public static JSONObject addOwner(JSONObject json, String owner, boolean shouldAddHarmlessJunk)
125             throws JSONException {
126         if (owner != null) {
127             return addToJSONObject(json, OWNER_KEY, owner, shouldAddHarmlessJunk);
128         }
129         return json;
130     }
131 
132     /**
133      * Converts a string representation of a JSON object into a JSONObject with a keyed field for
134      * buyer.
135      *
136      * <p>Optionally adds harmless junk to the object by adding unexpected fields.
137      */
addBuyer( JSONObject json, AdTechIdentifier adTechIdentifier, boolean shouldAddHarmlessJunk)138     public static JSONObject addBuyer(
139             JSONObject json, AdTechIdentifier adTechIdentifier, boolean shouldAddHarmlessJunk)
140             throws JSONException {
141         if (adTechIdentifier != null) {
142             return addToJSONObject(
143                     json, BUYER_KEY, adTechIdentifier.toString(), shouldAddHarmlessJunk);
144         }
145         return json;
146     }
147 
148     /**
149      * Converts a string representation of a JSON object into a JSONObject with a keyed field for
150      * name.
151      *
152      * <p>Optionally adds harmless junk to the object by adding unexpected fields.
153      */
addName(JSONObject json, String name, boolean shouldAddHarmlessJunk)154     public static JSONObject addName(JSONObject json, String name, boolean shouldAddHarmlessJunk)
155             throws JSONException {
156         if (name != null) {
157             return addToJSONObject(json, NAME_KEY, name, shouldAddHarmlessJunk);
158         }
159         return json;
160     }
161 
162     /**
163      * Converts a string representation of a JSON object into a JSONObject with a keyed field for
164      * activation time.
165      *
166      * <p>Optionally adds harmless junk to the object by adding unexpected fields.
167      */
addActivationTime( JSONObject json, Instant activationTime, boolean shouldAddHarmlessJunk)168     public static JSONObject addActivationTime(
169             JSONObject json, Instant activationTime, boolean shouldAddHarmlessJunk)
170             throws JSONException {
171         if (activationTime != null) {
172             return addToJSONObject(
173                     json,
174                     ACTIVATION_TIME_KEY,
175                     activationTime.toEpochMilli(),
176                     shouldAddHarmlessJunk);
177         }
178         return json;
179     }
180 
181     /**
182      * Converts a string representation of a JSON object into a JSONObject with a keyed field for
183      * expiration time.
184      *
185      * <p>Optionally adds harmless junk to the object by adding unexpected fields.
186      */
addExpirationTime( JSONObject json, Instant expirationTime, boolean shouldAddHarmlessJunk)187     public static JSONObject addExpirationTime(
188             JSONObject json, Instant expirationTime, boolean shouldAddHarmlessJunk)
189             throws JSONException {
190         if (expirationTime != null) {
191             return addToJSONObject(
192                     json,
193                     EXPIRATION_TIME_KEY,
194                     expirationTime.toEpochMilli(),
195                     shouldAddHarmlessJunk);
196         }
197         return json;
198     }
199 
200     /**
201      * Converts a string representation of a JSON object into a JSONObject with a keyed field for
202      * daily update uri.
203      *
204      * <p>Optionally adds harmless junk to the object by adding unexpected fields.
205      */
addDailyUpdateUri( JSONObject json, Uri dailyUpdateUri, boolean shouldAddHarmlessJunk)206     public static JSONObject addDailyUpdateUri(
207             JSONObject json, Uri dailyUpdateUri, boolean shouldAddHarmlessJunk)
208             throws JSONException {
209         if (dailyUpdateUri != null) {
210             return addToJSONObject(
211                     json, DAILY_UPDATE_URI_KEY, dailyUpdateUri.toString(), shouldAddHarmlessJunk);
212         }
213         return json;
214     }
215 
216     /**
217      * Converts a string representation of a JSON object into a JSONObject with a keyed field for
218      * bidding logic uri.
219      *
220      * <p>Optionally adds harmless junk to the object by adding unexpected fields.
221      */
addBiddingLogicUri( JSONObject json, Uri biddingLogicUri, boolean shouldAddHarmlessJunk)222     public static JSONObject addBiddingLogicUri(
223             JSONObject json, Uri biddingLogicUri, boolean shouldAddHarmlessJunk)
224             throws JSONException {
225         if (biddingLogicUri != null) {
226             return addToJSONObject(
227                     json, BIDDING_LOGIC_URI_KEY, biddingLogicUri.toString(), shouldAddHarmlessJunk);
228         }
229         return json;
230     }
231 
232     /**
233      * Converts a string representation of a JSON object into a JSONObject with a keyed field for
234      * user bidding signals.
235      *
236      * <p>Optionally adds harmless junk to the object by adding unexpected fields.
237      */
addUserBiddingSignals( JSONObject json, String userBiddingSignals, boolean shouldAddHarmlessJunk)238     public static JSONObject addUserBiddingSignals(
239             JSONObject json, String userBiddingSignals, boolean shouldAddHarmlessJunk)
240             throws JSONException {
241         if (userBiddingSignals != null) {
242             JSONObject userBiddingSignalsJson = new JSONObject(userBiddingSignals);
243             return addToJSONObject(
244                     json, USER_BIDDING_SIGNALS_KEY, userBiddingSignalsJson, shouldAddHarmlessJunk);
245         }
246         return json;
247     }
248 
249     /**
250      * Converts {@link DBTrustedBiddingData} into a JSONObject with a keyed field for trusted
251      * bidding data.
252      *
253      * <p>Optionally adds harmless junk to the object by adding unexpected fields.
254      */
addTrustedBiddingData( JSONObject json, DBTrustedBiddingData trustedBiddingData, boolean shouldAddHarmlessJunk)255     public static JSONObject addTrustedBiddingData(
256             JSONObject json, DBTrustedBiddingData trustedBiddingData, boolean shouldAddHarmlessJunk)
257             throws JSONException {
258         if (trustedBiddingData != null) {
259             JSONObject trustedBiddingDataJson = new JSONObject();
260 
261             if (shouldAddHarmlessJunk) {
262                 JsonFixture.addHarmlessJunkValues(trustedBiddingDataJson);
263             }
264 
265             trustedBiddingDataJson.put(
266                     TRUSTED_BIDDING_URI_KEY, trustedBiddingData.getUri().toString());
267             JSONArray trustedBiddingKeysJson = new JSONArray(trustedBiddingData.getKeys());
268             if (shouldAddHarmlessJunk) {
269                 JsonFixture.addHarmlessJunkValues(trustedBiddingKeysJson);
270             }
271             trustedBiddingDataJson.put(TRUSTED_BIDDING_KEYS_KEY, trustedBiddingKeysJson);
272 
273             return addToJSONObject(json, TRUSTED_BIDDING_DATA_KEY, trustedBiddingDataJson, false);
274         }
275 
276         return json;
277     }
278 
279     /**
280      * Converts a list of {@link DBAdData} into a JSONObject with a keyed field for ads.
281      *
282      * <p>Optionally adds harmless junk to the object by adding unexpected fields.
283      */
addAds( JSONObject json, List<DBAdData> ads, boolean shouldAddHarmlessJunk)284     public static JSONObject addAds(
285             JSONObject json, List<DBAdData> ads, boolean shouldAddHarmlessJunk)
286             throws JSONException {
287         if (ads != null) {
288             JSONArray adsJson = new JSONArray();
289 
290             if (shouldAddHarmlessJunk) {
291                 JsonFixture.addHarmlessJunkValues(adsJson);
292             }
293 
294             for (DBAdData ad : ads) {
295                 JSONObject adJson = new JSONObject();
296                 if (shouldAddHarmlessJunk) {
297                     JsonFixture.addHarmlessJunkValues(adJson);
298                 }
299 
300                 adJson.put(RENDER_URI_KEY, ad.getRenderUri().toString());
301                 try {
302                     adJson.put(METADATA_KEY, new JSONObject(ad.getMetadata()));
303                 } catch (JSONException exception) {
304                     sLogger.v(
305                             "Trying to add invalid JSON to test object (%s); inserting as String"
306                                     + " instead",
307                             exception.getMessage());
308                     adJson.put(METADATA_KEY, ad.getMetadata());
309                 }
310                 if (!ad.getAdCounterKeys().isEmpty()) {
311                     adJson.put(AD_COUNTERS_KEY, new JSONArray(ad.getAdCounterKeys()));
312                 }
313                 if (ad.getAdFilters() != null) {
314                     adJson.put(AD_FILTERS_KEY, ad.getAdFilters().toJson());
315                 }
316                 if (ad.getAdRenderId() != null) {
317                     adJson.put(AD_RENDER_ID_KEY, ad.getAdRenderId());
318                 }
319                 adsJson.put(adJson);
320             }
321 
322             return addToJSONObject(json, ADS_KEY, adsJson, false);
323         }
324 
325         return json;
326     }
327 
328     /**
329      * Converts a list of {@link String} into a JSONObject with a keyed field for auction server
330      * request flags.
331      *
332      * <p>Optionally adds harmless junk to the object by adding unexpected fields.
333      */
addAuctionServerRequestFlags( JSONObject json, List<String> auctionServerRequestFlags, boolean shouldAddHarmlessJunk)334     public static JSONObject addAuctionServerRequestFlags(
335             JSONObject json, List<String> auctionServerRequestFlags, boolean shouldAddHarmlessJunk)
336             throws JSONException {
337         if (auctionServerRequestFlags != null) {
338             JSONArray auctionServerRequestFlagsArray = new JSONArray();
339             for (String s : auctionServerRequestFlags) {
340                 auctionServerRequestFlagsArray.put(s);
341             }
342             if (shouldAddHarmlessJunk) {
343                 JsonFixture.addHarmlessJunkValues(auctionServerRequestFlagsArray);
344             }
345             return addToJSONObject(
346                     json, AUCTION_SERVER_REQUEST_FLAGS_KEY, auctionServerRequestFlagsArray, false);
347         }
348         return json;
349     }
350 
addToJSONObject( JSONObject json, String key, Object value, boolean shouldAddHarmlessJunk)351     private static JSONObject addToJSONObject(
352             JSONObject json, String key, Object value, boolean shouldAddHarmlessJunk)
353             throws JSONException {
354         if (json == null) {
355             json = new JSONObject();
356         }
357 
358         if (shouldAddHarmlessJunk) {
359             JsonFixture.addHarmlessJunkValues(json);
360         }
361 
362         json.put(key, value);
363         return json;
364     }
365 }
366