-
Notifications
You must be signed in to change notification settings - Fork 181
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
Net-burst
merged 3 commits into
add-pg-tests-infrastructure
from
add-bid-req-resp-pg-tests
Feb 7, 2022
Merged
Changes from 1 commit
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
164 changes: 164 additions & 0 deletions
164
src/test/groovy/org/prebid/server/functional/pg/PgBidResponseSpec.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | | ||
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'" | ||
} | ||
} |
156 changes: 156 additions & 0 deletions
156
src/test/groovy/org/prebid/server/functional/pg/PgBidderRequestSpec.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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