Skip to content

Commit b6852f7

Browse files
authored
Test: Add tests for exponential backoff (prebid#2970)
1 parent 6c933d4 commit b6852f7

4 files changed

Lines changed: 143 additions & 12 deletions

File tree

src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/VendorList.groovy

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package org.prebid.server.functional.testcontainers.scaffolding
22

33
import org.mockserver.matchers.TimeToLive
44
import org.mockserver.matchers.Times
5+
import org.mockserver.model.Delay
56
import org.mockserver.model.HttpRequest
67
import org.mockserver.model.HttpResponse
78
import org.testcontainers.containers.MockServerContainer
@@ -17,7 +18,7 @@ import static org.prebid.server.functional.util.privacy.TcfConsent.TcfPolicyVers
1718

1819
class VendorList extends NetworkScaffolding {
1920

20-
private static final String VENDOR_LIST_ENDPOINT = "/{TCF_POLICY}/vendor-list.json"
21+
private static final String VENDOR_LIST_ENDPOINT = "/v{TCF_POLICY}/vendor-list.json"
2122

2223
VendorList(MockServerContainer mockServerContainer) {
2324
super(mockServerContainer, VENDOR_LIST_ENDPOINT)
@@ -39,16 +40,19 @@ class VendorList extends NetworkScaffolding {
3940
}
4041

4142
void setResponse(TcfPolicyVersion tcfPolicyVersion = TCF_POLICY_V2,
43+
Delay delay = null,
4244
Map<Integer, Vendor> vendors = [(GENERIC_VENDOR_ID): Vendor.getDefaultVendor(GENERIC_VENDOR_ID)]) {
43-
def prepareEndpoint = endpoint.replace("{TCF_POLICY}", "v" + tcfPolicyVersion.vendorListVersion)
45+
def prepareEndpoint = endpoint.replace("{TCF_POLICY}", tcfPolicyVersion.vendorListVersion.toString())
4446
def prepareEncodeResponseBody = encode(defaultVendorListResponse.tap {
4547
it.tcfPolicyVersion = tcfPolicyVersion.vendorListVersion
4648
it.vendors = vendors
4749
})
4850

4951
mockServerClient.when(request().withPath(prepareEndpoint), Times.unlimited(), TimeToLive.unlimited(), -10)
50-
.respond { request -> request.withPath(endpoint)
51-
? response().withStatusCode(OK_200.code()).withBody(prepareEncodeResponseBody)
52-
: HttpResponse.notFoundResponse()}
52+
.respond { request ->
53+
request.withPath(endpoint)
54+
? response().withStatusCode(OK_200.code()).withDelay(delay).withBody(prepareEncodeResponseBody)
55+
: HttpResponse.notFoundResponse()
56+
}
5357
}
5458
}

src/test/groovy/org/prebid/server/functional/tests/privacy/GdprAmpSpec.groovy

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.prebid.server.functional.tests.privacy
22

3+
import org.mockserver.model.Delay
34
import org.prebid.server.functional.model.ChannelType
45
import org.prebid.server.functional.model.config.AccountConfig
56
import org.prebid.server.functional.model.config.AccountGdprConfig
@@ -327,7 +328,7 @@ class GdprAmpSpec extends PrivacyBaseSpec {
327328
privacyPbsService.sendAmpRequest(ampRequest)
328329

329330
then: "Used vendor list have proper specification version of GVL"
330-
def properVendorListPath = "/app/prebid-server/data/vendorlist-v${tcfPolicyVersion.vendorListVersion}/${tcfPolicyVersion.vendorListVersion}.json"
331+
def properVendorListPath = VENDOR_LIST_PATH.replace("{VendorVersion}", tcfPolicyVersion.vendorListVersion.toString())
331332
PBSUtils.waitUntil { privacyPbsService.isFileExist(properVendorListPath) }
332333
def vendorList = privacyPbsService.getValueFromContainer(properVendorListPath, VendorListConsent.class)
333334
assert vendorList.tcfPolicyVersion == tcfPolicyVersion.vendorListVersion
@@ -369,4 +370,64 @@ class GdprAmpSpec extends PrivacyBaseSpec {
369370
assert response.ext?.warnings[PREBID]*.message ==
370371
["Parsing consent string: ${tcfConsent} failed. TCF policy version ${invalidTcfPolicyVersion} is not supported" as String]
371372
}
373+
374+
def "PBS amp should emit the same error without a second GVL list request if a retry is too soon for the exponential-backoff"() {
375+
given: "Test start time"
376+
def startTime = Instant.now()
377+
378+
and: "Prepare tcf consent string"
379+
def tcfConsent = new TcfConsent.Builder()
380+
.setPurposesLITransparency(BASIC_ADS)
381+
.setTcfPolicyVersion(tcfPolicyVersion.value)
382+
.setVendorListVersion(tcfPolicyVersion.vendorListVersion)
383+
.setVendorLegitimateInterest([GENERIC_VENDOR_ID])
384+
.build()
385+
386+
and: "AMP request"
387+
def ampRequest = getGdprAmpRequest(tcfConsent)
388+
389+
and: "Default stored request"
390+
def ampStoredRequest = BidRequest.defaultBidRequest
391+
392+
and: "Stored request in DB"
393+
def storedRequest = StoredRequest.getStoredRequest(ampRequest, ampStoredRequest)
394+
storedRequestDao.save(storedRequest)
395+
396+
and: "Reset valid vendor list response"
397+
vendorListResponse.reset()
398+
399+
and: "Set vendor list response with delay"
400+
vendorListResponse.setResponse(tcfPolicyVersion, Delay.seconds(EXPONENTIAL_BACKOFF_MAX_DELAY + 3))
401+
402+
when: "PBS processes amp request"
403+
privacyPbsService.sendAmpRequest(ampRequest)
404+
405+
then: "PBS shouldn't fetch vendor list"
406+
def vendorListPath = VENDOR_LIST_PATH.replace("{VendorVersion}", tcfPolicyVersion.vendorListVersion.toString())
407+
assert !privacyPbsService.isFileExist(vendorListPath)
408+
409+
and: "Logs should contain proper vendor list version"
410+
def logs = privacyPbsService.getLogsByTime(startTime)
411+
def tcfError = "TCF 2 vendor list for version v${tcfPolicyVersion.vendorListVersion}.${tcfPolicyVersion.vendorListVersion} not found, started downloading."
412+
assert getLogsByText(logs, tcfError)
413+
414+
and: "Second start for fetch second round of logs"
415+
def secondStartTime = Instant.now()
416+
417+
when: "PBS processes amp request"
418+
privacyPbsService.sendAmpRequest(ampRequest)
419+
420+
then: "PBS shouldn't fetch vendor list"
421+
assert !privacyPbsService.isFileExist(vendorListPath)
422+
423+
and: "Logs should contain proper vendor list version"
424+
def logsSecond = privacyPbsService.getLogsByTime(secondStartTime)
425+
assert getLogsByText(logsSecond, tcfError)
426+
427+
and: "Reset vendor list response"
428+
vendorListResponse.reset()
429+
430+
where:
431+
tcfPolicyVersion << [TCF_POLICY_V2, TCF_POLICY_V3]
432+
}
372433
}

src/test/groovy/org/prebid/server/functional/tests/privacy/GdprAuctionSpec.groovy

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.prebid.server.functional.tests.privacy
22

3+
import org.mockserver.model.Delay
34
import org.prebid.server.functional.model.ChannelType
45
import org.prebid.server.functional.model.config.AccountGdprConfig
56
import org.prebid.server.functional.model.request.auction.DistributionChannel
@@ -275,7 +276,7 @@ class GdprAuctionSpec extends PrivacyBaseSpec {
275276
privacyPbsService.sendAuctionRequest(bidRequest)
276277

277278
then: "Used vendor list have proper specification version of GVL"
278-
def properVendorListPath = "/app/prebid-server/data/vendorlist-v${tcfPolicyVersion.vendorListVersion}/${tcfPolicyVersion.vendorListVersion}.json"
279+
def properVendorListPath = VENDOR_LIST_PATH.replace("{VendorVersion}", tcfPolicyVersion.vendorListVersion.toString())
279280
PBSUtils.waitUntil { privacyPbsService.isFileExist(properVendorListPath) }
280281
def vendorList = privacyPbsService.getValueFromContainer(properVendorListPath, VendorListConsent.class)
281282
assert vendorList.tcfPolicyVersion == tcfPolicyVersion.vendorListVersion
@@ -313,4 +314,57 @@ class GdprAuctionSpec extends PrivacyBaseSpec {
313314
assert response.ext?.warnings[ErrorType.PREBID]*.message ==
314315
["Parsing consent string: ${tcfConsent} failed. TCF policy version ${invalidTcfPolicyVersion} is not supported" as String]
315316
}
317+
318+
def "PBS auction should emit the same error without a second GVL list request if a retry is too soon for the exponential-backoff"() {
319+
given: "Test start time"
320+
def startTime = Instant.now()
321+
322+
and: "Tcf consent setup"
323+
def tcfConsent = new TcfConsent.Builder()
324+
.setPurposesLITransparency(BASIC_ADS)
325+
.setTcfPolicyVersion(tcfPolicyVersion.value)
326+
.setVendorListVersion(tcfPolicyVersion.vendorListVersion)
327+
.setVendorLegitimateInterest([GENERIC_VENDOR_ID])
328+
.build()
329+
330+
and: "Bid request"
331+
def bidRequest = getGdprBidRequest(tcfConsent)
332+
333+
and: "Reset valid vendor list response"
334+
vendorListResponse.reset()
335+
336+
and: "Set vendor list response with delay"
337+
vendorListResponse.setResponse(tcfPolicyVersion, Delay.seconds(EXPONENTIAL_BACKOFF_MAX_DELAY + 3))
338+
339+
when: "PBS processes auction request"
340+
privacyPbsService.sendAuctionRequest(bidRequest)
341+
342+
then: "Used vendor list have proper specification version of GVL"
343+
def properVendorListPath = VENDOR_LIST_PATH.replace("{VendorVersion}", tcfPolicyVersion.vendorListVersion.toString())
344+
assert !privacyPbsService.isFileExist(properVendorListPath)
345+
346+
and: "Logs should contain proper vendor list version"
347+
def logs = privacyPbsService.getLogsByTime(startTime)
348+
def tcfError = "TCF 2 vendor list for version v${tcfPolicyVersion.vendorListVersion}.${tcfPolicyVersion.vendorListVersion} not found, started downloading."
349+
assert getLogsByText(logs, tcfError)
350+
351+
and: "Second start for fetch second round of logs"
352+
def secondStartTime = Instant.now()
353+
354+
when: "PBS processes amp request"
355+
privacyPbsService.sendAuctionRequest(bidRequest)
356+
357+
then: "PBS shouldn't fetch vendor list"
358+
assert !privacyPbsService.isFileExist(properVendorListPath)
359+
360+
and: "Logs should contain proper vendor list version"
361+
def logsSecond = privacyPbsService.getLogsByTime(secondStartTime)
362+
assert getLogsByText(logsSecond, tcfError)
363+
364+
and: "Reset vendor list response"
365+
vendorListResponse.reset()
366+
367+
where:
368+
tcfPolicyVersion << [TCF_POLICY_V2, TCF_POLICY_V3]
369+
}
316370
}

src/test/groovy/org/prebid/server/functional/tests/privacy/PrivacyBaseSpec.groovy

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ abstract class PrivacyBaseSpec extends BaseSpec {
6666
"gdpr.vendorlist.v3.http-endpoint-template": "$networkServiceContainer.rootUri/v3/vendor-list.json".toString()]
6767
protected static final Map<String, String> SETTING_CONFIG = ["settings.enforce-valid-account": 'true']
6868
protected static final Map<String, String> GENERIC_VENDOR_CONFIG = ["adapters.generic.meta-info.vendor-id": GENERIC_VENDOR_ID as String,
69-
"gdpr.host-vendor-id" : GENERIC_VENDOR_ID as String,
70-
"adapters.generic.ccpa-enforced" : "true"]
69+
"gdpr.host-vendor-id" : GENERIC_VENDOR_ID as String,
70+
"adapters.generic.ccpa-enforced" : "true"]
7171

7272
@Shared
7373
protected static final int PURPOSES_ONLY_GVL_VERSION = PBSUtils.getRandomNumber(0, 4095)
@@ -78,17 +78,29 @@ abstract class PrivacyBaseSpec extends BaseSpec {
7878
@Shared
7979
protected static final int PURPOSES_AND_LEG_INT_PURPOSES_GVL_VERSION = PBSUtils.getRandomNumberWithExclusion([PURPOSES_ONLY_GVL_VERSION, LEG_INT_PURPOSES_ONLY_GVL_VERSION, LEG_INT_AND_FLEXIBLE_PURPOSES_GVL_VERSION], 0, 4095)
8080

81+
protected static final int EXPONENTIAL_BACKOFF_MAX_DELAY = 1
82+
83+
private static final Map<String, String> RETRY_POLICY_EXPONENTIAL_CONFIG = [
84+
"gdpr.vendorlist.v2.retry-policy.exponential-backoff.delay-millis" : 1 as String,
85+
"gdpr.vendorlist.v2.retry-policy.exponential-backoff.max-delay-millis": EXPONENTIAL_BACKOFF_MAX_DELAY as String,
86+
"gdpr.vendorlist.v2.retry-policy.exponential-backoff.factor" : Long.MAX_VALUE as String,
87+
"gdpr.vendorlist.v3.retry-policy.exponential-backoff.delay-millis" : 1 as String,
88+
"gdpr.vendorlist.v3.retry-policy.exponential-backoff.max-delay-millis": EXPONENTIAL_BACKOFF_MAX_DELAY as String,
89+
"gdpr.vendorlist.v3.retry-policy.exponential-backoff.factor" : Long.MAX_VALUE as String]
90+
8191
private static final PbsPgConfig pgConfig = new PbsPgConfig(networkServiceContainer)
8292

83-
protected static final Map<String, String> PBS_CONFIG = OPENX_CONFIG + OPENX_COOKIE_SYNC_CONFIG +
84-
GENERIC_COOKIE_SYNC_CONFIG + pgConfig.properties + GDPR_VENDOR_LIST_CONFIG + SETTING_CONFIG + GENERIC_VENDOR_CONFIG
93+
protected static final String VENDOR_LIST_PATH = "/app/prebid-server/data/vendorlist-v{VendorVersion}/{VendorVersion}.json"
8594
protected static final String VALID_VALUE_FOR_GPC_HEADER = "1"
8695
protected static final GppConsent SIMPLE_GPC_DISALLOW_LOGIC = new UspNatV1Consent.Builder().setGpc(true).build()
8796
protected static final VendorList vendorListResponse = new VendorList(networkServiceContainer)
8897

8998
@Shared
9099
protected final PrebidServerService privacyPbsService = pbsServiceFactory.getService(GDPR_VENDOR_LIST_CONFIG +
91-
GENERIC_COOKIE_SYNC_CONFIG + GENERIC_VENDOR_CONFIG)
100+
GENERIC_COOKIE_SYNC_CONFIG + GENERIC_VENDOR_CONFIG + RETRY_POLICY_EXPONENTIAL_CONFIG)
101+
102+
protected static final Map<String, String> PBS_CONFIG = OPENX_CONFIG + OPENX_COOKIE_SYNC_CONFIG +
103+
GENERIC_COOKIE_SYNC_CONFIG + pgConfig.properties + GDPR_VENDOR_LIST_CONFIG + SETTING_CONFIG + GENERIC_VENDOR_CONFIG
92104

93105
@Shared
94106
protected final PrebidServerService activityPbsService = pbsServiceFactory.getService(PBS_CONFIG)

0 commit comments

Comments
 (0)