Skip to content

Commit

Permalink
Tests: Cover DSA fields and validation (#2939)
Browse files Browse the repository at this point in the history
  • Loading branch information
AntoxaAntoxic authored Feb 5, 2024
1 parent 062a7b2 commit bcc291c
Show file tree
Hide file tree
Showing 7 changed files with 378 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.prebid.server.functional.model.request.auction

import groovy.transform.ToString
import org.prebid.server.functional.util.PBSUtils

@ToString(includeNames = true, ignoreNulls = true)
class DsaTransparency {

String domain
List<Integer> params

static DsaTransparency getDefaultRegsDsaTransparency() {
new DsaTransparency(domain: PBSUtils.randomString)
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.prebid.server.functional.model.request.auction

import com.fasterxml.jackson.databind.PropertyNamingStrategies
import com.fasterxml.jackson.databind.annotation.JsonNaming
import groovy.transform.ToString
import org.prebid.server.functional.util.PBSUtils

@JsonNaming(PropertyNamingStrategies.LowerCaseStrategy)
@ToString(includeNames = true, ignoreNulls = true)
class RegsDsa {

Integer required
Integer pubRender
Integer dataToPub
List<DsaTransparency> transparency

static RegsDsa getDefaultRegsDsa(ReqsDsaRequiredType required) {
new RegsDsa(
required: required.value,
pubRender: PBSUtils.getRandomNumber(0, 2),
dataToPub: PBSUtils.getRandomNumber(0, 2),
transparency: [DsaTransparency.defaultRegsDsaTransparency]
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ class RegsExt {
Integer gdpr
String usPrivacy
String gpc
RegsDsa dsa

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.prebid.server.functional.model.request.auction

import com.fasterxml.jackson.annotation.JsonValue

enum ReqsDsaRequiredType {

NOT_REQUIRED(0), SUPPORTED(1), REQUIRED(2), REQUIRED_PUBLISHER_ONLINE_PLATFORM(3)

@JsonValue
final Integer value

ReqsDsaRequiredType(Integer value) {
this.value = value
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package org.prebid.server.functional.model.response.auction

import groovy.transform.ToString
import org.prebid.server.functional.model.Currency

@ToString(includeNames = true, ignoreNulls = true)
class BidExt {

Prebid prebid
BigDecimal origbidcpm
Currency origbidcur
BidExtDsa dsa

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.prebid.server.functional.model.response.auction

import groovy.transform.ToString
import org.prebid.server.functional.model.request.auction.DsaTransparency
import org.prebid.server.functional.util.PBSUtils

@ToString(includeNames = true, ignoreNulls = true)
class BidExtDsa {

String behalf
String paid
List<DsaTransparency> transparency
Integer adrender

static BidExtDsa getDefaultBidExtDsa() {
new BidExtDsa(
behalf: PBSUtils.randomString,
paid: PBSUtils.randomString,
adrender: PBSUtils.getRandomNumber(0, 2),
transparency: [DsaTransparency.defaultRegsDsaTransparency]
)
}
}
293 changes: 293 additions & 0 deletions src/test/groovy/org/prebid/server/functional/tests/DsaSpec.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
package org.prebid.server.functional.tests

import org.prebid.server.functional.model.bidder.BidderName
import org.prebid.server.functional.model.db.StoredRequest
import org.prebid.server.functional.model.request.amp.AmpRequest
import org.prebid.server.functional.model.request.auction.BidRequest
import org.prebid.server.functional.model.request.auction.RegsDsa
import org.prebid.server.functional.model.request.auction.ReqsDsaRequiredType
import org.prebid.server.functional.model.response.auction.BidExt
import org.prebid.server.functional.model.response.auction.BidExtDsa
import org.prebid.server.functional.model.response.auction.BidResponse

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

class DsaSpec extends BaseSpec {

def "AMP request should send DSA to bidder and succeed when DSA is not required"() {
given: "Default AmpRequest"
def ampRequest = AmpRequest.defaultAmpRequest
def dsa = RegsDsa.getDefaultRegsDsa(dsaRequired)

and: "Stored default bid request with DSA"
def ampStoredRequest = BidRequest.defaultBidRequest.tap {
regs.ext.dsa = dsa
setAccountId(ampRequest.account)
}

and: "Save storedRequest into DB"
def storedRequest = StoredRequest.getStoredRequest(ampRequest, ampStoredRequest)
storedRequestDao.save(storedRequest)

and: "Default bidder response with DSA"
def bidResponse = BidResponse.getDefaultBidResponse(ampStoredRequest).tap {
seatbid[0].bid[0].ext = bidExt
}

and: "Set bidder response"
bidder.setResponse(ampStoredRequest.id, bidResponse)

when: "PBS processes amp request"
def response = defaultPbsService.sendAmpRequest(ampRequest)

then: "Bidder request should contain DSA"
def bidderRequests = bidder.getBidderRequest(ampStoredRequest.id)
verifyAll {
bidderRequests.regs.ext.dsa.required == dsa.required
bidderRequests.regs.ext.dsa.dataToPub == dsa.dataToPub
bidderRequests.regs.ext.dsa.pubRender == dsa.pubRender
bidderRequests.regs.ext.dsa.transparency[0].domain == dsa.transparency[0].domain
bidderRequests.regs.ext.dsa.transparency[0].params == dsa.transparency[0].params
}

and: "Bidder response should not contain DSA"
def bidderResponse = decode(response.ext.debug.httpcalls.get(BidderName.GENERIC.value)[0].responseBody, BidResponse)
assert !bidderResponse.seatbid[0].bid[0].ext?.dsa

and: "PBS should not log warning"
assert !response.ext.warnings
assert !response.ext.errors

where:
dsaRequired | bidExt
ReqsDsaRequiredType.NOT_REQUIRED | null
ReqsDsaRequiredType.SUPPORTED | new BidExt(dsa: null)
}

def "AMP request should send DSA to bidder and always succeed when bidder returns DSA"() {
given: "Default AmpRequest"
def ampRequest = AmpRequest.defaultAmpRequest
def dsa = RegsDsa.getDefaultRegsDsa(dsaRequired)

and: "Stored default bid request with DSA"
def ampStoredRequest = BidRequest.defaultBidRequest.tap {
regs.ext.dsa = dsa
setAccountId(ampRequest.account)
}

and: "Save storedRequest into DB"
def storedRequest = StoredRequest.getStoredRequest(ampRequest, ampStoredRequest)
storedRequestDao.save(storedRequest)

and: "Default bidder response with DSA"
def bidDsa = BidExtDsa.getDefaultBidExtDsa()
def bidResponse = BidResponse.getDefaultBidResponse(ampStoredRequest).tap {
seatbid[0].bid[0].ext = new BidExt(dsa: bidDsa)
}

and: "Set bidder response"
bidder.setResponse(ampStoredRequest.id, bidResponse)

when: "PBS processes amp request"
def response = defaultPbsService.sendAmpRequest(ampRequest)

then: "Bidder request should contain DSA"
def bidderRequests = bidder.getBidderRequest(ampStoredRequest.id)
verifyAll {
bidderRequests.regs.ext.dsa.required == dsa.required
bidderRequests.regs.ext.dsa.dataToPub == dsa.dataToPub
bidderRequests.regs.ext.dsa.pubRender == dsa.pubRender
bidderRequests.regs.ext.dsa.transparency[0].domain == dsa.transparency[0].domain
bidderRequests.regs.ext.dsa.transparency[0].params == dsa.transparency[0].params
}

and: "Bidder response should contain DSA"
def bidderResponse = decode(response.ext.debug.httpcalls.get(BidderName.GENERIC.value)[0].responseBody, BidResponse)
def actualDsa = bidderResponse.seatbid[0].bid[0].ext.dsa
verifyAll {
actualDsa.transparency[0].domain == bidDsa.transparency[0].domain
actualDsa.transparency[0].params == bidDsa.transparency[0].params
actualDsa.adrender == bidDsa.adrender
actualDsa.behalf == bidDsa.behalf
actualDsa.paid == bidDsa.paid
}

and: "PBS should not log warning"
assert !response.ext.warnings
assert !response.ext.errors

where:
dsaRequired << ReqsDsaRequiredType.values()
}

def "AMP request should send DSA to bidder and fail on response when DSA is required and bidder does not return DSA"() {
given: "Default AmpRequest"
def ampRequest = AmpRequest.defaultAmpRequest
def dsa = RegsDsa.getDefaultRegsDsa(dsaRequired)

and: "Stored default bid request with DSA"
def ampStoredRequest = BidRequest.defaultBidRequest.tap {
regs.ext.dsa = dsa
setAccountId(ampRequest.account)
}

and: "Save storedRequest into DB"
def storedRequest = StoredRequest.getStoredRequest(ampRequest, ampStoredRequest)
storedRequestDao.save(storedRequest)

and: "Default bidder response with DSA"
def bidResponse = BidResponse.getDefaultBidResponse(ampStoredRequest).tap {
seatbid[0].bid[0].ext = bidExt
}

and: "Set bidder response"
bidder.setResponse(ampStoredRequest.id, bidResponse)

when: "PBS processes amp request"
def response = defaultPbsService.sendAmpRequest(ampRequest)

then: "Bidder request should contain DSA"
def bidderRequests = bidder.getBidderRequest(ampStoredRequest.id)
verifyAll {
bidderRequests.regs.ext.dsa.required == dsa.required
bidderRequests.regs.ext.dsa.dataToPub == dsa.dataToPub
bidderRequests.regs.ext.dsa.pubRender == dsa.pubRender
bidderRequests.regs.ext.dsa.transparency[0].domain == dsa.transparency[0].domain
bidderRequests.regs.ext.dsa.transparency[0].params == dsa.transparency[0].params
}

and: "Bidder response should not contain DSA"
def bidderResponse = decode(response.ext.debug.httpcalls.get(BidderName.GENERIC.value)[0].responseBody, BidResponse)
assert !bidderResponse.seatbid[0].bid[0].ext?.dsa

and: "Response should contain error"
def expectedBidId = bidResponse.seatbid[0].bid[0].id
assert response.ext?.errors[GENERIC]*.code == [5]
assert response.ext?.errors[GENERIC]*.message == ["BidId `$expectedBidId` validation messages: Error: Bid \"$expectedBidId\" missing DSA"]

where:
dsaRequired | bidExt
ReqsDsaRequiredType.REQUIRED | new BidExt(dsa: null)
ReqsDsaRequiredType.REQUIRED_PUBLISHER_ONLINE_PLATFORM | null
}

def "Auction request should send DSA to bidder and succeeds when DSA is not required and bidder does not return DSA"() {
given: "Default bid request with DSA"
def dsa = RegsDsa.getDefaultRegsDsa(dsaRequired)
def bidRequest = BidRequest.defaultBidRequest.tap {
regs.ext.dsa = dsa
}

and: "Default bidder response with DSA"
def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap {
seatbid[0].bid[0].ext = new BidExt(dsa: null)
}

and: "Set bidder response"
bidder.setResponse(bidRequest.id, bidResponse)

when: "PBS processes auction request"
def response = defaultPbsService.sendAuctionRequest(bidRequest)

then: "Bidder request should contain DSA"
def bidderRequests = bidder.getBidderRequest(bidRequest.id)
verifyAll {
bidderRequests.regs.ext.dsa.required == dsa.required
bidderRequests.regs.ext.dsa.dataToPub == dsa.dataToPub
bidderRequests.regs.ext.dsa.pubRender == dsa.pubRender
bidderRequests.regs.ext.dsa.transparency[0].domain == dsa.transparency[0].domain
bidderRequests.regs.ext.dsa.transparency[0].params == dsa.transparency[0].params
}

and: "DSA is not returned"
assert !response.seatbid[0].bid[0].ext.dsa

where:
dsaRequired << [ReqsDsaRequiredType.NOT_REQUIRED, ReqsDsaRequiredType.SUPPORTED]
}

def "Auction request should send DSA to bidder and always succeed when bidder returns DSA"() {
given: "Default bid request with DSA"
def dsa = RegsDsa.getDefaultRegsDsa(dsaRequired)
def bidRequest = BidRequest.defaultBidRequest.tap {
regs.ext.dsa = dsa
}

and: "Default bidder response with DSA"
def bidDsa = BidExtDsa.getDefaultBidExtDsa()
def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap {
seatbid[0].bid[0].ext = new BidExt(dsa: bidDsa)
}

and: "Set bidder response"
bidder.setResponse(bidRequest.id, bidResponse)

when: "PBS processes auction request"
def response = defaultPbsService.sendAuctionRequest(bidRequest)

then: "Bidder request should contain DSA"
def bidderRequests = bidder.getBidderRequest(bidRequest.id)
verifyAll {
bidderRequests.regs.ext.dsa.required == dsa.required
bidderRequests.regs.ext.dsa.dataToPub == dsa.dataToPub
bidderRequests.regs.ext.dsa.pubRender == dsa.pubRender
bidderRequests.regs.ext.dsa.transparency[0].domain == dsa.transparency[0].domain
bidderRequests.regs.ext.dsa.transparency[0].params == dsa.transparency[0].params
}

and: "DSA is not returned"
def actualDsa = response.seatbid[0].bid[0].ext.dsa
verifyAll {
actualDsa.transparency[0].domain == bidDsa.transparency[0].domain
actualDsa.transparency[0].params == bidDsa.transparency[0].params
actualDsa.adrender == bidDsa.adrender
actualDsa.behalf == bidDsa.behalf
actualDsa.paid == bidDsa.paid
}

where:
dsaRequired << ReqsDsaRequiredType.values()
}

def "Auction request should send DSA to bidder and fail on response when DSA is required and bidder does not return DSA"() {
given: "Default bid request with DSA"
def dsa = RegsDsa.getDefaultRegsDsa(dsaRequired)
def bidRequest = BidRequest.defaultBidRequest.tap {
regs.ext.dsa = dsa
}

and: "Default bidder response with DSA"
def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap {
seatbid[0].bid[0].ext = bidExt
}

and: "Set bidder response"
bidder.setResponse(bidRequest.id, bidResponse)

when: "PBS processes auction request"
def response = defaultPbsService.sendAuctionRequest(bidRequest)

then: "Bidder request should contain DSA"
def bidderRequests = bidder.getBidderRequest(bidRequest.id)
verifyAll {
bidderRequests.regs.ext.dsa.required == dsa.required
bidderRequests.regs.ext.dsa.dataToPub == dsa.dataToPub
bidderRequests.regs.ext.dsa.pubRender == dsa.pubRender
bidderRequests.regs.ext.dsa.transparency[0].domain == dsa.transparency[0].domain
bidderRequests.regs.ext.dsa.transparency[0].params == dsa.transparency[0].params
}

and: "Response should contain error"
def expectedBidId = bidResponse.seatbid[0].bid[0].id
verifyAll {
response.seatbid.isEmpty()
response.ext?.errors[GENERIC]*.code == [5]
response.ext?.errors[GENERIC]*.message == ["BidId `$expectedBidId` validation messages: Error: Bid \"$expectedBidId\" missing DSA"]
}

where:
dsaRequired | bidExt
ReqsDsaRequiredType.REQUIRED | new BidExt(dsa: null)
ReqsDsaRequiredType.REQUIRED_PUBLISHER_ONLINE_PLATFORM | null
}
}

0 comments on commit bcc291c

Please sign in to comment.