From e5a66a81b508e9def258e057d5c58b1576e12fe2 Mon Sep 17 00:00:00 2001 From: Markiyan Mykush <95693607+marki1an@users.noreply.github.com> Date: Thu, 7 Nov 2024 13:10:43 +0200 Subject: [PATCH] Test: `pb request correction` module (#3533) Add functional tests for pb request correction module --- .../server/functional/model/ModuleName.groovy | 3 +- .../config/ModuleHookImplementation.groovy | 3 +- .../config/PbRequestCorrectionConfig.groovy | 29 ++ .../model/config/PbsModulesConfig.groovy | 1 + .../model/request/auction/AppExt.groovy | 1 + .../model/request/auction/AppPrebid.groovy | 10 + .../model/request/auction/Imp.groovy | 2 +- .../tests/module/ModuleBaseSpec.groovy | 8 + .../PbRequestCorrectionSpec.groovy | 454 ++++++++++++++++++ .../server/functional/util/PBSUtils.groovy | 23 + 10 files changed, 531 insertions(+), 3 deletions(-) create mode 100644 src/test/groovy/org/prebid/server/functional/model/config/PbRequestCorrectionConfig.groovy create mode 100644 src/test/groovy/org/prebid/server/functional/model/request/auction/AppPrebid.groovy create mode 100644 src/test/groovy/org/prebid/server/functional/tests/module/pbrequestcorrection/PbRequestCorrectionSpec.groovy diff --git a/src/test/groovy/org/prebid/server/functional/model/ModuleName.groovy b/src/test/groovy/org/prebid/server/functional/model/ModuleName.groovy index 5efcdf40709..2bc06ab7144 100644 --- a/src/test/groovy/org/prebid/server/functional/model/ModuleName.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/ModuleName.groovy @@ -6,7 +6,8 @@ enum ModuleName { PB_RICHMEDIA_FILTER("pb-richmedia-filter"), PB_RESPONSE_CORRECTION ("pb-response-correction"), - ORTB2_BLOCKING("ortb2-blocking") + ORTB2_BLOCKING("ortb2-blocking"), + PB_REQUEST_CORRECTION('pb-request-correction'), @JsonValue final String code diff --git a/src/test/groovy/org/prebid/server/functional/model/config/ModuleHookImplementation.groovy b/src/test/groovy/org/prebid/server/functional/model/config/ModuleHookImplementation.groovy index b5c57122a3f..247bdea4353 100644 --- a/src/test/groovy/org/prebid/server/functional/model/config/ModuleHookImplementation.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/config/ModuleHookImplementation.groovy @@ -9,7 +9,8 @@ enum ModuleHookImplementation { PB_RICHMEDIA_FILTER_ALL_PROCESSED_RESPONSES("pb-richmedia-filter-all-processed-bid-responses-hook"), RESPONSE_CORRECTION_ALL_PROCESSED_RESPONSES("pb-response-correction-all-processed-bid-responses"), ORTB2_BLOCKING_BIDDER_REQUEST("ortb2-blocking-bidder-request"), - ORTB2_BLOCKING_RAW_BIDDER_RESPONSE("ortb2-blocking-raw-bidder-response") + ORTB2_BLOCKING_RAW_BIDDER_RESPONSE("ortb2-blocking-raw-bidder-response"), + PB_REQUEST_CORRECTION_PROCESSED_AUCTION_REQUEST("pb-request-correction-processed-auction-request"), @JsonValue final String code diff --git a/src/test/groovy/org/prebid/server/functional/model/config/PbRequestCorrectionConfig.groovy b/src/test/groovy/org/prebid/server/functional/model/config/PbRequestCorrectionConfig.groovy new file mode 100644 index 00000000000..5d7a980115b --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/config/PbRequestCorrectionConfig.groovy @@ -0,0 +1,29 @@ +package org.prebid.server.functional.model.config + +import com.fasterxml.jackson.annotation.JsonProperty +import groovy.transform.ToString + +@ToString(includeNames = true, ignoreNulls = true) +class PbRequestCorrectionConfig { + + @JsonProperty("pbsdkAndroidInstlRemove") + Boolean interstitialCorrectionEnabled + @JsonProperty("pbsdkUaCleanup") + Boolean userAgentCorrectionEnabled + @JsonProperty("pbsdk-android-instl-remove") + Boolean interstitialCorrectionEnabledKebabCase + @JsonProperty("pbsdk-ua-cleanup") + Boolean userAgentCorrectionEnabledKebabCase + + Boolean enabled + + static PbRequestCorrectionConfig getDefaultConfigWithInterstitial(Boolean interstitialCorrectionEnabled = true, + Boolean enabled = true) { + new PbRequestCorrectionConfig(enabled: enabled, interstitialCorrectionEnabled: interstitialCorrectionEnabled) + } + + static PbRequestCorrectionConfig getDefaultConfigWithUserAgentCorrection(Boolean userAgentCorrectionEnabled = true, + Boolean enabled = true) { + new PbRequestCorrectionConfig(enabled: enabled, userAgentCorrectionEnabled: userAgentCorrectionEnabled) + } +} diff --git a/src/test/groovy/org/prebid/server/functional/model/config/PbsModulesConfig.groovy b/src/test/groovy/org/prebid/server/functional/model/config/PbsModulesConfig.groovy index f9121ae0b3a..59f640f966c 100644 --- a/src/test/groovy/org/prebid/server/functional/model/config/PbsModulesConfig.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/config/PbsModulesConfig.groovy @@ -12,4 +12,5 @@ class PbsModulesConfig { RichmediaFilter pbRichmediaFilter Ortb2BlockingConfig ortb2Blocking PbResponseCorrection pbResponseCorrection + PbRequestCorrectionConfig pbRequestCorrection } diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/AppExt.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/AppExt.groovy index b31926c14b5..ee3c1c9a8f0 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/AppExt.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/AppExt.groovy @@ -6,4 +6,5 @@ import groovy.transform.ToString class AppExt { AppExtData data + AppPrebid prebid } diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/AppPrebid.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/AppPrebid.groovy new file mode 100644 index 00000000000..edb365d4d6f --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/AppPrebid.groovy @@ -0,0 +1,10 @@ +package org.prebid.server.functional.model.request.auction + +import groovy.transform.ToString + +@ToString(includeNames = true, ignoreNulls = true) +class AppPrebid { + + String source + String version +} diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/Imp.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/Imp.groovy index dbea9b32624..13c97a36ba4 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/Imp.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/Imp.groovy @@ -30,7 +30,7 @@ class Imp { Pmp pmp String displayManager String displayManagerVer - Integer instl + OperationState instl String tagId BigDecimal bidFloor Currency bidFloorCur diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/ModuleBaseSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/ModuleBaseSpec.groovy index 19cb2cd53de..7d281790dcb 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/ModuleBaseSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/ModuleBaseSpec.groovy @@ -2,13 +2,16 @@ package org.prebid.server.functional.tests.module import org.prebid.server.functional.model.config.Endpoint import org.prebid.server.functional.model.config.ExecutionPlan +import org.prebid.server.functional.model.config.Stage import org.prebid.server.functional.tests.BaseSpec import static org.prebid.server.functional.model.ModuleName.ORTB2_BLOCKING +import static org.prebid.server.functional.model.ModuleName.PB_REQUEST_CORRECTION import static org.prebid.server.functional.model.ModuleName.PB_RESPONSE_CORRECTION import static org.prebid.server.functional.model.ModuleName.PB_RICHMEDIA_FILTER import static org.prebid.server.functional.model.config.Endpoint.OPENRTB2_AUCTION import static org.prebid.server.functional.model.config.Stage.ALL_PROCESSED_BID_RESPONSES +import static org.prebid.server.functional.model.config.Stage.PROCESSED_AUCTION_REQUEST class ModuleBaseSpec extends BaseSpec { @@ -51,4 +54,9 @@ class ModuleBaseSpec extends BaseSpec { protected static Map getOrtb2BlockingSettings(boolean isEnabled = true) { ["hooks.${ORTB2_BLOCKING.code}.enabled": isEnabled as String] } + + protected static Map getRequestCorrectionSettings(Endpoint endpoint = OPENRTB2_AUCTION, Stage stage = PROCESSED_AUCTION_REQUEST) { + ["hooks.${PB_REQUEST_CORRECTION.code}.enabled": "true", + "hooks.host-execution-plan" : encode(ExecutionPlan.getSingleEndpointExecutionPlan(endpoint, PB_REQUEST_CORRECTION, [stage]))] + } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/pbrequestcorrection/PbRequestCorrectionSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/pbrequestcorrection/PbRequestCorrectionSpec.groovy new file mode 100644 index 00000000000..68b00bdd0d1 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/tests/module/pbrequestcorrection/PbRequestCorrectionSpec.groovy @@ -0,0 +1,454 @@ +package org.prebid.server.functional.tests.module.pbrequestcorrection + +import org.prebid.server.functional.model.config.AccountConfig +import org.prebid.server.functional.model.config.AccountHooksConfiguration +import org.prebid.server.functional.model.config.PbRequestCorrectionConfig +import org.prebid.server.functional.model.config.PbsModulesConfig +import org.prebid.server.functional.model.db.Account +import org.prebid.server.functional.model.request.auction.BidRequest +import org.prebid.server.functional.model.request.auction.AppExt +import org.prebid.server.functional.model.request.auction.AppPrebid +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.auction.OperationState +import org.prebid.server.functional.service.PrebidServerService +import org.prebid.server.functional.tests.module.ModuleBaseSpec +import org.prebid.server.functional.util.PBSUtils + +import static org.prebid.server.functional.model.request.auction.DistributionChannel.APP +import static org.prebid.server.functional.model.request.auction.OperationState.YES + +class PbRequestCorrectionSpec extends ModuleBaseSpec { + + private static final String PREBID_MOBILE = "prebid-mobile" + private static final String DEVICE_PREBID_MOBILE_PATTERN = "PrebidMobile/" + private static final String ACCEPTABLE_DEVICE_UA_VERSION_THRESHOLD = PBSUtils.getRandomVersion("0.0", "2.1.5") + private static final String ACCEPTABLE_DEVICE_INSTL_VERSION_THRESHOLD = PBSUtils.getRandomVersion("0.0", "2.2.3") + private static final String ANDROID = "android" + private static final String IOS = "IOS" + + private PrebidServerService pbsServiceWithRequestCorrectionModule = pbsServiceFactory.getService(requestCorrectionSettings) + + def "PBS should remove positive instl from imps for android app when request correction is enabled for account"() { + given: "Android APP bid request with version lover then version threshold" + def prebid = new AppPrebid(source: PBSUtils.getRandomCase(PREBID_MOBILE), version: ACCEPTABLE_DEVICE_INSTL_VERSION_THRESHOLD) + def bidRequest = BidRequest.getDefaultBidRequest(APP).tap { + imp = imps + app.bundle = PBSUtils.getRandomCase(bundle) + app.ext = new AppExt(prebid: prebid) + } + + and: "Account in the DB" + def account = createAccountWithRequestCorrectionConfig(bidRequest, requestCorrectionConfig) + accountDao.save(account) + + when: "PBS processes auction request" + pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Bidder request shouldn't contain imp.instl" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp.instl.every { it == null } + + where: + imps | bundle | requestCorrectionConfig + [Imp.defaultImpression.tap { instl = YES }] | "$ANDROID${PBSUtils.randomString}" | PbRequestCorrectionConfig.defaultConfigWithInterstitial + [Imp.defaultImpression.tap { instl = null }, Imp.defaultImpression.tap { instl = YES }] | "${PBSUtils.randomString}$ANDROID${PBSUtils.randomString}" | PbRequestCorrectionConfig.defaultConfigWithInterstitial + [Imp.defaultImpression.tap { instl = YES }, Imp.defaultImpression.tap { instl = null }] | "${PBSUtils.randomString}$ANDROID${PBSUtils.getRandomNumber()}" | PbRequestCorrectionConfig.defaultConfigWithInterstitial + [Imp.defaultImpression.tap { instl = YES }, Imp.defaultImpression.tap { instl = YES }] | "$ANDROID${PBSUtils.randomString}_$ANDROID${PBSUtils.getRandomNumber()}" | PbRequestCorrectionConfig.defaultConfigWithInterstitial + [Imp.defaultImpression.tap { instl = YES }] | "$ANDROID${PBSUtils.randomString}" | new PbRequestCorrectionConfig(enabled: true, interstitialCorrectionEnabledKebabCase: true) + [Imp.defaultImpression.tap { instl = null }, Imp.defaultImpression.tap { instl = YES }] | "${PBSUtils.randomString}$ANDROID${PBSUtils.randomString}" | new PbRequestCorrectionConfig(enabled: true, interstitialCorrectionEnabledKebabCase: true) + [Imp.defaultImpression.tap { instl = YES }, Imp.defaultImpression.tap { instl = null }] | "${PBSUtils.randomString}$ANDROID${PBSUtils.getRandomNumber()}" | new PbRequestCorrectionConfig(enabled: true, interstitialCorrectionEnabledKebabCase: true) + [Imp.defaultImpression.tap { instl = YES }, Imp.defaultImpression.tap { instl = YES }] | "$ANDROID${PBSUtils.randomString}_$ANDROID${PBSUtils.getRandomNumber()}" | new PbRequestCorrectionConfig(enabled: true, interstitialCorrectionEnabledKebabCase: true) + } + + def "PBS shouldn't remove negative instl from imps for android app when request correction is enabled for account"() { + given: "Android APP bid request with version lover then version threshold" + def prebid = new AppPrebid(source: PBSUtils.getRandomCase(PREBID_MOBILE), version: ACCEPTABLE_DEVICE_INSTL_VERSION_THRESHOLD) + def bidRequest = BidRequest.getDefaultBidRequest(APP).tap { + imp = imps + app.bundle = PBSUtils.getRandomCase(ANDROID) + app.ext = new AppExt(prebid: prebid) + } + + and: "Account in the DB" + def requestCorrectionConfig = PbRequestCorrectionConfig.defaultConfigWithInterstitial + def account = createAccountWithRequestCorrectionConfig(bidRequest, requestCorrectionConfig) + accountDao.save(account) + + when: "PBS processes auction request" + pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Bidder request should contain original imp.instl" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp.instl == bidRequest.imp.instl + + where: + imps << [[Imp.defaultImpression.tap { instl = OperationState.NO }], + [Imp.defaultImpression.tap { instl = null }, Imp.defaultImpression.tap { instl = OperationState.NO }], + [Imp.defaultImpression.tap { instl = OperationState.NO }, Imp.defaultImpression.tap { instl = null }], + [Imp.defaultImpression.tap { instl = OperationState.NO }, Imp.defaultImpression.tap { instl = OperationState.NO }]] + } + + def "PBS shouldn't remove positive instl from imps for not android or not prebid-mobile app when request correction is enabled for account"() { + given: "Android APP bid request with version lover then version threshold" + def prebid = new AppPrebid(source: PBSUtils.getRandomCase(source), version: PBSUtils.getRandomVersion(ACCEPTABLE_DEVICE_INSTL_VERSION_THRESHOLD)) + def bidRequest = BidRequest.getDefaultBidRequest(APP).tap { + imp.first.instl = YES + app.bundle = PBSUtils.getRandomCase(bundle) + app.ext = new AppExt(prebid: prebid) + } + + and: "Account in the DB" + def requestCorrectionConfig = PbRequestCorrectionConfig.defaultConfigWithInterstitial + def account = createAccountWithRequestCorrectionConfig(bidRequest, requestCorrectionConfig) + accountDao.save(account) + + when: "PBS processes auction request" + pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Bidder request should contain original imp.instl" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp.instl == bidRequest.imp.instl + + where: + bundle | source + IOS | PREBID_MOBILE + PBSUtils.randomString | PREBID_MOBILE + ANDROID | PBSUtils.randomString + ANDROID | PBSUtils.randomString + PREBID_MOBILE + ANDROID | PREBID_MOBILE + PBSUtils.randomString + } + + def "PBS shouldn't remove positive instl from imps for app when request correction is enabled for account but some required parameter is empty"() { + given: "Android APP bid request with version lover then version threshold" + def prebid = new AppPrebid(source: source, version: version) + def bidRequest = BidRequest.getDefaultBidRequest(APP).tap { + imp.first.instl = instl + app.bundle = bundle + app.ext = new AppExt(prebid: prebid) + } + + and: "Account in the DB" + def requestCorrectionConfig = PbRequestCorrectionConfig.defaultConfigWithInterstitial + def account = createAccountWithRequestCorrectionConfig(bidRequest, requestCorrectionConfig) + accountDao.save(account) + + when: "PBS processes auction request" + pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Bidder request should contain original imp.instl" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp.instl == bidRequest.imp.instl + + where: + bundle | source | version | instl + null | PREBID_MOBILE | ACCEPTABLE_DEVICE_INSTL_VERSION_THRESHOLD | YES + ANDROID | null | ACCEPTABLE_DEVICE_INSTL_VERSION_THRESHOLD | YES + ANDROID | PREBID_MOBILE | null | YES + ANDROID | PREBID_MOBILE | ACCEPTABLE_DEVICE_INSTL_VERSION_THRESHOLD | null + } + + def "PBS shouldn't remove positive instl from imps for android app when request correction is enabled for account and version is threshold"() { + given: "Android APP bid request with version threshold" + def prebid = new AppPrebid(source: PBSUtils.getRandomCase(PREBID_MOBILE), version: "2.2.3") + def bidRequest = BidRequest.getDefaultBidRequest(APP).tap { + imp.first.instl = YES + app.bundle = PBSUtils.getRandomCase(ANDROID) + app.ext = new AppExt(prebid: prebid) + } + + and: "Account in the DB" + def requestCorrectionConfig = PbRequestCorrectionConfig.defaultConfigWithInterstitial + def account = createAccountWithRequestCorrectionConfig(bidRequest, requestCorrectionConfig) + accountDao.save(account) + + when: "PBS processes auction request" + pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Bidder request should contain original imp.instl" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp.instl == bidRequest.imp.instl + } + + def "PBS shouldn't remove positive instl from imps for android app when request correction is enabled for account and version is higher then threshold"() { + given: "Android APP bid request with version higher then version threshold" + def prebid = new AppPrebid(source: PBSUtils.getRandomCase(PREBID_MOBILE), version: PBSUtils.getRandomVersion("2.2.4")) + def bidRequest = BidRequest.getDefaultBidRequest(APP).tap { + imp.first.instl = YES + app.bundle = PBSUtils.getRandomCase(ANDROID) + app.ext = new AppExt(prebid: prebid) + } + + and: "Account in the DB" + def requestCorrectionConfig = PbRequestCorrectionConfig.defaultConfigWithInterstitial + def account = createAccountWithRequestCorrectionConfig(bidRequest, requestCorrectionConfig) + accountDao.save(account) + + when: "PBS processes auction request" + pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Bidder request should contain original imp.instl" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp.instl == bidRequest.imp.instl + } + + def "PBS shouldn't remove positive instl from imps for android app when request correction is disabled for account"() { + given: "Android APP bid request with version lover then version threshold" + def prebid = new AppPrebid(source: PBSUtils.getRandomCase(PREBID_MOBILE), version: ACCEPTABLE_DEVICE_INSTL_VERSION_THRESHOLD) + def bidRequest = BidRequest.getDefaultBidRequest(APP).tap { + imp.first.instl = YES + app.bundle = PBSUtils.getRandomCase(ANDROID) + app.ext = new AppExt(prebid: prebid) + } + + and: "Account in the DB" + def requestCorrectionConfig = PbRequestCorrectionConfig.getDefaultConfigWithInterstitial(interstitialCorrectionEnabled, enabled) + def account = createAccountWithRequestCorrectionConfig(bidRequest, requestCorrectionConfig) + accountDao.save(account) + + when: "PBS processes auction request" + pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Bidder request should contain original imp.instl" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp.instl == bidRequest.imp.instl + + where: + enabled | interstitialCorrectionEnabled + false | true + null | true + true | false + true | null + null | null + } + + def "PBS shouldn't remove positive instl from imps for android app when request correction is not applied for account"() { + given: "Android APP bid request with version lover then version threshold" + def prebid = new AppPrebid(source: PBSUtils.getRandomCase(PREBID_MOBILE), version: ACCEPTABLE_DEVICE_INSTL_VERSION_THRESHOLD) + def bidRequest = BidRequest.getDefaultBidRequest(APP).tap { + imp.first.instl = YES + app.bundle = PBSUtils.getRandomCase(ANDROID) + app.ext = new AppExt(prebid: prebid) + } + + and: "Account in the DB" + def accountConfig = new AccountConfig(hooks: new AccountHooksConfiguration(modules: new PbsModulesConfig())) + def account = new Account(uuid: bidRequest.accountId, config: accountConfig) + accountDao.save(account) + + when: "PBS processes auction request" + pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Bidder request should contain original imp.instl" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp.instl == bidRequest.imp.instl + } + + def "PBS should remove pattern device.ua when request correction is enabled for account and user agent correction enabled"() { + given: "Android APP bid request with version lover then version threshold" + def prebid = new AppPrebid(source: PREBID_MOBILE, version: ACCEPTABLE_DEVICE_UA_VERSION_THRESHOLD) + def bidRequest = BidRequest.getDefaultBidRequest(APP).tap { + app.ext = new AppExt(prebid: prebid) + device = new Device(ua: deviceUa) + } + + and: "Account in the DB" + def account = createAccountWithRequestCorrectionConfig(bidRequest, requestCorrectionConfig) + accountDao.save(account) + + when: "PBS processes auction request" + pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Bidder request shouldn't contain device.ua" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert !bidderRequest.device.ua + + where: + deviceUa | requestCorrectionConfig + "${DEVICE_PREBID_MOBILE_PATTERN}${PBSUtils.randomNumber}" | PbRequestCorrectionConfig.defaultConfigWithUserAgentCorrection + "${DEVICE_PREBID_MOBILE_PATTERN}${PBSUtils.randomNumber}${PBSUtils.randomString}" | PbRequestCorrectionConfig.defaultConfigWithUserAgentCorrection + "${DEVICE_PREBID_MOBILE_PATTERN}${PBSUtils.randomNumber}" | new PbRequestCorrectionConfig(enabled: true, userAgentCorrectionEnabledKebabCase: true) + "${DEVICE_PREBID_MOBILE_PATTERN}${PBSUtils.randomNumber}${PBSUtils.randomString}" | new PbRequestCorrectionConfig(enabled: true, userAgentCorrectionEnabledKebabCase: true) + } + + def "PBS should remove only pattern device.ua when request correction is enabled for account and user agent correction enabled"() { + given: "Android APP bid request with version lover then version threshold" + def prebid = new AppPrebid(source: PREBID_MOBILE, version: ACCEPTABLE_DEVICE_UA_VERSION_THRESHOLD) + def bidRequest = BidRequest.getDefaultBidRequest(APP).tap { + app.ext = new AppExt(prebid: prebid) + device = new Device(ua: deviceUa) + } + + and: "Account in the DB" + def requestCorrectionConfig = PbRequestCorrectionConfig.defaultConfigWithUserAgentCorrection + def account = createAccountWithRequestCorrectionConfig(bidRequest, requestCorrectionConfig) + accountDao.save(account) + + when: "PBS processes auction request" + pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Bidder request should contain device.ua" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.device.ua.contains(deviceUa.replaceAll("PrebidMobile/[0-9][^ ]*", '').trim()) + + where: + deviceUa << ["${PBSUtils.randomNumber} ${DEVICE_PREBID_MOBILE_PATTERN}${PBSUtils.randomNumber} ${PBSUtils.randomString}", + "${PBSUtils.randomString} ${DEVICE_PREBID_MOBILE_PATTERN}${PBSUtils.randomNumber}${PBSUtils.randomString} ${PBSUtils.randomString}", + "${DEVICE_PREBID_MOBILE_PATTERN}", + "${DEVICE_PREBID_MOBILE_PATTERN}${PBSUtils.randomNumber}", + "${DEVICE_PREBID_MOBILE_PATTERN}${PBSUtils.randomNumber} ${PBSUtils.randomString}" + ] + } + + def "PBS shouldn't remove pattern device.ua when request correction is enabled for account and user agent correction disabled"() { + given: "Android APP bid request with version lover then version threshold" + def deviceUserAgent = "${DEVICE_PREBID_MOBILE_PATTERN}${PBSUtils.randomNumber}" + def prebid = new AppPrebid(source: PBSUtils.getRandomCase(PREBID_MOBILE), version: ACCEPTABLE_DEVICE_UA_VERSION_THRESHOLD) + def bidRequest = BidRequest.getDefaultBidRequest(APP).tap { + app.ext = new AppExt(prebid: prebid) + device = new Device(ua: deviceUserAgent) + } + + and: "Account in the DB" + def requestCorrectionConfig = PbRequestCorrectionConfig.getDefaultConfigWithUserAgentCorrection(userAgentCorrectionEnabled, enabled) + def account = createAccountWithRequestCorrectionConfig(bidRequest, requestCorrectionConfig) + accountDao.save(account) + + when: "PBS processes auction request" + pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Bidder request should contain device.ua" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.device.ua == deviceUserAgent + + where: + enabled | userAgentCorrectionEnabled + false | true + null | true + true | false + true | null + null | null + } + + def "PBS shouldn't remove pattern device.ua when request correction is enabled for account and source not a prebid-mobile"() { + given: "Android APP bid request with version lover then version threshold" + def randomDeviceUa = "${DEVICE_PREBID_MOBILE_PATTERN}${PBSUtils.randomNumber}" + def bidRequest = BidRequest.getDefaultBidRequest(APP).tap { + app.ext = new AppExt(prebid: new AppPrebid(source: source, version: ACCEPTABLE_DEVICE_UA_VERSION_THRESHOLD)) + device = new Device(ua: randomDeviceUa) + } + + and: "Account in the DB" + def requestCorrectionConfig = PbRequestCorrectionConfig.defaultConfigWithUserAgentCorrection + def account = createAccountWithRequestCorrectionConfig(bidRequest, requestCorrectionConfig) + accountDao.save(account) + + when: "PBS processes auction request" + pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Bidder request should contain device.ua" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.device.ua == randomDeviceUa + + where: + source << ["prebid", + "mobile", + PREBID_MOBILE + PBSUtils.randomString, + PBSUtils.randomString + PREBID_MOBILE, + "mobile-prebid", + PBSUtils.randomString] + } + + def "PBS shouldn't remove pattern device.ua when request correction is enabled for account and version biggest that threshold"() { + given: "Android APP bid request with version higher then version threshold" + def randomDeviceUa = "${DEVICE_PREBID_MOBILE_PATTERN}${PBSUtils.randomNumber}" + def bidRequest = BidRequest.getDefaultBidRequest(APP).tap { + app.ext = new AppExt(prebid: new AppPrebid(source: PBSUtils.getRandomCase(PREBID_MOBILE), version: PBSUtils.getRandomVersion("2.1.6"))) + device = new Device(ua: randomDeviceUa) + } + + and: "Account in the DB" + def requestCorrectionConfig = PbRequestCorrectionConfig.defaultConfigWithUserAgentCorrection + def account = createAccountWithRequestCorrectionConfig(bidRequest, requestCorrectionConfig) + accountDao.save(account) + + when: "PBS processes auction request" + pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Bidder request should contain device.ua" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.device.ua == randomDeviceUa + } + + def "PBS shouldn't remove pattern device.ua when request correction is enabled for account and version threshold"() { + given: "Android APP bid request with version threshold" + def randomDeviceUa = "${DEVICE_PREBID_MOBILE_PATTERN}${PBSUtils.randomNumber}" + def bidRequest = BidRequest.getDefaultBidRequest(APP).tap { + app.ext = new AppExt(prebid: new AppPrebid(source: PBSUtils.getRandomCase(PREBID_MOBILE), version: "2.1.6")) + device = new Device(ua: randomDeviceUa) + } + + and: "Account in the DB" + def requestCorrectionConfig = PbRequestCorrectionConfig.defaultConfigWithUserAgentCorrection + def account = createAccountWithRequestCorrectionConfig(bidRequest, requestCorrectionConfig) + accountDao.save(account) + + when: "PBS processes auction request" + pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Bidder request should contain device.ua" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.device.ua == randomDeviceUa + } + + def "PBS shouldn't remove device.ua pattern when request correction is enabled for account and version threshold"() { + given: "Android APP bid request with version higher then version threshold" + def randomDeviceUa = PBSUtils.randomString + def bidRequest = BidRequest.getDefaultBidRequest(APP).tap { + app.ext = new AppExt(prebid: new AppPrebid(source: PBSUtils.getRandomCase(PREBID_MOBILE), version: PBSUtils.getRandomVersion("2.1.6"))) + device = new Device(ua: randomDeviceUa) + } + + and: "Account in the DB" + def requestCorrectionConfig = PbRequestCorrectionConfig.defaultConfigWithUserAgentCorrection + def account = createAccountWithRequestCorrectionConfig(bidRequest, requestCorrectionConfig) + accountDao.save(account) + + when: "PBS processes auction request" + pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Bidder request should contain device.ua" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.device.ua == randomDeviceUa + } + + def "PBS shouldn't remove device.ua pattern from device for android app when request correction is not applied for account"() { + given: "Android APP bid request with version lover then version threshold" + def prebid = new AppPrebid(source: PREBID_MOBILE, version: ACCEPTABLE_DEVICE_UA_VERSION_THRESHOLD) + def deviceUa = "${DEVICE_PREBID_MOBILE_PATTERN}${PBSUtils.randomNumber}" + def bidRequest = BidRequest.getDefaultBidRequest(APP).tap { + app.ext = new AppExt(prebid: prebid) + device = new Device(ua: deviceUa) + } + + and: "Account in the DB" + def accountConfig = new AccountConfig(hooks: new AccountHooksConfiguration(modules: new PbsModulesConfig())) + def account = new Account(uuid: bidRequest.accountId, config: accountConfig) + accountDao.save(account) + + when: "PBS processes auction request" + pbsServiceWithRequestCorrectionModule.sendAuctionRequest(bidRequest) + + then: "Bidder request should contain request device ua" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.device.ua == deviceUa + } + + private static Account createAccountWithRequestCorrectionConfig(BidRequest bidRequest, + PbRequestCorrectionConfig requestCorrectionConfig) { + def pbsModulesConfig = new PbsModulesConfig(pbRequestCorrection: requestCorrectionConfig) + def accountHooksConfig = new AccountHooksConfiguration(modules: pbsModulesConfig) + def accountConfig = new AccountConfig(hooks: accountHooksConfig) + new Account(uuid: bidRequest.accountId, config: accountConfig) + } +} diff --git a/src/test/groovy/org/prebid/server/functional/util/PBSUtils.groovy b/src/test/groovy/org/prebid/server/functional/util/PBSUtils.groovy index 0d72dcfe4c6..96fb86e59f5 100644 --- a/src/test/groovy/org/prebid/server/functional/util/PBSUtils.groovy +++ b/src/test/groovy/org/prebid/server/functional/util/PBSUtils.groovy @@ -128,4 +128,27 @@ class PBSUtils implements ObjectMapperWrapper { throw new IllegalArgumentException("Unknown case type: $caseType") } } + + static String getRandomVersion(String minVersion = "0.0.0", String maxVersion = "99.99.99") { + def minParts = minVersion.split('\\.').collect { it.toInteger() } + def maxParts = maxVersion.split('\\.').collect { it.toInteger() } + def versionParts = [] + + def major = getRandomNumber(minParts[0], maxParts[0]) + versionParts << major + + def minorMin = (major == minParts[0]) ? minParts[1] : 0 + def minorMax = (major == maxParts[0]) ? maxParts[1] : 99 + def minor = getRandomNumber(minorMin, minorMax) + versionParts << minor + + if (minParts.size() > 2 || maxParts.size() > 2) { + def patchMin = (major == minParts[0] && minor == minParts[1]) ? minParts[2] : 0 + def patchMax = (major == maxParts[0] && minor == maxParts[1]) ? maxParts[2] : 99 + def patch = getRandomNumber(patchMin, patchMax) + versionParts << patch + } + def version = versionParts.join('.') + return (version >= minVersion && version <= maxVersion) ? version : getRandomVersion(minVersion, maxVersion) + } }