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 com.android.adservices.service.customaudience; 18 19 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.ADS_KEY; 20 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.AD_COUNTERS_KEY; 21 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.AD_FILTERS_KEY; 22 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.AD_RENDER_ID_KEY; 23 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.AUCTION_SERVER_REQUEST_FLAGS_KEY; 24 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.METADATA_KEY; 25 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.RENDER_URI_KEY; 26 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.TRUSTED_BIDDING_DATA_KEY; 27 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.TRUSTED_BIDDING_KEYS_KEY; 28 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.TRUSTED_BIDDING_URI_KEY; 29 import static com.android.adservices.service.customaudience.CustomAudienceUpdatableDataReader.USER_BIDDING_SIGNALS_KEY; 30 31 import android.adservices.common.AdSelectionSignals; 32 import android.adservices.common.CommonFixture; 33 import android.adservices.customaudience.CustomAudienceFixture; 34 35 import com.android.adservices.LoggerFactory; 36 import com.android.adservices.common.DBAdDataFixture; 37 import com.android.adservices.common.JsonFixture; 38 import com.android.adservices.customaudience.DBTrustedBiddingDataFixture; 39 import com.android.adservices.data.common.DBAdData; 40 import com.android.adservices.data.customaudience.DBTrustedBiddingData; 41 42 import org.json.JSONArray; 43 import org.json.JSONException; 44 import org.json.JSONObject; 45 46 import java.util.List; 47 48 public class CustomAudienceUpdatableDataFixture { 49 private static final LoggerFactory.Logger sLogger = LoggerFactory.getFledgeLogger(); 50 getEmptyJsonResponseString()51 public static String getEmptyJsonResponseString() throws JSONException { 52 return toJsonResponseString(null, null, null); 53 } 54 getFullSuccessfulJsonResponseString()55 public static String getFullSuccessfulJsonResponseString() throws JSONException { 56 return toJsonResponseString( 57 CustomAudienceFixture.VALID_USER_BIDDING_SIGNALS.toString(), 58 DBTrustedBiddingDataFixture.getValidBuilderByBuyer(CommonFixture.VALID_BUYER_1) 59 .build(), 60 DBAdDataFixture.getValidDbAdDataListByBuyer(CommonFixture.VALID_BUYER_1)); 61 } 62 63 /** 64 * Converts the input user bidding signals, trusted bidding data, and list of ads to a valid 65 * JSON object, adds harmless junk fields, and returns it as a serialized string. 66 */ toJsonResponseStringWithHarmlessJunk( String userBiddingSignals, DBTrustedBiddingData trustedBiddingData, List<DBAdData> ads)67 public static String toJsonResponseStringWithHarmlessJunk( 68 String userBiddingSignals, DBTrustedBiddingData trustedBiddingData, List<DBAdData> ads) 69 throws JSONException { 70 return toJsonResponseString(userBiddingSignals, trustedBiddingData, ads, true); 71 } 72 73 /** 74 * Gets a valid JSON object with keys for user bidding signals, trusted bidding data, and a list 75 * of ads, malforms the expected schema, and returns it as a serialized string. 76 */ getMalformedJsonResponseString()77 public static String getMalformedJsonResponseString() throws JSONException { 78 return getMalformedJsonObject().toString(); 79 } 80 81 /** 82 * Gets a valid JSON object with keys for user bidding signals, trusted bidding data, and a list 83 * of ads, malforms the expected schema, and returns it. 84 */ getMalformedJsonObject()85 public static JSONObject getMalformedJsonObject() throws JSONException { 86 JSONObject jsonResponse = new JSONObject(); 87 88 jsonResponse.put( 89 USER_BIDDING_SIGNALS_KEY, 90 "user bidding signals but as a string and not a JSON object"); 91 jsonResponse.put(TRUSTED_BIDDING_DATA_KEY, 0); 92 jsonResponse.put(ADS_KEY, "mismatched schema"); 93 94 return jsonResponse; 95 } 96 97 /** 98 * Gets a valid JSON object with keys for user bidding signals, trusted bidding data, and a list 99 * of ads, malforms the expected schema at a deeper level, and returns it. 100 */ getDeeperMalformedJsonObject()101 public static JSONObject getDeeperMalformedJsonObject() throws JSONException { 102 JSONObject jsonResponse = new JSONObject(); 103 104 jsonResponse.put(USER_BIDDING_SIGNALS_KEY, 0); 105 106 JSONObject trustedBiddingDataObject = new JSONObject(); 107 trustedBiddingDataObject.put(TRUSTED_BIDDING_URI_KEY, 0); 108 trustedBiddingDataObject.put(TRUSTED_BIDDING_KEYS_KEY, 0); 109 jsonResponse.put(TRUSTED_BIDDING_DATA_KEY, trustedBiddingDataObject); 110 111 JSONArray adsArray = new JSONArray(); 112 JSONObject adObject0 = new JSONObject(); 113 adObject0.put(RENDER_URI_KEY, 0); 114 adObject0.put(METADATA_KEY, 0); 115 adsArray.put(adObject0); 116 JSONObject adObject1 = new JSONObject(); 117 adObject1.put(RENDER_URI_KEY, 1); 118 adObject1.put(METADATA_KEY, 1); 119 adsArray.put(adObject1); 120 jsonResponse.put(ADS_KEY, adsArray); 121 122 return jsonResponse; 123 } 124 125 /** 126 * Gets a valid JSON object with keys for user bidding signals, trusted bidding data, and a list 127 * of ads, malforms the expected schema to null, and returns it. 128 */ getMalformedNullJsonObject()129 public static JSONObject getMalformedNullJsonObject() throws JSONException { 130 JSONObject jsonResponse = new JSONObject(); 131 132 jsonResponse.put(USER_BIDDING_SIGNALS_KEY, JSONObject.NULL); 133 jsonResponse.put(TRUSTED_BIDDING_DATA_KEY, JSONObject.NULL); 134 jsonResponse.put(ADS_KEY, JSONObject.NULL); 135 136 return jsonResponse; 137 } 138 139 /** 140 * Converts the input user bidding signals, trusted bidding data, and list of ads to a valid 141 * JSON object and returns it as a serialized string. 142 */ toJsonResponseString( String userBiddingSignals, DBTrustedBiddingData trustedBiddingData, List<DBAdData> ads)143 public static String toJsonResponseString( 144 String userBiddingSignals, DBTrustedBiddingData trustedBiddingData, List<DBAdData> ads) 145 throws JSONException { 146 return toJsonResponseString(userBiddingSignals, trustedBiddingData, ads, false); 147 } 148 149 /** 150 * Converts the input user bidding signals, trusted bidding data, and list of ads to a valid 151 * JSON object and returns it as a serialized string. 152 * 153 * <p>Optionally adds harmless junk to the response by adding unexpected fields. 154 */ toJsonResponseString( String userBiddingSignals, DBTrustedBiddingData trustedBiddingData, List<DBAdData> ads, boolean shouldAddHarmlessJunk)155 private static String toJsonResponseString( 156 String userBiddingSignals, 157 DBTrustedBiddingData trustedBiddingData, 158 List<DBAdData> ads, 159 boolean shouldAddHarmlessJunk) 160 throws JSONException { 161 JSONObject jsonResponse = new JSONObject(); 162 163 jsonResponse = addToJsonObject(jsonResponse, userBiddingSignals, shouldAddHarmlessJunk); 164 jsonResponse = addToJsonObject(jsonResponse, trustedBiddingData, shouldAddHarmlessJunk); 165 jsonResponse = addToJsonObject(jsonResponse, ads, shouldAddHarmlessJunk); 166 167 return jsonResponse.toString(); 168 } 169 /** 170 * Converts the input user bidding signals, trusted bidding data, list of ads, and 171 * auctionServerRequestFlags to a valid JSON object and returns it as a serialized string. 172 */ toJsonResponseString( String userBiddingSignals, DBTrustedBiddingData trustedBiddingData, List<DBAdData> ads, List<String> auctionServerFlags)173 public static String toJsonResponseString( 174 String userBiddingSignals, 175 DBTrustedBiddingData trustedBiddingData, 176 List<DBAdData> ads, 177 List<String> auctionServerFlags) 178 throws JSONException { 179 return toJsonResponseString( 180 userBiddingSignals, trustedBiddingData, ads, auctionServerFlags, false); 181 } 182 183 /** 184 * Converts the input user bidding signals, trusted bidding data, list of ads, and 185 * auctionServerRequestFlags to a valid JSON object and returns it as a serialized string. 186 * 187 * <p>Optionally adds harmless junk to the response by adding unexpected fields. 188 */ toJsonResponseString( String userBiddingSignals, DBTrustedBiddingData trustedBiddingData, List<DBAdData> ads, List<String> auctionServerFlags, boolean shouldAddHarmlessJunk)189 public static String toJsonResponseString( 190 String userBiddingSignals, 191 DBTrustedBiddingData trustedBiddingData, 192 List<DBAdData> ads, 193 List<String> auctionServerFlags, 194 boolean shouldAddHarmlessJunk) 195 throws JSONException { 196 JSONObject jsonResponse = new JSONObject(); 197 198 jsonResponse = addToJsonObject(jsonResponse, userBiddingSignals, shouldAddHarmlessJunk); 199 jsonResponse = addToJsonObject(jsonResponse, trustedBiddingData, shouldAddHarmlessJunk); 200 jsonResponse = addToJsonObject(jsonResponse, ads, shouldAddHarmlessJunk); 201 jsonResponse = 202 addAuctionServerRequestFlagsToJsonObject( 203 jsonResponse, auctionServerFlags, shouldAddHarmlessJunk); 204 205 return jsonResponse.toString(); 206 } 207 208 /** 209 * Converts a string representation of a JSON object into a JSONObject with a keyed field for 210 * user bidding signals. 211 * 212 * <p>Optionally adds harmless junk to the object by adding unexpected fields. 213 */ addToJsonObject( JSONObject jsonResponse, String userBiddingSignals, boolean shouldAddHarmlessJunk)214 public static JSONObject addToJsonObject( 215 JSONObject jsonResponse, String userBiddingSignals, boolean shouldAddHarmlessJunk) 216 throws JSONException { 217 if (jsonResponse == null) { 218 jsonResponse = new JSONObject(); 219 } 220 221 if (shouldAddHarmlessJunk) { 222 JsonFixture.addHarmlessJunkValues(jsonResponse); 223 } 224 225 if (userBiddingSignals != null) { 226 JSONObject userBiddingSignalsJson = new JSONObject(userBiddingSignals); 227 jsonResponse.put(USER_BIDDING_SIGNALS_KEY, userBiddingSignalsJson); 228 } 229 230 return jsonResponse; 231 } 232 233 /** 234 * Converts {@link DBTrustedBiddingData} into a JSONObject with a keyed field for trusted 235 * bidding data. 236 * 237 * <p>Optionally adds harmless junk to the object by adding unexpected fields. 238 */ addToJsonObject( JSONObject jsonResponse, DBTrustedBiddingData trustedBiddingData, boolean shouldAddHarmlessJunk)239 public static JSONObject addToJsonObject( 240 JSONObject jsonResponse, 241 DBTrustedBiddingData trustedBiddingData, 242 boolean shouldAddHarmlessJunk) 243 throws JSONException { 244 if (jsonResponse == null) { 245 jsonResponse = new JSONObject(); 246 } 247 248 if (trustedBiddingData != null) { 249 JSONObject trustedBiddingDataJson = new JSONObject(); 250 if (shouldAddHarmlessJunk) { 251 JsonFixture.addHarmlessJunkValues(trustedBiddingDataJson); 252 } 253 254 trustedBiddingDataJson.put( 255 TRUSTED_BIDDING_URI_KEY, trustedBiddingData.getUri().toString()); 256 JSONArray trustedBiddingKeysJson = new JSONArray(trustedBiddingData.getKeys()); 257 if (shouldAddHarmlessJunk) { 258 JsonFixture.addHarmlessJunkValues(trustedBiddingKeysJson); 259 } 260 trustedBiddingDataJson.put(TRUSTED_BIDDING_KEYS_KEY, trustedBiddingKeysJson); 261 262 jsonResponse.put(TRUSTED_BIDDING_DATA_KEY, trustedBiddingDataJson); 263 } 264 265 return jsonResponse; 266 } 267 268 /** 269 * Converts a list of {@link DBAdData} into a JSONObject with a keyed field for ads. 270 * 271 * <p>Optionally adds harmless junk to the object by adding unexpected fields. 272 */ addToJsonObject( JSONObject jsonResponse, List<DBAdData> ads, boolean shouldAddHarmlessJunk)273 public static JSONObject addToJsonObject( 274 JSONObject jsonResponse, List<DBAdData> ads, boolean shouldAddHarmlessJunk) 275 throws JSONException { 276 if (jsonResponse == null) { 277 jsonResponse = new JSONObject(); 278 } 279 280 if (ads != null) { 281 JSONArray adsJson = new JSONArray(); 282 if (shouldAddHarmlessJunk) { 283 JsonFixture.addHarmlessJunkValues(adsJson); 284 } 285 286 for (DBAdData ad : ads) { 287 JSONObject adJson = new JSONObject(); 288 if (shouldAddHarmlessJunk) { 289 JsonFixture.addHarmlessJunkValues(adJson); 290 } 291 292 adJson.put(RENDER_URI_KEY, ad.getRenderUri().toString()); 293 try { 294 adJson.put(METADATA_KEY, new JSONObject(ad.getMetadata())); 295 } catch (JSONException exception) { 296 sLogger.v( 297 "Trying to add invalid JSON to test object (%s); inserting as String" 298 + " instead", 299 exception.getMessage()); 300 adJson.put(METADATA_KEY, ad.getMetadata()); 301 } 302 if (!ad.getAdCounterKeys().isEmpty()) { 303 adJson.put(AD_COUNTERS_KEY, new JSONArray(ad.getAdCounterKeys())); 304 } 305 if (ad.getAdFilters() != null) { 306 adJson.put(AD_FILTERS_KEY, ad.getAdFilters().toJson()); 307 } 308 if (ad.getAdRenderId() != null) { 309 adJson.put(AD_RENDER_ID_KEY, ad.getAdRenderId()); 310 } 311 adsJson.put(adJson); 312 } 313 314 jsonResponse.put(ADS_KEY, adsJson); 315 } 316 317 return jsonResponse; 318 } 319 320 /** 321 * Converts a list of {@link String} containing auction server request flags into a JSONObject 322 * keyed on {@link CustomAudienceUpdatableDataReader#AUCTION_SERVER_REQUEST_FLAGS_KEY}. 323 * 324 * <p>Optionally adds harmless junk to the object by adding unexpected fields. 325 */ addAuctionServerRequestFlagsToJsonObject( JSONObject jsonResponse, List<String> auctionServerRequestFlags, boolean shouldAddHarmlessJunk)326 public static JSONObject addAuctionServerRequestFlagsToJsonObject( 327 JSONObject jsonResponse, 328 List<String> auctionServerRequestFlags, 329 boolean shouldAddHarmlessJunk) 330 throws JSONException { 331 if (jsonResponse == null) { 332 jsonResponse = new JSONObject(); 333 } 334 JSONArray array = new JSONArray(auctionServerRequestFlags); 335 if (shouldAddHarmlessJunk) { 336 JsonFixture.addHarmlessJunkValues(array); 337 } 338 jsonResponse.put(AUCTION_SERVER_REQUEST_FLAGS_KEY, array); 339 return jsonResponse; 340 } 341 getValidBuilderFullSuccessfulResponse()342 public static CustomAudienceUpdatableData.Builder getValidBuilderFullSuccessfulResponse() 343 throws JSONException { 344 return CustomAudienceUpdatableData.builder() 345 .setUserBiddingSignals( 346 AdSelectionSignals.fromString( 347 JsonFixture.formatAsOrgJsonJSONObjectString( 348 CustomAudienceFixture.VALID_USER_BIDDING_SIGNALS 349 .toString()))) 350 .setTrustedBiddingData( 351 DBTrustedBiddingDataFixture.getValidBuilderByBuyer( 352 CommonFixture.VALID_BUYER_1) 353 .build()) 354 .setAds(DBAdDataFixture.getValidDbAdDataListByBuyer(CommonFixture.VALID_BUYER_1)) 355 .setAttemptedUpdateTime(CommonFixture.FIXED_NOW) 356 .setInitialUpdateResult(BackgroundFetchRunner.UpdateResultType.SUCCESS) 357 .setContainsSuccessfulUpdate(true); 358 } 359 getValidBuilderEmptySuccessfulResponse()360 public static CustomAudienceUpdatableData.Builder getValidBuilderEmptySuccessfulResponse() { 361 return CustomAudienceUpdatableData.builder() 362 .setUserBiddingSignals(null) 363 .setTrustedBiddingData(null) 364 .setAds(null) 365 .setAttemptedUpdateTime(CommonFixture.FIXED_NOW) 366 .setInitialUpdateResult(BackgroundFetchRunner.UpdateResultType.SUCCESS) 367 .setContainsSuccessfulUpdate(true); 368 } 369 getValidBuilderEmptyFailedResponse()370 public static CustomAudienceUpdatableData.Builder getValidBuilderEmptyFailedResponse() { 371 return CustomAudienceUpdatableData.builder() 372 .setUserBiddingSignals(null) 373 .setTrustedBiddingData(null) 374 .setAds(null) 375 .setAttemptedUpdateTime(CommonFixture.FIXED_NOW) 376 .setInitialUpdateResult(BackgroundFetchRunner.UpdateResultType.SUCCESS) 377 .setContainsSuccessfulUpdate(false); 378 } 379 } 380