Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PG bidder request, bid response, user details specs #1590

Merged
merged 3 commits into from
Feb 7, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package org.prebid.server.functional.pg


import org.prebid.server.functional.model.deals.lineitem.LineItemSize
import org.prebid.server.functional.model.mock.services.generalplanner.PlansResponse
import org.prebid.server.functional.model.request.auction.BidRequest
import org.prebid.server.functional.model.request.auction.Format
import org.prebid.server.functional.model.request.dealsupdate.ForceDealsUpdateRequest
import org.prebid.server.functional.model.response.auction.BidResponse
import org.prebid.server.functional.util.PBSUtils
import spock.lang.Unroll

import static org.prebid.server.functional.model.response.auction.ErrorType.GENERIC

class PgBidResponseSpec extends BasePgSpec {

def cleanup() {
pgPbsService.sendForceDealsUpdateRequest(ForceDealsUpdateRequest.invalidateLineItemsRequest)
}

def "PBS should allow valid bidder response with deals info continue taking part in auction"() {
given: "Bid request"
def bidRequest = BidRequest.defaultBidRequest

and: "Planner Mock line items"
def plansResponse = PlansResponse.getDefaultPlansResponse(bidRequest.site.publisher.id)
generalPlanner.initPlansResponse(plansResponse)
def lineItemCount = plansResponse.lineItems.size()

and: "Line items are fetched by PBS"
pgPbsService.sendForceDealsUpdateRequest(ForceDealsUpdateRequest.updateLineItemsRequest)

and: "Set bid response"
def bidResponse = BidResponse.getDefaultPgBidResponse(bidRequest, plansResponse)
bidder.setResponse(bidRequest.id, bidResponse)

when: "Sending auction request to PBS"
def auctionResponse = pgPbsService.sendAuctionRequest(bidRequest)

then: "Bidder returned valid response with deals info during auction"
assert auctionResponse.ext?.debug?.pgmetrics?.sentToClient?.size() == lineItemCount
assert auctionResponse.ext?.debug?.pgmetrics?.sentToClientAsTopMatch?.size() == lineItemCount
}

@Unroll
def "PBS should invalidate bidder response when '#field' doesn't match with the bid request"() {
given: "Bid request"
def bidRequest = BidRequest.defaultBidRequest

and: "Planner Mock line items"
def plansResponse = PlansResponse.getDefaultPlansResponse(bidRequest.site.publisher.id)
generalPlanner.initPlansResponse(plansResponse)

and: "Line items are fetched by PBS"
pgPbsService.sendForceDealsUpdateRequest(ForceDealsUpdateRequest.updateLineItemsRequest)

and: "Set bid response"
def bidResponse = bidResponseGeneric(bidRequest, plansResponse)
bidder.setResponse(bidRequest.id, bidResponse)

when: "Sending auction request to PBS"
def auctionResponse = pgPbsService.sendAuctionRequest(bidRequest)

then: "Bidder response is invalid"
def bidderError = auctionResponse.ext?.errors?.get(GENERIC)
assert bidderError?.size() == 1
assert bidderError[0].message.startsWith(errorMessage(bidResponse))

where:
field |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it should be 2 separate tests

bidResponseGeneric |
errorMessage

"bid id" |
{ BidRequest bidReq, PlansResponse plansResp ->
BidResponse.getDefaultPgBidResponse(bidReq, plansResp).tap {
seatbid[0].bid[0].impid = PBSUtils.randomNumber as String
}
} |
{ BidResponse bidResp -> "Bid \"${bidResp.seatbid[0].bid[0].id}\" has no corresponding imp in request" }

"deal id" |
{ BidRequest bidReq, PlansResponse plansResp ->
BidResponse.getDefaultPgBidResponse(bidReq, plansResp).tap {
seatbid[0].bid[0].dealid = PBSUtils.randomNumber as String
}
} |
{ BidResponse bidResp ->
"WARNING: Bid \"${bidResp.seatbid[0].bid[0].id}\" has 'dealid' not present in corresponding imp in request."
}
}

def "PBS should invalidate bidder response when non-matched to the bid request size is returned"() {
given: "Bid request with set sizes"
def bidRequest = BidRequest.defaultBidRequest.tap {
imp[0].banner.format = [Format.defaultFormat]
}
def impFormat = bidRequest.imp[0].banner.format[0]

and: "Planner Mock line items"
def plansResponse = PlansResponse.getDefaultPlansResponse(bidRequest.site.publisher.id)
generalPlanner.initPlansResponse(plansResponse)

and: "Line items are fetched by PBS"
pgPbsService.sendForceDealsUpdateRequest(ForceDealsUpdateRequest.updateLineItemsRequest)

and: "Set bid response with unmatched to the bid request size"
def bidResponse = BidResponse.getDefaultPgBidResponse(bidRequest, plansResponse).tap {
seatbid[0].bid[0].w = PBSUtils.randomNumber
}
def bid = bidResponse.seatbid[0].bid[0]
bidder.setResponse(bidRequest.id, bidResponse)

when: "Sending auction request to PBS"
def auctionResponse = pgPbsService.sendAuctionRequest(bidRequest)

then: "Bidder response is invalid"
assert auctionResponse.ext?.debug?.pgmetrics?.responseInvalidated?.size() == plansResponse.lineItems.size()

and: "PBS invalidated response as unmatched by size"
def bidderError = auctionResponse.ext?.errors?.get(GENERIC)
assert bidderError?.size() == 1
assert bidderError[0].message == "Bid \"$bid.id\" has 'w' and 'h' not supported by " +
"corresponding imp in request. Bid dimensions: '${bid.w}x$bid.h', formats in imp: '${impFormat.w}x$impFormat.h'"
}

def "PBS should invalidate bidder response when non-matched to the PBS line item size response is returned"() {
given: "Bid request"
def newFormat = new Format(w: PBSUtils.randomNumber, h: PBSUtils.randomNumber)
def bidRequest = BidRequest.defaultBidRequest.tap {
imp[0].banner.format = [Format.defaultFormat, newFormat]
}

and: "Planner Mock line items with a default size"
def plansResponse = PlansResponse.getDefaultPlansResponse(bidRequest.site.publisher.id).tap {
lineItems[0].sizes = [LineItemSize.defaultLineItemSize]
}
def lineItemSize = plansResponse.lineItems[0].sizes[0]
generalPlanner.initPlansResponse(plansResponse)

and: "Line items are fetched by PBS"
pgPbsService.sendForceDealsUpdateRequest(ForceDealsUpdateRequest.updateLineItemsRequest)

and: "Set bid response with non-matched to the line item size"
def bidResponse = BidResponse.getDefaultPgBidResponse(bidRequest, plansResponse).tap {
seatbid[0].bid[0].w = newFormat.w
seatbid[0].bid[0].h = newFormat.h
}
def bid = bidResponse.seatbid[0].bid[0]
bidder.setResponse(bidRequest.id, bidResponse)

when: "Sending auction request to PBS"
def auctionResponse = pgPbsService.sendAuctionRequest(bidRequest)

then: "Bidder response is invalid"
assert auctionResponse.ext?.debug?.pgmetrics?.responseInvalidated?.size() == plansResponse.lineItems.size()

and: "PBS invalidated response as not matched by size"
def bidderError = auctionResponse.ext?.errors?.get(GENERIC)
assert bidderError?.size() == 1
assert bidderError[0].message == "Bid \"$bid.id\" has 'w' and 'h' not matched to Line Item. " +
"Bid dimensions: '${bid.w}x$bid.h', Line Item sizes: '${lineItemSize.w}x$lineItemSize.h'"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package org.prebid.server.functional.pg

import org.prebid.server.functional.model.UidsCookie
import org.prebid.server.functional.model.bidder.Generic
import org.prebid.server.functional.model.deals.lineitem.LineItem
import org.prebid.server.functional.model.deals.userdata.UserDetailsResponse
import org.prebid.server.functional.model.mock.services.generalplanner.PlansResponse
import org.prebid.server.functional.model.request.auction.BidRequest
import org.prebid.server.functional.model.request.auction.Bidder
import org.prebid.server.functional.model.request.auction.Device
import org.prebid.server.functional.model.request.auction.Imp
import org.prebid.server.functional.model.request.dealsupdate.ForceDealsUpdateRequest
import org.prebid.server.functional.model.response.auction.BidResponse
import org.prebid.server.functional.util.HttpUtil
import org.prebid.server.functional.util.PBSUtils
import spock.lang.Ignore

class PgBidderRequestSpec extends BasePgSpec {

def cleanup() {
pgPbsService.sendForceDealsUpdateRequest(ForceDealsUpdateRequest.invalidateLineItemsRequest)
}

def "PBS should be able to add given device info to the bidder request"() {
given: "Bid request"
def bidRequest = BidRequest.defaultBidRequest.tap {
device = new Device(ua: PBSUtils.randomString,
make: PBSUtils.randomString,
model: PBSUtils.randomString)
}

and: "Planner Mock line items"
def plansResponse = PlansResponse.getDefaultPlansResponse(bidRequest.site.publisher.id)
generalPlanner.initPlansResponse(plansResponse)

and: "Bid response"
def bidResponse = BidResponse.getDefaultPgBidResponse(bidRequest, plansResponse)
bidder.setResponse(bidRequest.id, bidResponse)

and: "Line items are fetched by PBS"
pgPbsService.sendForceDealsUpdateRequest(ForceDealsUpdateRequest.updateLineItemsRequest)

and: "User Service response is set"
def userResponse = UserDetailsResponse.defaultUserResponse
userData.setUserDataResponse(userResponse)

and: "Cookies with user ids"
def uidsCookie = UidsCookie.defaultUidsCookie
def cookieHeader = HttpUtil.getCookieHeader(mapper, uidsCookie)

when: "Sending auction request to PBS"
pgPbsService.sendAuctionRequest(bidRequest, cookieHeader)

then: "PBS sent a request to the bidder with added device info"
def bidderRequest = bidder.getBidderRequest(bidRequest.id)
assert bidderRequest.user?.ext?.fcapids == userResponse.user.ext.fcapIds
assert bidderRequest.user.data?.size() == userResponse.user.data.size()
assert bidderRequest.user.data[0].id == userResponse.user.data[0].name
assert bidderRequest.user.data[0].segment?.size() == userResponse.user.data[0].segment.size()
assert bidderRequest.user.data[0].segment[0].id == userResponse.user.data[0].segment[0].id
}

def "PBS should be able to add pmp deals part to the bidder request when PG is enabled"() {
given: "Bid request"
def bidRequest = BidRequest.defaultBidRequest

and: "Planner Mock line items"
def accountId = bidRequest.site.publisher.id
def plansResponse = new PlansResponse(lineItems: [LineItem.getDefaultLineItem(accountId), LineItem.getDefaultLineItem(accountId)])
generalPlanner.initPlansResponse(plansResponse)

and: "Bid response"
def bidResponse = BidResponse.getDefaultPgBidResponse(bidRequest, plansResponse)
bidder.setResponse(bidRequest.id, bidResponse)

and: "Line items are fetched by PBS"
pgPbsService.sendForceDealsUpdateRequest(ForceDealsUpdateRequest.updateLineItemsRequest)

when: "Sending auction request to PBS"
pgPbsService.sendAuctionRequest(bidRequest)

then: "PBS sent a request to the bidder with added deals"
def bidderRequest = bidder.getBidderRequest(bidRequest.id)
assert bidderRequest.imp?.size() == bidRequest.imp.size()
assert bidderRequest.imp[0].pmp?.deals?.size() == plansResponse.lineItems.size()
assert bidderRequest.imp[0].pmp?.deals
assert plansResponse.lineItems.each { lineItem ->
def deal = bidderRequest.imp[0]?.pmp?.deals?.find { it.id == lineItem.dealId }
assert deal
assert deal?.ext?.line?.lineItemId == lineItem.lineItemId
assert deal?.ext?.line?.extLineItemId == lineItem.extLineItemId
assert deal?.ext?.line?.sizes?.size() == lineItem.sizes.size()
assert deal?.ext?.line?.sizes[0].w == lineItem.sizes[0].w
assert deal?.ext?.line?.sizes[0].h == lineItem.sizes[0].h
}
}

@Ignore(value = "https://jira.magnite-core.com/browse/HB-13821")
def "PBS shouldn't add already top matched line item by first impression to the second impression deals bidder request section"() {
given: "Bid request with two impressions"
def bidRequest = BidRequest.defaultBidRequest.tap {
imp[0].ext.prebid.bidder = new Bidder(generic: new Generic())
imp << Imp.defaultImpression
imp[1].ext.prebid.bidder = new Bidder(generic: new Generic())
}

and: "Planner Mock line items"
def accountId = bidRequest.site.publisher.id
def plansResponse = new PlansResponse(lineItems: [LineItem.getDefaultLineItem(accountId), LineItem.getDefaultLineItem(accountId)])
generalPlanner.initPlansResponse(plansResponse)

and: "Bid response"
def bidResponse = BidResponse.getDefaultPgBidResponse(bidRequest, plansResponse)
bidder.setResponse(bidRequest.id, bidResponse)

and: "Line items are fetched by PBS"
pgPbsService.sendForceDealsUpdateRequest(ForceDealsUpdateRequest.updateLineItemsRequest)

when: "Sending auction request to PBS"
def auctionResponse = pgPbsService.sendAuctionRequest(bidRequest)

then: "PBS sent a request to the bidder with two impressions"
def bidderRequest = bidder.getBidderRequest(bidRequest.id)
assert bidderRequest.imp?.size() == bidRequest.imp.size()

and: "First impression contains 2 deals according to the line items"
def firstRequestImp = bidderRequest.imp.find { it.id == bidRequest.imp[0].id }
assert firstRequestImp?.pmp?.deals?.size() == plansResponse.lineItems.size()
assert plansResponse.lineItems.each { lineItem ->
def deal = firstRequestImp.pmp.deals.find { it.id == lineItem.dealId }
assert deal
assert deal?.ext?.line?.lineItemId == lineItem.lineItemId
assert deal?.ext?.line?.extLineItemId == lineItem.extLineItemId
assert deal?.ext?.line?.sizes?.size() == lineItem.sizes.size()
assert deal?.ext?.line?.sizes[0].w == lineItem.sizes[0].w
assert deal?.ext?.line?.sizes[0].h == lineItem.sizes[0].h
}

def topMatchLineItemId = firstRequestImp.pmp.deals.first().ext.line.lineItemId
def secondRequestImp = bidderRequest.imp.find { it.id == bidRequest.imp[1].id }

and: "Second impression contains only 1 deal excluding already top matched line items by the first impression"
assert secondRequestImp.pmp.deals.size() == plansResponse.lineItems.size() - 1
assert !(secondRequestImp.pmp.deals.collect { it.ext.line.lineItemId } in topMatchLineItemId)

assert plansResponse.lineItems.findAll { it.lineItemId != topMatchLineItemId }.each { lineItem ->
def deal = secondRequestImp.pmp.deals.find { it.id == lineItem.dealId }
assert deal
assert deal?.ext?.line?.lineItemId == lineItem.lineItemId
assert deal?.ext?.line?.extLineItemId == lineItem.extLineItemId
assert deal?.ext?.line?.sizes?.size() == lineItem.sizes.size()
assert deal?.ext?.line?.sizes[0].w == lineItem.sizes[0].w
assert deal?.ext?.line?.sizes[0].h == lineItem.sizes[0].h
}
}
}
Loading