Skip to content

Conversation

@osulzhenko
Copy link
Collaborator

@osulzhenko osulzhenko commented Mar 13, 2025

🔧 Type of changes

  • new bid adapter
  • bid adapter update
  • new feature
  • new analytics adapter
  • new module
  • module update
  • bugfix
  • documentation
  • configuration
  • dependency update
  • tech debt (test coverage, refactorings, etc.)

✨ What's the context?

What's the context for the changes?

🧠 Rationale behind the change

Why did you choose to make these changes? Were there any trade-offs you had to consider?

🔎 New Bid Adapter Checklist

  • verify email contact works
  • NO fully dynamic hostnames
  • geographic host parameters are NOT required
  • direct use of HTTP is prohibited - implement an existing Bidder interface that will do all the job
  • if the ORTB is just forwarded to the endpoint, use the generic adapter - define the new adapter as the alias of the generic adapter
  • cover an adapter configuration with an integration test

🧪 Test plan

How do you know the changes are safe to ship to production?

🏎 Quality check

  • Are your changes following our code style guidelines?
  • Are there any breaking changes in your code?
  • Does your test coverage exceed 90%?
  • Are there any erroneous console logs, debuggers or leftover code in your changes?

@osulzhenko osulzhenko added the tests Functional or other tests label Mar 13, 2025
@osulzhenko osulzhenko requested a review from marki1an March 13, 2025 18:36
@osulzhenko osulzhenko self-assigned this Mar 13, 2025
then: "PBS should rank bid with deal as top priority"
def bids = response.seatbid.first.bid
assert bids.find(it -> it.id == bidBDeal.id).ext.prebid.rank == 1
assert bids.find(it -> it.id == bidBiggerPrice.id).ext.prebid.rank == 2
Copy link
Collaborator

Choose a reason for hiding this comment

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

I hope bid.price (highest first)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Check other occurrences

assert bids.find(it -> it.id == bidBiggerPrice.id).ext.prebid.rank == 2
}

def "PBS should ignore bid ranked from original response when auction.ranking default"() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Here we can add a where block and add a case for default and false, and we should receive the same result

Comment on lines 1633 to 1637
and: "Account in the DB"
def accountAuctionConfig = new AccountAuctionConfig(ranking: new AuctionRankingConfig(enabled: true))
def accountConfig = new AccountConfig(status: ACTIVE, auction: accountAuctionConfig)
def account = new Account(uuid: bidRequest.accountId, config: accountConfig)
accountDao.save(account)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can be in a static method like getAccountConfigWithEnabledAuctionRanking()


and: "Account in the DB"
def accountId = PBSUtils.randomNumber.toString()

Copy link
Collaborator

Choose a reason for hiding this comment

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

Please remove empty line

@@ -0,0 +1,6 @@
package org.prebid.server.functional.model.config

class AuctionCacheConfig {
Copy link
Collaborator

Choose a reason for hiding this comment

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

@tostring(includeNames = true, ignoreNulls = true)

@@ -0,0 +1,6 @@
package org.prebid.server.functional.model.config

class AuctionRankingConfig {
Copy link
Collaborator

Choose a reason for hiding this comment

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

@tostring(includeNames = true, ignoreNulls = true)

@osulzhenko osulzhenko requested a review from marki1an May 28, 2025 08:34
@osulzhenko osulzhenko changed the base branch from master to bid-ranking June 3, 2025 18:46
@osulzhenko osulzhenko force-pushed the functional-tests/bid-ranking branch from 5035474 to 34428bb Compare June 3, 2025 21:09
…unctional-tests/bid-ranking

# Conflicts:
#	src/test/groovy/org/prebid/server/functional/model/config/AccountAuctionConfig.groovy
]
}

def "PBS shouldn't add bid ranked for multiple media types request when account config for auction.ranking disabled or default"() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would leave only a one such test that starts with PBS shouldn't add bid ranked, because ranking depends on multibid config and not vice versa, so those tests look redundant except for the fact they check the bid ranking config

def response = defaultPbsService.sendAuctionRequest(bidRequest)

then: "PBS should rank single bid"
assert response.seatbid.first.bid?.ext?.prebid?.rank?.flatten() == [1]
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd say the bid ranking feature make sense only when there are at least two bids in order to cover correctness of the sorting logic

in the particular test it mentions preferDeals but it can't be covered because only one bid is present

if you want to show that the second bid was removed due to multibid config I still suggest using another valid bid in order to show that the ranking isn't broken

e.g.
multibid1.price = 1
multibid2.price = 2
bid3.price = 0.5

the result is multibid2.rank = 1, bid3.rank = 2 (not 3)

assert response.seatbid.first.bid?.ext?.prebid?.rank?.flatten() == [1]
}

def "PBS should add bid ranked and rank by deals for request with multiBid when auction.ranking and preferDeals are enabled"() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

one important thing that is missed in tests is understanding that the sorting and ranking happens within an imp, and I don't see any test mention it while it's a core requirement and I don't see any test covers two bids for different imps that have the same rank

}
}

static List<Bid> getDefaultMultyTypesBids(Imp imp, @DelegatesTo(Bid) Closure commonInit = null) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Multi

assert bids.find(it -> it.id == bidBiggerPrice.id).ext.prebid.rank == 2
}

def "PBS should add bid ranked and rank by deals for multiple media types request when auction.ranking and preferDeals are enabled"() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't understand the difference between this test and PBS should add bid ranked and rank by deals for request with multiBid when auction.ranking and preferDeals are enabled

looks like the set up is pretty much the same, and the multiple media type request doesn't have any impact on the outcome, since the outcome is mocked identically

@osulzhenko osulzhenko requested a review from AntoxaAntoxic June 5, 2025 12:47
Comment on lines +1750 to +1751
assert bids.find(it -> it.id == bidBiggerPrice.id).ext.prebid.rank == 1
assert bids.find(it -> it.id == bidBDeal.id).ext.prebid.rank == 2
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please consider to replace magic 1 and 2 numbers with something meaningful

it.price = bidPrice + 1
it.ext = new BidExt(prebid: new Prebid(rank: PBSUtils.randomNumber))
}
def bidBDeal = Bid.getDefaultBid(bidRequest.imp[0]).tap {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Rename with like bidWithDealId

def prebidServerService = pbsServiceFactory.getService(pbsConfig)

and: "Bid request with multiple bidders"
def bidRequest = BidRequest.getDefaultVideoRequest().tap {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why only video request?

assert bids.find(it -> it.id == lowerPriceBid.id).ext.prebid.rank == 2

and: "PBS should contain error for invalid bid"
assert response.ext.errors[ErrorType.GENERIC]?.message?.any { it.contains(middlePriceBid.id) }
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you add proper assets for error with the full sentence

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is not a validation test case. It shouldn’t matter what error is here — main task is to verify that PBS sets ranks correctly


def middlePriceBid = Bid.getDefaultBid(bidRequest.imp.first).tap {
price = bidPrice + 1
adm = null
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why was the adm removed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

adm was removed to provoke a bid error; it could be any type of error except for a pricing one.
An error with adm just popped into my mind first, that’s all

@osulzhenko osulzhenko requested a review from marki1an June 9, 2025 13:54
@osulzhenko osulzhenko merged commit 96c0727 into bid-ranking Jun 10, 2025
1 check passed
@osulzhenko osulzhenko deleted the functional-tests/bid-ranking branch June 10, 2025 09:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tests Functional or other tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants