Skip to content

Commit

Permalink
Update TargetingInfo Behavior (#1088)
Browse files Browse the repository at this point in the history
* Add Targeting option

* Remove FF usage

* PR Comments + Tests

* PR Comments

* Update tests

* Remove cacheId value

* Reset values for test

* Fix test for checking correct testcase

* In case of winning bid, targeting should have local-cache-id

* Refactor teardown

* PR Update

* Add Native format case

* Check cacheid with adObject

---------

Co-authored-by: Ankit Rajendra Thanekar <[email protected]>
  • Loading branch information
ankit-thanekar007 and Ankit Rajendra Thanekar authored Jan 28, 2025
1 parent 02f47c0 commit 9e6e610
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 2 deletions.
21 changes: 19 additions & 2 deletions PrebidMobile/AdUnits/AdUnit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,28 @@ public class AdUnit: NSObject, DispatcherDelegate {
})
}

private func setUp(_ adObject: AnyObject?, with bidResponse: BidResponse) -> ResultCode {
func setUp(_ adObject: AnyObject?, with bidResponse: BidResponse) -> ResultCode {

if Targeting.shared.forceSdkToChooseWinner {
Log.error("Breaking change: set Targeting.forceSdkToChooseWinner = false and test your behavior. In the upcoming major release, the SDK will send all targeting keywords to the AdSever, so you should prepare your setup.")
}

guard let winningBid = bidResponse.winningBid else {

//When the new behavior is active
if !Targeting.shared.forceSdkToChooseWinner {

if let adObject {
Utils.shared.validateAndAttachKeywords(adObject: adObject, bidResponse: bidResponse)
}
//If there are no winning bids, but there are bids the SDK will send back prebidDemandFetchSuccess
if let bids = bidResponse.allBids, !bids.isEmpty {
return .prebidDemandFetchSuccess
}
}
return .prebidDemandNoBids
}

if let cacheId = cacheBidIfNeeded(winningBid) {
bidResponse.addTargetingInfoValue(key: PrebidLocalCacheIdKey, value: cacheId)
}
Expand Down
3 changes: 3 additions & 0 deletions PrebidMobile/ConfigurationAndTargeting/Targeting.swift
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ public class Targeting: NSObject {
UserConsentDataManager.shared.isAllowedAccessDeviceData()
}

/// This value forces SDK to choose targeting info of the winning bid
public var forceSdkToChooseWinner : Bool = true

// MARK: - External User Ids

/// Array of external user IDs.
Expand Down
147 changes: 147 additions & 0 deletions PrebidMobileTests/AdUnitTests/AdUnitTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ class AdUnitTests: XCTestCase {

override func tearDown() {
Targeting.shared.clearUserKeywords()
Targeting.shared.forceSdkToChooseWinner = true

Prebid.shared.useExternalClickthroughBrowser = false
Prebid.shared.useCacheForReportingWithRenderingAPI = false
}

func testFetchDemand() {
Expand Down Expand Up @@ -114,6 +117,150 @@ class AdUnitTests: XCTestCase {
XCTAssertEqual(realBidInfo?.nativeAdCacheId, expectedCacheId)
}

//forceSdkToChooseWinner + Winner = Contains Targeting Info
func testForcedWinnerAndWinningBid() {
//given
Targeting.shared.forceSdkToChooseWinner = true

let expected = ResultCode.prebidDemandFetchSuccess

let adUnit = AdUnit(configId: "138c4d03-0efb-4498-9dc6-cb5a9acb2ea4", size: CGSize(width: 300, height: 250), adFormats: [.banner])
//This needs to after AdUnit init as the AdUnit enables this value.
//We need to disabled to not look for cache id for winning bid
Prebid.shared.useCacheForReportingWithRenderingAPI = false
let adObject = NSMutableDictionary()
let rawWinningBid = PBMBidResponseTransformer.makeValidResponse(bidPrice: 0.75)
let jsonDict = rawWinningBid.jsonDict as? NSDictionary
let bidResponse = BidResponse(jsonDictionary: jsonDict ?? [:])

//when
let resultCode = adUnit.setUp(adObject, with: bidResponse)

//then
XCTAssertTrue((adObject.allKeys as? [String])?.contains("hb_bidder") ?? false)
XCTAssertEqual(resultCode, expected)
}

//forceSdkToChooseWinner + No Winner = Doesn't contain Targeting Info
func testForcedWinnerAndLoosingBid() {
//given
Targeting.shared.forceSdkToChooseWinner = true
let expected = ResultCode.prebidDemandNoBids
let adUnit = AdUnit(configId: "138c4d03-0efb-4498-9dc6-cb5a9acb2ea4", size: CGSize(width: 300, height: 250), adFormats: [.banner])
//This needs to after AdUnit init as the AdUnit enables this value.
//We need to disabled to not look for cache id for winning bid
Prebid.shared.useCacheForReportingWithRenderingAPI = false
let adObject = NSMutableDictionary()
let rawWinningBid = PBMBidResponseTransformer.makeValidResponseWithNonWinningTargetingInfo()
let jsonDict = rawWinningBid.jsonDict as? NSDictionary
let bidResponse = BidResponse(jsonDictionary: jsonDict ?? [:])

//when
let resultCode = adUnit.setUp(adObject, with: bidResponse)

//then
XCTAssertFalse((adObject.allKeys as? [String])?.contains("hb_bidder") ?? false)
XCTAssertEqual(resultCode, expected)
}

//Don't forceSdkToChooseWinner + Winner = Contains Targeting Info
func testNonForcedWinnerAndWinningBid() {
//given
Targeting.shared.forceSdkToChooseWinner = false
let expected = ResultCode.prebidDemandFetchSuccess
let adUnit = AdUnit(configId: "138c4d03-0efb-4498-9dc6-cb5a9acb2ea4", size: CGSize(width: 300, height: 250), adFormats: [.banner])
//This needs to after AdUnit init as the AdUnit enables this value.
//We need to disabled to not look for cache id for winning bid
Prebid.shared.useCacheForReportingWithRenderingAPI = false
let adObject = NSMutableDictionary()
let rawWinningBid = PBMBidResponseTransformer.makeValidResponse(bidPrice: 0.75)
let jsonDict = rawWinningBid.jsonDict as? NSDictionary
let bidResponse = BidResponse(jsonDictionary: jsonDict ?? [:])

//when
let resultCode = adUnit.setUp(adObject, with: bidResponse)

//then
XCTAssertTrue((adObject.allKeys as? [String])?.contains("hb_bidder") ?? false)
XCTAssertEqual(resultCode, expected)
}

//Don't forceSdkToChooseWinner + No Winner = Contains Targeting Info
func testNonForcedWinnerAndNonWinningBid() {
//given
Targeting.shared.forceSdkToChooseWinner = false

let expected = ResultCode.prebidDemandFetchSuccess
let adUnit = AdUnit(configId: "138c4d03-0efb-4498-9dc6-cb5a9acb2ea4", size: CGSize(width: 300, height: 250), adFormats: [.banner])
//This needs to after AdUnit init as the AdUnit enables this value.
//We need to disabled to not look for cache id for winning bid
Prebid.shared.useCacheForReportingWithRenderingAPI = false
let adObject = NSMutableDictionary()
let rawWinningBid = PBMBidResponseTransformer.makeValidResponseWithNonWinningTargetingInfo()
let jsonDict = rawWinningBid.jsonDict as? NSDictionary
let bidResponse = BidResponse(jsonDictionary: jsonDict ?? [:])

//when
let resultCode = adUnit.setUp(adObject, with: bidResponse)

//then
XCTAssertTrue((adObject.allKeys as? [String])?.contains("hb_bidder") ?? false)
XCTAssertEqual(adObject["hb_bidder"] as? String, "Test-Bidder-1")
XCTAssertEqual(resultCode, expected)
}

//forceSdkToChooseWinner + Native Format Winner = Contains Targeting Info
func testForcedWinnerAndWinningBidNativeFormat() {
//given
Targeting.shared.forceSdkToChooseWinner = true

let expected = ResultCode.prebidDemandFetchSuccess

let adUnit = AdUnit(configId: "138c4d03-0efb-4498-9dc6-cb5a9acb2ea4", size: CGSize(width: 300, height: 250), adFormats: [.native])
//This needs to after AdUnit init as the AdUnit enables this value.
//We need to disabled to not look for cache id for winning bid
Prebid.shared.useCacheForReportingWithRenderingAPI = false
let adObject = NSMutableDictionary()
let rawWinningBid = PBMBidResponseTransformer.makeNativeValidResponse(bidPrice: 0.75)
let jsonDict = rawWinningBid.jsonDict as? NSDictionary
let bidResponse = BidResponse(jsonDictionary: jsonDict ?? [:])

//when
let resultCode = adUnit.setUp(adObject, with: bidResponse)

//then
XCTAssertNotNil(bidResponse.targetingInfo?[PrebidLocalCacheIdKey])
XCTAssertTrue((adObject.allKeys as? [String])?.contains(PrebidLocalCacheIdKey) ?? false)
XCTAssertTrue((adObject.allKeys as? [String])?.contains("hb_bidder") ?? false)
XCTAssertEqual(resultCode, expected)
}

//Don't forceSdkToChooseWinner + Native Format Winner = Contains Targeting Info
func testNonForcedWinnerAndWinningBidNativeFormat() {
//given
Targeting.shared.forceSdkToChooseWinner = false

let expected = ResultCode.prebidDemandFetchSuccess

let adUnit = AdUnit(configId: "138c4d03-0efb-4498-9dc6-cb5a9acb2ea4", size: CGSize(width: 300, height: 250), adFormats: [.native])
//This needs to after AdUnit init as the AdUnit enables this value.
//We need to disabled to not look for cache id for winning bid
Prebid.shared.useCacheForReportingWithRenderingAPI = false
let adObject = NSMutableDictionary()
let rawWinningBid = PBMBidResponseTransformer.makeNativeValidResponse(bidPrice: 0.75)
let jsonDict = rawWinningBid.jsonDict as? NSDictionary
let bidResponse = BidResponse(jsonDictionary: jsonDict ?? [:])

//when
let resultCode = adUnit.setUp(adObject, with: bidResponse)

//then
XCTAssertNotNil(bidResponse.targetingInfo?[PrebidLocalCacheIdKey])
XCTAssertTrue((adObject.allKeys as? [String])?.contains(PrebidLocalCacheIdKey) ?? false)
XCTAssertTrue((adObject.allKeys as? [String])?.contains("hb_bidder") ?? false)
XCTAssertEqual(resultCode, expected)
}

func testBidInfoCompletion() {
Prebid.shared.prebidServerAccountId = "test-account-id"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ extension PBMBidResponseTransformer {
return buildResponse("{\"id\":\"B4A2D3F4-41B6-4D37-B68B-EE8893E85C31\",\"seatbid\":[\(winningBidFragment)],\"cur\":\"USD\",\"ext\":{\"responsetimemillis\":{\"openx\":62}}}")
}

static func makeNativeValidResponse(bidPrice: Float, noWinningBidProperties: Bool = false) -> PrebidServerResponse {
let winningBidFragment = noWinningBidProperties ? "" : "{\"bid\":[{\"id\":\"test-bid-id-1\",\"impid\":\"8BBB0D42-5A73-45AC-B275-51B299A74C32\",\"price\":\(bidPrice),\"adm\":\"<html><div>You Won! This is a test bid</div></html>\",\"adid\":\"test-ad-id-12345\",\"adomain\":[\"openx.com\"],\"crid\":\"test-creative-id-1\",\"w\":300,\"h\":250,\"ext\":{\"prebid\":{\"targeting\":{\"hb_bidder\":\"openx\",\"hb_bidder_openx\":\"openx\",\"hb_env\":\"mobile-app\",\"hb_env_openx\":\"mobile-app\",\"hb_pb\":\"0.10\",\"hb_pb_openx\":\"0.10\",\"hb_size\":\"300x250\",\"hb_size_openx\":\"300x250\"},\"type\":\"native\"},\"bidder\":{\"ad_ox_cats\":[2],\"agency_id\":\"agency_10\",\"brand_id\":\"brand_10\",\"buyer_id\":\"buyer_10\",\"matching_ad_id\":{\"campaign_id\":1,\"creative_id\":3,\"placement_id\":2},\"next_highest_bid_price\":0.099}}}],\"seat\":\"openx\"}"
return buildResponse("{\"id\":\"B4A2D3F4-41B6-4D37-B68B-EE8893E85C31\",\"seatbid\":[\(winningBidFragment)],\"cur\":\"USD\",\"ext\":{\"responsetimemillis\":{\"openx\":62}}}")
}

static func makeValidResponseWithNonWinningTargetingInfo() -> PrebidServerResponse {
let winningBidFragment = "{\n \"bid\": [\n {\n \"id\": \"test_id_bid\",\n \"impid\": \"test_imp\",\n \"price\": 0,\n \"ext\": {\n \"origbidcpm\": 0,\n \"prebid\": {\n \"meta\": {},\n \"targeting\": {\n \"hb_bidder\": \"Test-Bidder-1\",\n \"hb_source\": \"s2s\",\n }\n }\n }\n }\n ],\n \"seat\": \"Test-Bidder-1\"\n}"
return buildResponse("{\"id\":\"B4A2D3F4-41B6-4D37-B68B-EE8893E85C31\",\"seatbid\":[\(winningBidFragment)],\"cur\":\"USD\",\"ext\":{\"responsetimemillis\":{\"openx\":62}}}")
}

static func makeValidResponseWithCTF(bidPrice: Float, ctfBanner: Double, ctfPreRender: Double) -> PrebidServerResponse {
let winningBidFragment = "{\"bid\":[{\"id\":\"test-bid-id-1\",\"impid\":\"8BBB0D42-5A73-45AC-B275-51B299A74C32\",\"price\":\(bidPrice),\"adm\":\"<html><div>You Won! This is a test bid</div></html>\",\"adid\":\"test-ad-id-12345\",\"adomain\":[\"openx.com\"],\"crid\":\"test-creative-id-1\",\"w\":300,\"h\":250,\"ext\":{\"prebid\":{\"targeting\":{\"hb_bidder\":\"openx\",\"hb_bidder_openx\":\"openx\",\"hb_env\":\"mobile-app\",\"hb_env_openx\":\"mobile-app\",\"hb_pb\":\"0.10\",\"hb_pb_openx\":\"0.10\",\"hb_size\":\"300x250\",\"hb_size_openx\":\"300x250\"},\"type\":\"banner\"},\"bidder\":{\"ad_ox_cats\":[2],\"agency_id\":\"agency_10\",\"brand_id\":\"brand_10\",\"buyer_id\":\"buyer_10\",\"matching_ad_id\":{\"campaign_id\":1,\"creative_id\":3,\"placement_id\":2},\"next_highest_bid_price\":0.099}}}],\"seat\":\"openx\"}"
return buildResponse("{\"id\":\"B4A2D3F4-41B6-4D37-B68B-EE8893E85C31\",\"seatbid\":[\(winningBidFragment)],\"cur\":\"USD\",\"ext\":{\"responsetimemillis\":{\"openx\":62},\"prebid\":{\"passthrough\":[{\"type\":\"prebidmobilesdk\", \"sdkconfiguration\":{\"cftbanner\":\(ctfBanner),\"cftprerender\":\(ctfPreRender)}}]}}}")
Expand Down
12 changes: 12 additions & 0 deletions PrebidMobileTests/TargetingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class TargetingTests: XCTestCase {

override func tearDown() {
UtilitiesForTesting.resetTargeting(.shared)
Targeting.shared.forceSdkToChooseWinner = true
}

func testDomain() {
Expand Down Expand Up @@ -122,6 +123,17 @@ class TargetingTests: XCTestCase {
XCTAssertEqual(locationPrecision, Targeting.shared.locationPrecision)
}

func testforceSdkToChooseWinner() {
//given
let forceSdkToChooseWinner = false

//when
Targeting.shared.forceSdkToChooseWinner = forceSdkToChooseWinner

//then
XCTAssertEqual(forceSdkToChooseWinner, Targeting.shared.forceSdkToChooseWinner)
}

// MARK: - Year Of Birth
func testYearOfBirth() {
//given
Expand Down

0 comments on commit 9e6e610

Please sign in to comment.