From 29eb16c18c1e9aac99d3f8a20bb3a27d4624f125 Mon Sep 17 00:00:00 2001 From: markiian Date: Fri, 1 Aug 2025 12:55:52 +0300 Subject: [PATCH 01/16] Add functional tests for get `/vtrack` endpoint --- .../service/PrebidServerService.groovy | 23 ++- .../scaffolding/PrebidCache.groovy | 22 ++- .../functional/tests/BidderParamsSpec.groovy | 4 +- .../server/functional/tests/CacheSpec.groovy | 140 ++++++++++++++---- .../functional/tests/HttpSettingsSpec.groovy | 2 +- .../server/functional/tests/SmokeSpec.groovy | 2 +- 6 files changed, 157 insertions(+), 36 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy index b9c173baa54..503c35a6100 100644 --- a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy +++ b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy @@ -213,7 +213,7 @@ class PrebidServerService implements ObjectMapperWrapper { response.body.asByteArray() } - PrebidCacheResponse sendVtrackRequest(VtrackRequest request, String account) { + PrebidCacheResponse sendPostVtrackRequest(VtrackRequest request, String account) { def response = given(requestSpecification).queryParam("a", account) .body(request) .post(VTRACK_ENDPOINT) @@ -222,6 +222,27 @@ class PrebidServerService implements ObjectMapperWrapper { decode(response.body.asString(), PrebidCacheResponse) } + int sendGetVtrackRequest(String uuid, String cacheHost = null) { + def requestSpecification = given(requestSpecification) + + setUpUuidIfPresent(uuid, requestSpecification) + setUpCacheHostIfPresent(cacheHost, requestSpecification) + + requestSpecification.get(VTRACK_ENDPOINT).statusCode() + } + + private static void setUpUuidIfPresent(String uuid, RequestSpecification requestSpecification) { + if (uuid != null) { + requestSpecification.queryParam("uuid", uuid) + } + } + + private static void setUpCacheHostIfPresent(String cacheHost, RequestSpecification requestSpecification) { + if (cacheHost != null) { + requestSpecification.queryParam("ch", cacheHost) + } + } + StatusResponse sendStatusRequest() { def response = given(requestSpecification).get(STATUS_ENDPOINT) diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy index 224f7c8b228..1a7e45bdf45 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy @@ -13,6 +13,7 @@ import java.util.stream.Stream import static org.mockserver.model.HttpRequest.request import static org.mockserver.model.HttpResponse.response +import static org.mockserver.model.HttpStatusCode.INTERNAL_SERVER_ERROR_500 import static org.mockserver.model.HttpStatusCode.OK_200 import static org.mockserver.model.JsonPathBody.jsonPath @@ -59,7 +60,7 @@ class PrebidCache extends NetworkScaffolding { @Override HttpRequest getRequest() { request().withMethod("POST") - .withPath(CACHE_ENDPOINT) + .withPath(CACHE_ENDPOINT) } @Override @@ -70,6 +71,25 @@ class PrebidCache extends NetworkScaffolding { : HttpResponse.notFoundResponse()} } + void setVtrackResponse(String uuid) { + mockServerClient.when(request() + .withMethod("GET") + .withPath(endpoint) + .withQueryStringParameter("uuid",uuid), Times.unlimited(), TimeToLive.unlimited(), -10) + .respond{request -> request.withPath(endpoint) + ? response().withStatusCode(OK_200.code()) + : HttpResponse.notFoundResponse()} + } + + void setInvalidVtrackResponse(String uuid) { + mockServerClient.when(request() + .withMethod("GET") + .withPath(endpoint) + .withQueryStringParameter("uuid",uuid), Times.unlimited(), TimeToLive.unlimited(), -10) + .respond{response().withStatusCode(INTERNAL_SERVER_ERROR_500.code())} + + } + private static HttpRequest getXmlCacheRequest(String payload) { request().withMethod("POST") .withPath(CACHE_ENDPOINT) diff --git a/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy index 0db60125603..495650fe6e4 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy @@ -140,7 +140,7 @@ class BidderParamsSpec extends BaseSpec { accountDao.save(account) when: "PBS processes vtrack request" - pbsService.sendVtrackRequest(request, accountId.toString()) + pbsService.sendPostVtrackRequest(request, accountId.toString()) then: "vast xml is modified" def prebidCacheRequest = prebidCache.getXmlRecordedRequestsBody(payload) @@ -172,7 +172,7 @@ class BidderParamsSpec extends BaseSpec { accountDao.save(account) when: "PBS processes vtrack request" - pbsService.sendVtrackRequest(request, accountId.toString()) + pbsService.sendPostVtrackRequest(request, accountId.toString()) then: "vast xml is not modified" def prebidCacheRequest = prebidCache.getXmlRecordedRequestsBody(payload) diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy index b745ae53a1f..855dd22cade 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy @@ -1,5 +1,6 @@ package org.prebid.server.functional.tests +import org.mockserver.model.HttpStatusCode import org.prebid.server.functional.model.config.AccountAuctionConfig import org.prebid.server.functional.model.config.AccountCacheConfig import org.prebid.server.functional.model.config.AccountConfig @@ -33,21 +34,25 @@ class CacheSpec extends BaseSpec { private static final String JSON_CREATIVE_SIZE_ACCOUNT_METRIC = "account.%s.prebid_cache.creative_size.json" private static final String XML_CREATIVE_TTL_ACCOUNT_METRIC = "account.%s.prebid_cache.creative_ttl.xml" private static final String JSON_CREATIVE_TTL_ACCOUNT_METRIC = "account.%s.prebid_cache.creative_ttl.json" - private static final String CACHE_REQUEST_OK_ACCOUNT_METRIC = "account.%s.prebid_cache.requests.ok" + private static final String ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC = "account.%s.prebid_cache.vtrack.write.ok" + private static final String PREBID_CACHE_REQUEST_OK_ACCOUNT_METRIC = "account.%s.prebid_cache.requests.ok" private static final String XML_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.creative_size.xml" private static final String JSON_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.creative_size.json" - private static final String CACHE_REQUEST_OK_GLOBAL_METRIC = "prebid_cache.requests.ok" + private static final String PREBID_CACHE_OK_WRITE_OK_METRIC = "prebid_cache.vtrack.write.ok" + private static final String PREBID_CACHE_REQUEST_OK_METRIC = "prebid_cache.requests.ok" + private static final String PREBID_CACHE_VTRACK_READ_OK_METRIC = "prebid_cache.vtrack.read.ok" private static final String CACHE_PATH = "/${PBSUtils.randomString}".toString() private static final String CACHE_HOST = "${PBSUtils.randomString}:${PBSUtils.getRandomNumber(0, 65535)}".toString() private static final String INTERNAL_CACHE_PATH = '/cache' private static final String HTTP_SCHEME = 'http' private static final String HTTPS_SCHEME = 'https' + private static final String CACHE_ENDPOINT = "/cache" def "PBS should update prebid_cache.creative_size.xml metric when xml creative is received"() { given: "Current value of metric prebid_cache.requests.ok" - def initialValue = getCurrentMetricValue(defaultPbsService, CACHE_REQUEST_OK_GLOBAL_METRIC) + def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_OK_WRITE_OK_METRIC) and: "Default VtrackRequest" def accountId = PBSUtils.randomNumber.toString() @@ -58,22 +63,22 @@ class CacheSpec extends BaseSpec { flushMetrics(defaultPbsService) when: "PBS processes vtrack request" - defaultPbsService.sendVtrackRequest(request, accountId) + defaultPbsService.sendPostVtrackRequest(request, accountId) then: "prebid_cache.creative_size.xml metric should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() def creativeSize = creative.bytes.length - assert metrics[CACHE_REQUEST_OK_GLOBAL_METRIC] == initialValue + 1 + assert metrics[PREBID_CACHE_OK_WRITE_OK_METRIC] == initialValue + 1 assert metrics[XML_CREATIVE_SIZE_GLOBAL_METRIC] == creativeSize and: "account..prebid_cache.creative_size.xml should be updated" - assert metrics[CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(accountId)] == 1 + assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC.formatted(accountId)] == 1 assert metrics[XML_CREATIVE_SIZE_ACCOUNT_METRIC.formatted(accountId)] == creativeSize } def "PBS should update prebid_cache.creative_size.json metric when json creative is received"() { given: "Current value of metric prebid_cache.requests.ok" - def initialValue = getCurrentMetricValue(defaultPbsService, CACHE_REQUEST_OK_GLOBAL_METRIC) + def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_REQUEST_OK_METRIC) and: "Default BidRequest with cache, targeting" def bidRequest = BidRequest.defaultBidRequest.tap { @@ -98,11 +103,11 @@ class CacheSpec extends BaseSpec { and: "prebid_cache.creative_size.json metric should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert metrics[CACHE_REQUEST_OK_GLOBAL_METRIC] == initialValue + 1 + assert metrics[PREBID_CACHE_REQUEST_OK_METRIC] == initialValue + 1 assert metrics[JSON_CREATIVE_SIZE_GLOBAL_METRIC] == creativeSize and: "account..prebid_cache.creative_size.json should be update" - assert metrics[CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[PREBID_CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 assert metrics[JSON_CREATIVE_SIZE_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == creativeSize } @@ -205,7 +210,7 @@ class CacheSpec extends BaseSpec { and: "PBS should include metrics for request" def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[JSON_CREATIVE_TTL_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl - assert metrics[CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[PREBID_CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(pbsConfig) @@ -248,7 +253,7 @@ class CacheSpec extends BaseSpec { def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[JSON_CREATIVE_TTL_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == videoHostTtl assert metrics[XML_CREATIVE_TTL_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == videoHostTtl - assert metrics[CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[PREBID_CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(pbsConfig) @@ -285,7 +290,7 @@ class CacheSpec extends BaseSpec { and: "PBS should include metrics for request" def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[JSON_CREATIVE_TTL_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl - assert metrics[CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[PREBID_CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(pbsConfig) @@ -321,7 +326,7 @@ class CacheSpec extends BaseSpec { and: "PBS should include metrics for request" def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[JSON_CREATIVE_TTL_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl - assert metrics[CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[PREBID_CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(pbsConfig) @@ -355,7 +360,7 @@ class CacheSpec extends BaseSpec { and: "PBS should include metrics for request" def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[JSON_CREATIVE_TTL_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl - assert metrics[CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[PREBID_CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(pbsConfig) @@ -472,7 +477,7 @@ class CacheSpec extends BaseSpec { def "PBS should update prebid_cache.creative_size.xml metric and adding tracking xml when xml creative contain #wrapper and impression are valid xml value"() { given: "Current value of metric prebid_cache.requests.ok" - def initialValue = getCurrentMetricValue(defaultPbsService, CACHE_REQUEST_OK_GLOBAL_METRIC) + def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_OK_WRITE_OK_METRIC) and: "Create and save enabled events config in account" def accountId = PBSUtils.randomNumber.toString() @@ -495,7 +500,7 @@ class CacheSpec extends BaseSpec { flushMetrics(defaultPbsService) when: "PBS processes vtrack request" - defaultPbsService.sendVtrackRequest(request, accountId) + defaultPbsService.sendPostVtrackRequest(request, accountId) then: "Vast xml is modified" def prebidCacheRequest = prebidCache.getXmlRecordedRequestsBody(payload) @@ -504,10 +509,10 @@ class CacheSpec extends BaseSpec { and: "prebid_cache.creative_size.xml metric should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert metrics[CACHE_REQUEST_OK_GLOBAL_METRIC] == initialValue + 1 + assert metrics[PREBID_CACHE_OK_WRITE_OK_METRIC] == initialValue + 1 and: "account..prebid_cache.creative_size.xml should be updated" - assert metrics[CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(accountId) as String] == 1 + assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC.formatted(accountId) as String] == 1 where: wrapper | impression @@ -607,7 +612,7 @@ class CacheSpec extends BaseSpec { assert prebidCache.getRequestCount(bidRequest.imp[0].id) == 1 and: "Bid response targeting should contain value" - verifyAll (bidResponse?.seatbid[0]?.bid[0]?.ext?.prebid?.targeting as Map) { + verifyAll(bidResponse?.seatbid[0]?.bid[0]?.ext?.prebid?.targeting as Map) { it.get("hb_cache_id") it.get("hb_cache_id_generic") it.get("hb_cache_path") == CACHE_PATH @@ -643,7 +648,7 @@ class CacheSpec extends BaseSpec { assert prebidCache.getRequestCount(bidRequest.imp[0].id) == 1 and: "Bid response targeting should contain value" - verifyAll (bidResponse.seatbid[0].bid[0].ext.prebid.targeting) { + verifyAll(bidResponse.seatbid[0].bid[0].ext.prebid.targeting) { it.get("hb_cache_id") it.get("hb_cache_id_generic") it.get("hb_cache_path") == INTERNAL_CACHE_PATH @@ -662,7 +667,7 @@ class CacheSpec extends BaseSpec { def "PBS should cache bids and add targeting values when account cache config #accountAuctionConfig"() { given: "Current value of metric prebid_cache.requests.ok" - def initialValue = getCurrentMetricValue(defaultPbsService, CACHE_REQUEST_OK_GLOBAL_METRIC) + def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_REQUEST_OK_METRIC) and: "Default BidRequest with cache, targeting" def bidRequest = BidRequest.getDefaultVideoRequest().tap { @@ -696,8 +701,8 @@ class CacheSpec extends BaseSpec { and: "Metrics should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert metrics[CACHE_REQUEST_OK_GLOBAL_METRIC] == initialValue + 1 - assert metrics[CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[PREBID_CACHE_REQUEST_OK_METRIC] == initialValue + 1 + assert metrics[PREBID_CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 where: accountAuctionConfig << [ @@ -710,7 +715,7 @@ class CacheSpec extends BaseSpec { def "PBS shouldn't cache bids and add targeting values when account cache config disabled"() { given: "Current value of metric prebid_cache.requests.ok" - def initialValue = getCurrentMetricValue(defaultPbsService, CACHE_REQUEST_OK_GLOBAL_METRIC) + def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_OK_WRITE_OK_METRIC) and: "Default BidRequest with cache, targeting" def bidRequest = BidRequest.getDefaultVideoRequest().tap { @@ -745,13 +750,13 @@ class CacheSpec extends BaseSpec { and: "Metrics shouldn't be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert metrics[CACHE_REQUEST_OK_GLOBAL_METRIC] == initialValue - assert !metrics[CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] + assert metrics[PREBID_CACHE_OK_WRITE_OK_METRIC] == initialValue + assert !metrics[ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC.formatted(bidRequest.accountId)] } def "PBS should update prebid_cache.creative_size.xml metric when account cache config #enabledCacheConcfig"() { given: "Current value of metric prebid_cache.requests.ok" - def okInitialValue = getCurrentMetricValue(defaultPbsService, CACHE_REQUEST_OK_GLOBAL_METRIC) + def okInitialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_OK_WRITE_OK_METRIC) and: "Default VtrackRequest" def accountId = PBSUtils.randomNumber.toString() @@ -771,18 +776,93 @@ class CacheSpec extends BaseSpec { flushMetrics(defaultPbsService) when: "PBS processes vtrack request" - defaultPbsService.sendVtrackRequest(request, accountId) + defaultPbsService.sendPostVtrackRequest(request, accountId) then: "prebid_cache.creative_size.xml metric should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() def creativeSize = creative.bytes.length - assert metrics[CACHE_REQUEST_OK_GLOBAL_METRIC] == okInitialValue + 1 + assert metrics[PREBID_CACHE_OK_WRITE_OK_METRIC] == okInitialValue + 1 and: "account..prebid_cache.creative_size.xml should be updated" - assert metrics[CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(accountId)] == 1 + assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC.formatted(accountId)] == 1 assert metrics[XML_CREATIVE_SIZE_ACCOUNT_METRIC.formatted(accountId)] == creativeSize where: enabledCacheConcfig << [null, false, true] } + + def "PBS should return 400 status code when get vtrack request without uuid"() { + given: "PBS processes get vtrack request" + def response = defaultPbsService.sendGetVtrackRequest(null) + + expect: "Response body should contain error status code" + assert response == HttpStatusCode.BAD_REQUEST_400.code() + + cleanup: + prebidCache.reset(CACHE_ENDPOINT) + } + + def "PBS should return 200 status code when get vtrack request contain uuid"() { + given: "Random uuid" + def uuid = UUID.randomUUID().toString() + + and: "Clean up and set up successful response" + prebidCache.setVtrackResponse(uuid) + + when: "PBS processes get vtrack request" + def response = defaultPbsService.sendGetVtrackRequest(uuid) + + then: "Response body should contain error status code" + assert response == HttpStatusCode.OK_200.code() + + and: "Metrics should contain" + def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() + assert metricsRequest[PREBID_CACHE_VTRACK_READ_OK_METRIC] == 1 + + cleanup: + prebidCache.reset(CACHE_ENDPOINT) + } + + def "PBS should return status code that came from pbc when get vtrack request and response from pbc invalid"() { + given: "Random uuid" + def uuid = UUID.randomUUID().toString() + + and: "Set up invalid response" + prebidCache.setInvalidVtrackResponse(uuid) + + when: "PBS processes get vtrack request" + def response = defaultPbsService.sendGetVtrackRequest(uuid) + + then: "Response body should contain error status code" + assert response == HttpStatusCode.INTERNAL_SERVER_ERROR_500.code() + + and: "Metrics should contain" + def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() + assert metricsRequest["prebid_cache.vtrack.read.err"] == 1 + + cleanup: "Clean cache mock response" + prebidCache.reset(CACHE_ENDPOINT) + } + + def "PBS should return 500 status code when get vtrack request with uuid and response from pbc invalid"() { + given: "Current value of metric prebid_cache.requests.ok" + def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_VTRACK_READ_OK_METRIC) + + and: "Random uuid and cache host" + def uuid = UUID.randomUUID().toString() + def cacheHost = PBSUtils.randomString + + and: "Clean up and set up successful response" + prebidCache.setVtrackResponse(uuid) + + when: "PBS processes get vtrack request" + def response = defaultPbsService.sendGetVtrackRequest(uuid, cacheHost) + + then: "Response body should contain status code ok" + assert response == HttpStatusCode.OK_200.code() + + and: "Metrics should contain" + def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() + assert metricsRequest[PREBID_CACHE_VTRACK_READ_OK_METRIC] == initialValue + 1 + } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/HttpSettingsSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/HttpSettingsSpec.groovy index 2c6d1556a81..bd05266437c 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/HttpSettingsSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/HttpSettingsSpec.groovy @@ -148,7 +148,7 @@ class HttpSettingsSpec extends BaseSpec { httpSettings.setResponse(accountId, httpSettingsResponse) when: "PBS processes vtrack request" - def response = prebidServerService.sendVtrackRequest(request, accountId) + def response = prebidServerService.sendPostVtrackRequest(request, accountId) then: "Response should contain uid" assert response.responses[0]?.uuid diff --git a/src/test/groovy/org/prebid/server/functional/tests/SmokeSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/SmokeSpec.groovy index c7cceae6d01..daa27b260fa 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/SmokeSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/SmokeSpec.groovy @@ -98,7 +98,7 @@ class SmokeSpec extends BaseSpec { def accountId = PBSUtils.randomNumber.toString() when: "PBS processes vtrack request" - def response = defaultPbsService.sendVtrackRequest(request, accountId) + def response = defaultPbsService.sendPostVtrackRequest(request, accountId) then: "Response should contain uid" assert response.responses[0]?.uuid From 8a51f8c3dceaf2d879746fb6080089e9713e9c0d Mon Sep 17 00:00:00 2001 From: markiian Date: Fri, 1 Aug 2025 12:59:10 +0300 Subject: [PATCH 02/16] Update naming --- .../server/functional/tests/CacheSpec.groovy | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy index 855dd22cade..8e420484949 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy @@ -35,7 +35,7 @@ class CacheSpec extends BaseSpec { private static final String XML_CREATIVE_TTL_ACCOUNT_METRIC = "account.%s.prebid_cache.creative_ttl.xml" private static final String JSON_CREATIVE_TTL_ACCOUNT_METRIC = "account.%s.prebid_cache.creative_ttl.json" private static final String ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC = "account.%s.prebid_cache.vtrack.write.ok" - private static final String PREBID_CACHE_REQUEST_OK_ACCOUNT_METRIC = "account.%s.prebid_cache.requests.ok" + private static final String ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC = "account.%s.prebid_cache.requests.ok" private static final String XML_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.creative_size.xml" private static final String JSON_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.creative_size.json" @@ -107,7 +107,7 @@ class CacheSpec extends BaseSpec { assert metrics[JSON_CREATIVE_SIZE_GLOBAL_METRIC] == creativeSize and: "account..prebid_cache.creative_size.json should be update" - assert metrics[PREBID_CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 assert metrics[JSON_CREATIVE_SIZE_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == creativeSize } @@ -210,7 +210,7 @@ class CacheSpec extends BaseSpec { and: "PBS should include metrics for request" def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[JSON_CREATIVE_TTL_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl - assert metrics[PREBID_CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(pbsConfig) @@ -253,7 +253,7 @@ class CacheSpec extends BaseSpec { def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[JSON_CREATIVE_TTL_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == videoHostTtl assert metrics[XML_CREATIVE_TTL_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == videoHostTtl - assert metrics[PREBID_CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(pbsConfig) @@ -290,7 +290,7 @@ class CacheSpec extends BaseSpec { and: "PBS should include metrics for request" def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[JSON_CREATIVE_TTL_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl - assert metrics[PREBID_CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(pbsConfig) @@ -326,7 +326,7 @@ class CacheSpec extends BaseSpec { and: "PBS should include metrics for request" def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[JSON_CREATIVE_TTL_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl - assert metrics[PREBID_CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(pbsConfig) @@ -360,7 +360,7 @@ class CacheSpec extends BaseSpec { and: "PBS should include metrics for request" def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[JSON_CREATIVE_TTL_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl - assert metrics[PREBID_CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(pbsConfig) @@ -702,7 +702,7 @@ class CacheSpec extends BaseSpec { and: "Metrics should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() assert metrics[PREBID_CACHE_REQUEST_OK_METRIC] == initialValue + 1 - assert metrics[PREBID_CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 where: accountAuctionConfig << [ From 987c1852d057bf6563a0f07e3c5bc2c330091979 Mon Sep 17 00:00:00 2001 From: markiian Date: Fri, 1 Aug 2025 13:01:36 +0300 Subject: [PATCH 03/16] Update naming --- .../server/functional/tests/CacheSpec.groovy | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy index 8e420484949..a6b9ba62fb9 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy @@ -39,9 +39,9 @@ class CacheSpec extends BaseSpec { private static final String XML_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.creative_size.xml" private static final String JSON_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.creative_size.json" - private static final String PREBID_CACHE_OK_WRITE_OK_METRIC = "prebid_cache.vtrack.write.ok" - private static final String PREBID_CACHE_REQUEST_OK_METRIC = "prebid_cache.requests.ok" + private static final String PREBID_CACHE_VTRACK_WRITE_OK_METRIC = "prebid_cache.vtrack.write.ok" private static final String PREBID_CACHE_VTRACK_READ_OK_METRIC = "prebid_cache.vtrack.read.ok" + private static final String PREBID_CACHE_REQUEST_OK_METRIC = "prebid_cache.requests.ok" private static final String CACHE_PATH = "/${PBSUtils.randomString}".toString() private static final String CACHE_HOST = "${PBSUtils.randomString}:${PBSUtils.getRandomNumber(0, 65535)}".toString() @@ -52,7 +52,7 @@ class CacheSpec extends BaseSpec { def "PBS should update prebid_cache.creative_size.xml metric when xml creative is received"() { given: "Current value of metric prebid_cache.requests.ok" - def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_OK_WRITE_OK_METRIC) + def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_VTRACK_WRITE_OK_METRIC) and: "Default VtrackRequest" def accountId = PBSUtils.randomNumber.toString() @@ -68,7 +68,7 @@ class CacheSpec extends BaseSpec { then: "prebid_cache.creative_size.xml metric should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() def creativeSize = creative.bytes.length - assert metrics[PREBID_CACHE_OK_WRITE_OK_METRIC] == initialValue + 1 + assert metrics[PREBID_CACHE_VTRACK_WRITE_OK_METRIC] == initialValue + 1 assert metrics[XML_CREATIVE_SIZE_GLOBAL_METRIC] == creativeSize and: "account..prebid_cache.creative_size.xml should be updated" @@ -477,7 +477,7 @@ class CacheSpec extends BaseSpec { def "PBS should update prebid_cache.creative_size.xml metric and adding tracking xml when xml creative contain #wrapper and impression are valid xml value"() { given: "Current value of metric prebid_cache.requests.ok" - def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_OK_WRITE_OK_METRIC) + def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_VTRACK_WRITE_OK_METRIC) and: "Create and save enabled events config in account" def accountId = PBSUtils.randomNumber.toString() @@ -509,7 +509,7 @@ class CacheSpec extends BaseSpec { and: "prebid_cache.creative_size.xml metric should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert metrics[PREBID_CACHE_OK_WRITE_OK_METRIC] == initialValue + 1 + assert metrics[PREBID_CACHE_VTRACK_WRITE_OK_METRIC] == initialValue + 1 and: "account..prebid_cache.creative_size.xml should be updated" assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC.formatted(accountId) as String] == 1 @@ -715,7 +715,7 @@ class CacheSpec extends BaseSpec { def "PBS shouldn't cache bids and add targeting values when account cache config disabled"() { given: "Current value of metric prebid_cache.requests.ok" - def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_OK_WRITE_OK_METRIC) + def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_VTRACK_WRITE_OK_METRIC) and: "Default BidRequest with cache, targeting" def bidRequest = BidRequest.getDefaultVideoRequest().tap { @@ -750,13 +750,13 @@ class CacheSpec extends BaseSpec { and: "Metrics shouldn't be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert metrics[PREBID_CACHE_OK_WRITE_OK_METRIC] == initialValue + assert metrics[PREBID_CACHE_VTRACK_WRITE_OK_METRIC] == initialValue assert !metrics[ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC.formatted(bidRequest.accountId)] } def "PBS should update prebid_cache.creative_size.xml metric when account cache config #enabledCacheConcfig"() { given: "Current value of metric prebid_cache.requests.ok" - def okInitialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_OK_WRITE_OK_METRIC) + def okInitialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_VTRACK_WRITE_OK_METRIC) and: "Default VtrackRequest" def accountId = PBSUtils.randomNumber.toString() @@ -781,7 +781,7 @@ class CacheSpec extends BaseSpec { then: "prebid_cache.creative_size.xml metric should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() def creativeSize = creative.bytes.length - assert metrics[PREBID_CACHE_OK_WRITE_OK_METRIC] == okInitialValue + 1 + assert metrics[PREBID_CACHE_VTRACK_WRITE_OK_METRIC] == okInitialValue + 1 and: "account..prebid_cache.creative_size.xml should be updated" assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC.formatted(accountId)] == 1 From c8bf7039a968b646703e153a2215432106f701c6 Mon Sep 17 00:00:00 2001 From: markiian Date: Fri, 1 Aug 2025 13:17:09 +0300 Subject: [PATCH 04/16] Update test description --- .../server/functional/tests/CacheSpec.groovy | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy index a6b9ba62fb9..b2a0173c353 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy @@ -15,6 +15,7 @@ import org.prebid.server.functional.model.request.vtrack.xml.Vast import org.prebid.server.functional.model.response.auction.Adm import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.util.PBSUtils +import spock.lang.IgnoreRest import static org.prebid.server.functional.model.response.auction.ErrorType.CACHE import static org.prebid.server.functional.model.AccountStatus.ACTIVE @@ -41,6 +42,7 @@ class CacheSpec extends BaseSpec { private static final String JSON_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.creative_size.json" private static final String PREBID_CACHE_VTRACK_WRITE_OK_METRIC = "prebid_cache.vtrack.write.ok" private static final String PREBID_CACHE_VTRACK_READ_OK_METRIC = "prebid_cache.vtrack.read.ok" + private static final String PREBID_CACHE_VTRACK_READ_ERROR_METRIC = "prebid_cache.vtrack.read.err" private static final String PREBID_CACHE_REQUEST_OK_METRIC = "prebid_cache.requests.ok" private static final String CACHE_PATH = "/${PBSUtils.randomString}".toString() @@ -812,10 +814,10 @@ class CacheSpec extends BaseSpec { when: "PBS processes get vtrack request" def response = defaultPbsService.sendGetVtrackRequest(uuid) - then: "Response body should contain error status code" + then: "Response body should contain 200 status code" assert response == HttpStatusCode.OK_200.code() - and: "Metrics should contain" + and: "Metrics should contain ok metric" def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() assert metricsRequest[PREBID_CACHE_VTRACK_READ_OK_METRIC] == 1 @@ -836,16 +838,16 @@ class CacheSpec extends BaseSpec { then: "Response body should contain error status code" assert response == HttpStatusCode.INTERNAL_SERVER_ERROR_500.code() - and: "Metrics should contain" + and: "Metrics should contain error metric" def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() - assert metricsRequest["prebid_cache.vtrack.read.err"] == 1 + assert metricsRequest[PREBID_CACHE_VTRACK_READ_ERROR_METRIC] == 1 cleanup: "Clean cache mock response" prebidCache.reset(CACHE_ENDPOINT) } - def "PBS should return 500 status code when get vtrack request with uuid and response from pbc invalid"() { - given: "Current value of metric prebid_cache.requests.ok" + def "PBS should return 200 status code when get vtrack request with uuid and ch"() { + given: "Current value of metric prebid_cache.vtrack.read.ok" def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_VTRACK_READ_OK_METRIC) and: "Random uuid and cache host" @@ -858,11 +860,14 @@ class CacheSpec extends BaseSpec { when: "PBS processes get vtrack request" def response = defaultPbsService.sendGetVtrackRequest(uuid, cacheHost) - then: "Response body should contain status code ok" + then: "Response body should contain 200 status code" assert response == HttpStatusCode.OK_200.code() - and: "Metrics should contain" + and: "Metrics should contain ok metrics" def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() assert metricsRequest[PREBID_CACHE_VTRACK_READ_OK_METRIC] == initialValue + 1 + + cleanup: "Clean cache mock response" + prebidCache.reset(CACHE_ENDPOINT) } } From ff51ee39a9701db35c839f46a984e07eaca330bb Mon Sep 17 00:00:00 2001 From: markiian Date: Thu, 9 Oct 2025 11:13:39 +0300 Subject: [PATCH 05/16] Add more coverage for /get vtrack endpoint --- .../scaffolding/PrebidCache.groovy | 37 +++++++----- .../server/functional/tests/CacheSpec.groovy | 59 +++++++++++++++++-- 2 files changed, 76 insertions(+), 20 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy index 1a7e45bdf45..ad0636c923f 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy @@ -44,8 +44,8 @@ class PrebidCache extends NetworkScaffolding { @Override protected HttpRequest getRequest(String impId) { request().withMethod("POST") - .withPath(CACHE_ENDPOINT) - .withBody(jsonPath("\$.puts[?(@.value.impid == '$impId')]")) + .withPath(CACHE_ENDPOINT) + .withBody(jsonPath("\$.puts[?(@.value.impid == '$impId')]")) } List getRecordedRequests(String impId) { @@ -60,40 +60,49 @@ class PrebidCache extends NetworkScaffolding { @Override HttpRequest getRequest() { request().withMethod("POST") - .withPath(CACHE_ENDPOINT) + .withPath(CACHE_ENDPOINT) } @Override void setResponse() { mockServerClient.when(request().withPath(endpoint), Times.unlimited(), TimeToLive.unlimited(), -10) - .respond{request -> request.withPath(endpoint) - ? response().withStatusCode(OK_200.code()).withBody(getBodyByRequest(request)) - : HttpResponse.notFoundResponse()} + .respond { request -> + request.withPath(endpoint) + ? response().withStatusCode(OK_200.code()).withBody(getBodyByRequest(request)) + : HttpResponse.notFoundResponse() + } + } + + void setInvalidPostResponse() { + mockServerClient.when(request().withPath(endpoint), Times.unlimited(), TimeToLive.unlimited(), -10) + .respond { response().withStatusCode(INTERNAL_SERVER_ERROR_500.code()) } } void setVtrackResponse(String uuid) { mockServerClient.when(request() .withMethod("GET") .withPath(endpoint) - .withQueryStringParameter("uuid",uuid), Times.unlimited(), TimeToLive.unlimited(), -10) - .respond{request -> request.withPath(endpoint) - ? response().withStatusCode(OK_200.code()) - : HttpResponse.notFoundResponse()} + .withQueryStringParameter("uuid", uuid), Times.unlimited(), TimeToLive.unlimited(), -10) + .respond { request -> + request.withPath(endpoint) + ? response().withStatusCode(OK_200.code()) + : HttpResponse.notFoundResponse() + } } void setInvalidVtrackResponse(String uuid) { mockServerClient.when(request() .withMethod("GET") .withPath(endpoint) - .withQueryStringParameter("uuid",uuid), Times.unlimited(), TimeToLive.unlimited(), -10) - .respond{response().withStatusCode(INTERNAL_SERVER_ERROR_500.code())} + .withQueryStringParameter("uuid", uuid), Times.unlimited(), TimeToLive.unlimited(), -10) + .respond { response().withStatusCode(INTERNAL_SERVER_ERROR_500.code()) } } private static HttpRequest getXmlCacheRequest(String payload) { request().withMethod("POST") - .withPath(CACHE_ENDPOINT) - .withBody(jsonPath("\$.puts[?(@.value =~/^.*$payload.*\$/)]")) + .withPath(CACHE_ENDPOINT) + .withBody(jsonPath("\$.puts[?(@.value =~/^.*$payload.*\$/)]")) } private String getBodyByRequest(HttpRequest request) { diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy index b2a0173c353..e9a9bc58deb 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy @@ -14,6 +14,7 @@ import org.prebid.server.functional.model.request.vtrack.VtrackRequest import org.prebid.server.functional.model.request.vtrack.xml.Vast import org.prebid.server.functional.model.response.auction.Adm import org.prebid.server.functional.model.response.auction.BidResponse +import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.util.PBSUtils import spock.lang.IgnoreRest @@ -31,16 +32,18 @@ class CacheSpec extends BaseSpec { private static final Integer DEFAULT_UUID_LENGTH = 36 private static final Integer TARGETING_PARAM_NAME_MAX_LENGTH = 20 - private static final String XML_CREATIVE_SIZE_ACCOUNT_METRIC = "account.%s.prebid_cache.creative_size.xml" + private static final String XML_CREATIVE_SIZE_ACCOUNT_METRIC = "account.%s.prebid_cache.vtrack.creative_size.xml" private static final String JSON_CREATIVE_SIZE_ACCOUNT_METRIC = "account.%s.prebid_cache.creative_size.json" private static final String XML_CREATIVE_TTL_ACCOUNT_METRIC = "account.%s.prebid_cache.creative_ttl.xml" private static final String JSON_CREATIVE_TTL_ACCOUNT_METRIC = "account.%s.prebid_cache.creative_ttl.json" private static final String ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC = "account.%s.prebid_cache.vtrack.write.ok" + private static final String ACCOUNT_PREBID_CACHE_VTRACK_WRITE_ERR_METRIC = "account.%s.prebid_cache.vtrack.write.err" private static final String ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC = "account.%s.prebid_cache.requests.ok" - private static final String XML_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.creative_size.xml" + private static final String PREBID_CACHE_XML_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.vtrack.creative_size.xml" private static final String JSON_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.creative_size.json" private static final String PREBID_CACHE_VTRACK_WRITE_OK_METRIC = "prebid_cache.vtrack.write.ok" + private static final String PREBID_CACHE_VTRACK_WRITE_ERROR_METRIC = "prebid_cache.vtrack.write.err" private static final String PREBID_CACHE_VTRACK_READ_OK_METRIC = "prebid_cache.vtrack.read.ok" private static final String PREBID_CACHE_VTRACK_READ_ERROR_METRIC = "prebid_cache.vtrack.read.err" private static final String PREBID_CACHE_REQUEST_OK_METRIC = "prebid_cache.requests.ok" @@ -67,11 +70,11 @@ class CacheSpec extends BaseSpec { when: "PBS processes vtrack request" defaultPbsService.sendPostVtrackRequest(request, accountId) - then: "prebid_cache.creative_size.xml metric should be updated" + then: "prebid_cache.vtrack.creative_size.xml metric should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() def creativeSize = creative.bytes.length assert metrics[PREBID_CACHE_VTRACK_WRITE_OK_METRIC] == initialValue + 1 - assert metrics[XML_CREATIVE_SIZE_GLOBAL_METRIC] == creativeSize + assert metrics[PREBID_CACHE_XML_CREATIVE_SIZE_GLOBAL_METRIC] == creativeSize and: "account..prebid_cache.creative_size.xml should be updated" assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC.formatted(accountId)] == 1 @@ -793,6 +796,50 @@ class CacheSpec extends BaseSpec { enabledCacheConcfig << [null, false, true] } + def "PBS should failed cache and update prebid_cache.vtrack.write.err metric andwhen cache service respond with invalid status code"() { + given: "Current value of metric prebid_cache.requests.ok" + def okInitialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_VTRACK_WRITE_ERROR_METRIC) + + and: "Default VtrackRequest" + def accountId = PBSUtils.randomNumber.toString() + def creative = encodeXml(Vast.getDefaultVastModel(PBSUtils.randomString)) + def request = VtrackRequest.getDefaultVtrackRequest(creative) + + and: "Create and save enabled events config in account" + def account = new Account().tap { + it.uuid = accountId + it.config = new AccountConfig().tap { + it.auction = new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: true)) + } + } + accountDao.save(account) + + and: "Flush metrics" + flushMetrics(defaultPbsService) + + and: "Resent cache and set up invalid response" + prebidCache.reset() + prebidCache.setInvalidPostResponse() + + when: "PBS processes vtrack request" + defaultPbsService.sendPostVtrackRequest(request, accountId) + + then: "PBS throws an exception" + def exception = thrown(PrebidServerException) + assert exception.statusCode == 500 + assert exception.responseBody.contains("Error occurred while sending request to cache: HTTP status code 500") + + then: "prebid_cache.vtrack.write.err metric should be updated" + def metrics = defaultPbsService.sendCollectedMetricsRequest() + assert metrics[PREBID_CACHE_VTRACK_WRITE_ERROR_METRIC] == okInitialValue + 1 + + and: "account..prebid_cache.vtrack.write.err should be updated" + assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_WRITE_ERR_METRIC.formatted(accountId)] == 1 + + cleanup: + prebidCache.reset() + } + def "PBS should return 400 status code when get vtrack request without uuid"() { given: "PBS processes get vtrack request" def response = defaultPbsService.sendGetVtrackRequest(null) @@ -808,7 +855,7 @@ class CacheSpec extends BaseSpec { given: "Random uuid" def uuid = UUID.randomUUID().toString() - and: "Clean up and set up successful response" + and: "Cache set up successful response" prebidCache.setVtrackResponse(uuid) when: "PBS processes get vtrack request" @@ -829,7 +876,7 @@ class CacheSpec extends BaseSpec { given: "Random uuid" def uuid = UUID.randomUUID().toString() - and: "Set up invalid response" + and: "Cache set up invalid response" prebidCache.setInvalidVtrackResponse(uuid) when: "PBS processes get vtrack request" From 10d53dbc304c0864fdfdc68ef59c1c05aac3a26f Mon Sep 17 00:00:00 2001 From: markiian Date: Fri, 10 Oct 2025 01:14:23 +0300 Subject: [PATCH 06/16] Add more coverage metrics for /get vtrack endpoint --- .../server/functional/tests/CacheSpec.groovy | 102 +++++++++++++----- 1 file changed, 77 insertions(+), 25 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy index e9a9bc58deb..9827b5bec23 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy @@ -16,7 +16,6 @@ import org.prebid.server.functional.model.response.auction.Adm import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.util.PBSUtils -import spock.lang.IgnoreRest import static org.prebid.server.functional.model.response.auction.ErrorType.CACHE import static org.prebid.server.functional.model.AccountStatus.ACTIVE @@ -32,21 +31,31 @@ class CacheSpec extends BaseSpec { private static final Integer DEFAULT_UUID_LENGTH = 36 private static final Integer TARGETING_PARAM_NAME_MAX_LENGTH = 20 - private static final String XML_CREATIVE_SIZE_ACCOUNT_METRIC = "account.%s.prebid_cache.vtrack.creative_size.xml" - private static final String JSON_CREATIVE_SIZE_ACCOUNT_METRIC = "account.%s.prebid_cache.creative_size.json" - private static final String XML_CREATIVE_TTL_ACCOUNT_METRIC = "account.%s.prebid_cache.creative_ttl.xml" - private static final String JSON_CREATIVE_TTL_ACCOUNT_METRIC = "account.%s.prebid_cache.creative_ttl.json" + private static final String ACCOUNT_PREBID_CACHE_VTRACK_XML_CREATIVE_SIZE_METRIC = "account.%s.prebid_cache.vtrack.creative_size.xml" + private static final String ACCOUNT_JSON_CREATIVE_SIZE_METRIC = "account.%s.prebid_cache.creative_size.json" + private static final String ACCOUNT_XML_CREATIVE_SIZE_METRIC = "account.%s.prebid_cache.creative_size.xml" + private static final String ACCOUNT_XML_CREATIVE_TTL_METRIC = "account.%s.prebid_cache.creative_ttl.xml" + private static final String ACCOUNT_JSON_CREATIVE_TTL_METRIC = "account.%s.prebid_cache.creative_ttl.json" + + private static final String ACCOUNT_PREBID_CACHE_VTRACK_CREATIVE_TTL_XML_METRIC = "account.%s.prebid_cache.vtrack.creative_ttl.xml" private static final String ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC = "account.%s.prebid_cache.vtrack.write.ok" private static final String ACCOUNT_PREBID_CACHE_VTRACK_WRITE_ERR_METRIC = "account.%s.prebid_cache.vtrack.write.err" private static final String ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC = "account.%s.prebid_cache.requests.ok" - private static final String PREBID_CACHE_XML_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.vtrack.creative_size.xml" - private static final String JSON_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.creative_size.json" + private static final String PREBID_CACHE_REQUEST_OK_METRIC = "prebid_cache.requests.ok" + + private static final String PREBID_CACHE_JSON_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.creative_size.json" + private static final String PREBID_CACHE_XML_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.creative_size.xml" + private static final String PREBID_CACHE_XML_CREATIVE_TTL_METRIC = "prebid_cache.creative_ttl.xml" + private static final String PREBID_CACHE_JSON_CREATIVE_TTL_METRIC = "prebid_cache.creative_ttl.json" + + private static final String PREBID_CACHE_VTRACK_XML_CREATIVE_SIZE_METRIC = "prebid_cache.vtrack.creative_size.xml" + private static final String PREBID_CACHE_VTRACK_XML_CREATIVE_TTL_METRIC = "prebid_cache.vtrack.creative_ttl.xml" + private static final String PREBID_CACHE_VTRACK_WRITE_OK_METRIC = "prebid_cache.vtrack.write.ok" private static final String PREBID_CACHE_VTRACK_WRITE_ERROR_METRIC = "prebid_cache.vtrack.write.err" private static final String PREBID_CACHE_VTRACK_READ_OK_METRIC = "prebid_cache.vtrack.read.ok" private static final String PREBID_CACHE_VTRACK_READ_ERROR_METRIC = "prebid_cache.vtrack.read.err" - private static final String PREBID_CACHE_REQUEST_OK_METRIC = "prebid_cache.requests.ok" private static final String CACHE_PATH = "/${PBSUtils.randomString}".toString() private static final String CACHE_HOST = "${PBSUtils.randomString}:${PBSUtils.getRandomNumber(0, 65535)}".toString() @@ -74,11 +83,11 @@ class CacheSpec extends BaseSpec { def metrics = defaultPbsService.sendCollectedMetricsRequest() def creativeSize = creative.bytes.length assert metrics[PREBID_CACHE_VTRACK_WRITE_OK_METRIC] == initialValue + 1 - assert metrics[PREBID_CACHE_XML_CREATIVE_SIZE_GLOBAL_METRIC] == creativeSize + assert metrics[PREBID_CACHE_VTRACK_XML_CREATIVE_SIZE_METRIC] == creativeSize and: "account..prebid_cache.creative_size.xml should be updated" assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC.formatted(accountId)] == 1 - assert metrics[XML_CREATIVE_SIZE_ACCOUNT_METRIC.formatted(accountId)] == creativeSize + assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_XML_CREATIVE_SIZE_METRIC.formatted(accountId)] == creativeSize } def "PBS should update prebid_cache.creative_size.json metric when json creative is received"() { @@ -109,11 +118,47 @@ class CacheSpec extends BaseSpec { and: "prebid_cache.creative_size.json metric should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() assert metrics[PREBID_CACHE_REQUEST_OK_METRIC] == initialValue + 1 - assert metrics[JSON_CREATIVE_SIZE_GLOBAL_METRIC] == creativeSize + assert metrics[PREBID_CACHE_JSON_CREATIVE_SIZE_GLOBAL_METRIC] == creativeSize and: "account..prebid_cache.creative_size.json should be update" assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 - assert metrics[JSON_CREATIVE_SIZE_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == creativeSize + assert metrics[ACCOUNT_JSON_CREATIVE_SIZE_METRIC.formatted(bidRequest.accountId)] == creativeSize + } + + def "PBS should update prebid_cache.creative_size.xml metric when video bid and xml creative is received"() { + given: "Current value of metric prebid_cache.requests.ok" + def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_REQUEST_OK_METRIC) + + and: "Default BidRequest with cache, targeting" + def bidRequest = BidRequest.defaultVideoRequest.tap { + it.enableCache() + it.ext.prebid.targeting = new Targeting() + } + + and: "Default basic bid with banner creative" + def asset = new Asset(id: PBSUtils.randomNumber) + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + seatbid[0].bid[0].adm = new Adm(assets: [asset]) + } + + and: "Set bidder response" + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + defaultPbsService.sendAuctionRequest(bidRequest) + + then: "prebid_cache.creative_size.json should be update" + def adm = bidResponse.seatbid[0].bid[0].getAdm() + def creativeSize = adm.bytes.length + + and: "prebid_cache.creative_size.json metric should be updated" + def metrics = defaultPbsService.sendCollectedMetricsRequest() + assert metrics[PREBID_CACHE_REQUEST_OK_METRIC] == initialValue + 1 + assert metrics[PREBID_CACHE_XML_CREATIVE_SIZE_GLOBAL_METRIC] == creativeSize + + and: "account..prebid_cache.creative_size.json should be update" + assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[ACCOUNT_XML_CREATIVE_SIZE_METRIC.formatted(bidRequest.accountId)] == creativeSize } def "PBS should cache bids when targeting is specified"() { @@ -214,7 +259,7 @@ class CacheSpec extends BaseSpec { and: "PBS should include metrics for request" def metrics = pbsService.sendCollectedMetricsRequest() - assert metrics[JSON_CREATIVE_TTL_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl + assert metrics[ACCOUNT_JSON_CREATIVE_TTL_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 cleanup: "Stop and remove pbs container" @@ -254,12 +299,16 @@ class CacheSpec extends BaseSpec { and: "PBS cache key should have length equal to default UUID" assert cacheKey.length() == DEFAULT_UUID_LENGTH - and: "PBS should include metrics for request" + and: "PBS should include metrics for account" def metrics = pbsService.sendCollectedMetricsRequest() - assert metrics[JSON_CREATIVE_TTL_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == videoHostTtl - assert metrics[XML_CREATIVE_TTL_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == videoHostTtl + assert metrics[ACCOUNT_JSON_CREATIVE_TTL_METRIC.formatted(bidRequest.accountId)] == videoHostTtl + assert metrics[ACCOUNT_XML_CREATIVE_TTL_METRIC.formatted(bidRequest.accountId)] == videoHostTtl assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 + and: "PBS should include metrics prebid_cache_creative.{xml,json}.creative.ttl for general" + assert metrics[PREBID_CACHE_JSON_CREATIVE_TTL_METRIC] == videoHostTtl + assert metrics[PREBID_CACHE_XML_CREATIVE_TTL_METRIC] == videoHostTtl + cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(pbsConfig) } @@ -294,7 +343,7 @@ class CacheSpec extends BaseSpec { and: "PBS should include metrics for request" def metrics = pbsService.sendCollectedMetricsRequest() - assert metrics[JSON_CREATIVE_TTL_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl + assert metrics[ACCOUNT_JSON_CREATIVE_TTL_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 cleanup: "Stop and remove pbs container" @@ -330,7 +379,7 @@ class CacheSpec extends BaseSpec { and: "PBS should include metrics for request" def metrics = pbsService.sendCollectedMetricsRequest() - assert metrics[JSON_CREATIVE_TTL_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl + assert metrics[ACCOUNT_JSON_CREATIVE_TTL_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 cleanup: "Stop and remove pbs container" @@ -364,7 +413,7 @@ class CacheSpec extends BaseSpec { and: "PBS should include metrics for request" def metrics = pbsService.sendCollectedMetricsRequest() - assert metrics[JSON_CREATIVE_TTL_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl + assert metrics[ACCOUNT_JSON_CREATIVE_TTL_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 cleanup: "Stop and remove pbs container" @@ -481,8 +530,8 @@ class CacheSpec extends BaseSpec { } def "PBS should update prebid_cache.creative_size.xml metric and adding tracking xml when xml creative contain #wrapper and impression are valid xml value"() { - given: "Current value of metric prebid_cache.requests.ok" - def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_VTRACK_WRITE_OK_METRIC) + given: "Current value of metric prebid_cache.vtrack.write.ok" + def initialOkVTrackValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_VTRACK_WRITE_OK_METRIC) and: "Create and save enabled events config in account" def accountId = PBSUtils.randomNumber.toString() @@ -514,10 +563,13 @@ class CacheSpec extends BaseSpec { and: "prebid_cache.creative_size.xml metric should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert metrics[PREBID_CACHE_VTRACK_WRITE_OK_METRIC] == initialValue + 1 + def ttlSeconds = request.puts[0].ttlseconds + assert metrics[PREBID_CACHE_VTRACK_WRITE_OK_METRIC] == initialOkVTrackValue + 1 + assert metrics[PREBID_CACHE_VTRACK_XML_CREATIVE_TTL_METRIC] == ttlSeconds - and: "account..prebid_cache.creative_size.xml should be updated" + and: "account..prebid_cache.vtrack.creative_size.xml should be updated" assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC.formatted(accountId) as String] == 1 + assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_CREATIVE_TTL_XML_METRIC.formatted(accountId) as String] == ttlSeconds where: wrapper | impression @@ -790,13 +842,13 @@ class CacheSpec extends BaseSpec { and: "account..prebid_cache.creative_size.xml should be updated" assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC.formatted(accountId)] == 1 - assert metrics[XML_CREATIVE_SIZE_ACCOUNT_METRIC.formatted(accountId)] == creativeSize + assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_XML_CREATIVE_SIZE_METRIC.formatted(accountId)] == creativeSize where: enabledCacheConcfig << [null, false, true] } - def "PBS should failed cache and update prebid_cache.vtrack.write.err metric andwhen cache service respond with invalid status code"() { + def "PBS should failed cache and update prebid_cache.vtrack.write.err metric when cache service respond with invalid status code"() { given: "Current value of metric prebid_cache.requests.ok" def okInitialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_VTRACK_WRITE_ERROR_METRIC) From a9f27be8e191d24bbec659e63ebe20fe3882d805 Mon Sep 17 00:00:00 2001 From: markiian Date: Mon, 13 Oct 2025 20:11:03 +0300 Subject: [PATCH 07/16] Coverage metrics for cache internal /get vtrack endpoint --- .../service/PrebidServerService.groovy | 5 +- .../server/functional/tests/CacheSpec.groovy | 250 +++++++++++++----- 2 files changed, 188 insertions(+), 67 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy index 503c35a6100..85cf21914af 100644 --- a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy +++ b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy @@ -224,11 +224,12 @@ class PrebidServerService implements ObjectMapperWrapper { int sendGetVtrackRequest(String uuid, String cacheHost = null) { def requestSpecification = given(requestSpecification) - setUpUuidIfPresent(uuid, requestSpecification) setUpCacheHostIfPresent(cacheHost, requestSpecification) - requestSpecification.get(VTRACK_ENDPOINT).statusCode() + def response = requestSpecification.get(VTRACK_ENDPOINT) + checkResponseStatusCode(response) + response.statusCode() } private static void setUpUuidIfPresent(String uuid, RequestSpecification requestSpecification) { diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy index 9827b5bec23..844189d9c25 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy @@ -15,8 +15,11 @@ import org.prebid.server.functional.model.request.vtrack.xml.Vast import org.prebid.server.functional.model.response.auction.Adm import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.service.PrebidServerException +import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.util.PBSUtils +import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST +import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR import static org.prebid.server.functional.model.response.auction.ErrorType.CACHE import static org.prebid.server.functional.model.AccountStatus.ACTIVE import static org.prebid.server.functional.model.bidder.BidderName.GENERIC @@ -31,31 +34,31 @@ class CacheSpec extends BaseSpec { private static final Integer DEFAULT_UUID_LENGTH = 36 private static final Integer TARGETING_PARAM_NAME_MAX_LENGTH = 20 - private static final String ACCOUNT_PREBID_CACHE_VTRACK_XML_CREATIVE_SIZE_METRIC = "account.%s.prebid_cache.vtrack.creative_size.xml" + private static final String ACCOUNT_VTRACK_XML_CREATIVE_SIZE_METRIC = "account.%s.prebid_cache.vtrack.creative_size.xml" private static final String ACCOUNT_JSON_CREATIVE_SIZE_METRIC = "account.%s.prebid_cache.creative_size.json" private static final String ACCOUNT_XML_CREATIVE_SIZE_METRIC = "account.%s.prebid_cache.creative_size.xml" private static final String ACCOUNT_XML_CREATIVE_TTL_METRIC = "account.%s.prebid_cache.creative_ttl.xml" private static final String ACCOUNT_JSON_CREATIVE_TTL_METRIC = "account.%s.prebid_cache.creative_ttl.json" - private static final String ACCOUNT_PREBID_CACHE_VTRACK_CREATIVE_TTL_XML_METRIC = "account.%s.prebid_cache.vtrack.creative_ttl.xml" - private static final String ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC = "account.%s.prebid_cache.vtrack.write.ok" - private static final String ACCOUNT_PREBID_CACHE_VTRACK_WRITE_ERR_METRIC = "account.%s.prebid_cache.vtrack.write.err" - private static final String ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC = "account.%s.prebid_cache.requests.ok" + private static final String ACCOUNT_VTRACK_CREATIVE_TTL_XML_METRIC = "account.%s.prebid_cache.vtrack.creative_ttl.xml" + private static final String ACCOUNT_VTRACK_WRITE_OK_METRIC = "account.%s.prebid_cache.vtrack.write.ok" + private static final String ACCOUNT_VTRACK_WRITE_ERR_METRIC = "account.%s.prebid_cache.vtrack.write.err" + private static final String ACCOUNT_REQUEST_OK_METRIC = "account.%s.prebid_cache.requests.ok" - private static final String PREBID_CACHE_REQUEST_OK_METRIC = "prebid_cache.requests.ok" + private static final String REQUEST_OK_METRIC = "prebid_cache.requests.ok" - private static final String PREBID_CACHE_JSON_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.creative_size.json" - private static final String PREBID_CACHE_XML_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.creative_size.xml" - private static final String PREBID_CACHE_XML_CREATIVE_TTL_METRIC = "prebid_cache.creative_ttl.xml" - private static final String PREBID_CACHE_JSON_CREATIVE_TTL_METRIC = "prebid_cache.creative_ttl.json" + private static final String JSON_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.creative_size.json" + private static final String XML_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.creative_size.xml" + private static final String XML_CREATIVE_TTL_METRIC = "prebid_cache.creative_ttl.xml" + private static final String JSON_CREATIVE_TTL_METRIC = "prebid_cache.creative_ttl.json" - private static final String PREBID_CACHE_VTRACK_XML_CREATIVE_SIZE_METRIC = "prebid_cache.vtrack.creative_size.xml" - private static final String PREBID_CACHE_VTRACK_XML_CREATIVE_TTL_METRIC = "prebid_cache.vtrack.creative_ttl.xml" + private static final String VTRACK_XML_CREATIVE_SIZE_METRIC = "prebid_cache.vtrack.creative_size.xml" + private static final String VTRACK_XML_CREATIVE_TTL_METRIC = "prebid_cache.vtrack.creative_ttl.xml" - private static final String PREBID_CACHE_VTRACK_WRITE_OK_METRIC = "prebid_cache.vtrack.write.ok" - private static final String PREBID_CACHE_VTRACK_WRITE_ERROR_METRIC = "prebid_cache.vtrack.write.err" - private static final String PREBID_CACHE_VTRACK_READ_OK_METRIC = "prebid_cache.vtrack.read.ok" - private static final String PREBID_CACHE_VTRACK_READ_ERROR_METRIC = "prebid_cache.vtrack.read.err" + private static final String VTRACK_WRITE_OK_METRIC = "prebid_cache.vtrack.write.ok" + private static final String VTRACK_WRITE_ERROR_METRIC = "prebid_cache.vtrack.write.err" + private static final String VTRACK_READ_OK_METRIC = "prebid_cache.vtrack.read.ok" + private static final String VTRACK_READ_ERROR_METRIC = "prebid_cache.vtrack.read.err" private static final String CACHE_PATH = "/${PBSUtils.randomString}".toString() private static final String CACHE_HOST = "${PBSUtils.randomString}:${PBSUtils.getRandomNumber(0, 65535)}".toString() @@ -64,9 +67,22 @@ class CacheSpec extends BaseSpec { private static final String HTTPS_SCHEME = 'https' private static final String CACHE_ENDPOINT = "/cache" + static Map getInternalPrebidCacheConfig(String host = networkServiceContainer.hostAndPort) { + ["cache.internal.scheme": "http", + "cache.internal.host" : "$host".toString(), + "cache.internal.path" : "/cache" + ].asImmutable() + } + + private static PrebidServerService pbsServiceWithInternalCache + + def setupSpec() { + pbsServiceWithInternalCache = pbsServiceFactory.getService(getInternalPrebidCacheConfig()) + } + def "PBS should update prebid_cache.creative_size.xml metric when xml creative is received"() { given: "Current value of metric prebid_cache.requests.ok" - def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_VTRACK_WRITE_OK_METRIC) + def initialValue = getCurrentMetricValue(defaultPbsService, VTRACK_WRITE_OK_METRIC) and: "Default VtrackRequest" def accountId = PBSUtils.randomNumber.toString() @@ -82,17 +98,17 @@ class CacheSpec extends BaseSpec { then: "prebid_cache.vtrack.creative_size.xml metric should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() def creativeSize = creative.bytes.length - assert metrics[PREBID_CACHE_VTRACK_WRITE_OK_METRIC] == initialValue + 1 - assert metrics[PREBID_CACHE_VTRACK_XML_CREATIVE_SIZE_METRIC] == creativeSize + assert metrics[VTRACK_WRITE_OK_METRIC] == initialValue + 1 + assert metrics[VTRACK_XML_CREATIVE_SIZE_METRIC] == creativeSize and: "account..prebid_cache.creative_size.xml should be updated" - assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC.formatted(accountId)] == 1 - assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_XML_CREATIVE_SIZE_METRIC.formatted(accountId)] == creativeSize + assert metrics[ACCOUNT_VTRACK_WRITE_OK_METRIC.formatted(accountId)] == 1 + assert metrics[ACCOUNT_VTRACK_XML_CREATIVE_SIZE_METRIC.formatted(accountId)] == creativeSize } def "PBS should update prebid_cache.creative_size.json metric when json creative is received"() { given: "Current value of metric prebid_cache.requests.ok" - def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_REQUEST_OK_METRIC) + def initialValue = getCurrentMetricValue(defaultPbsService, REQUEST_OK_METRIC) and: "Default BidRequest with cache, targeting" def bidRequest = BidRequest.defaultBidRequest.tap { @@ -117,17 +133,17 @@ class CacheSpec extends BaseSpec { and: "prebid_cache.creative_size.json metric should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert metrics[PREBID_CACHE_REQUEST_OK_METRIC] == initialValue + 1 - assert metrics[PREBID_CACHE_JSON_CREATIVE_SIZE_GLOBAL_METRIC] == creativeSize + assert metrics[REQUEST_OK_METRIC] == initialValue + 1 + assert metrics[JSON_CREATIVE_SIZE_GLOBAL_METRIC] == creativeSize and: "account..prebid_cache.creative_size.json should be update" - assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[ACCOUNT_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 assert metrics[ACCOUNT_JSON_CREATIVE_SIZE_METRIC.formatted(bidRequest.accountId)] == creativeSize } def "PBS should update prebid_cache.creative_size.xml metric when video bid and xml creative is received"() { given: "Current value of metric prebid_cache.requests.ok" - def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_REQUEST_OK_METRIC) + def initialValue = getCurrentMetricValue(defaultPbsService, REQUEST_OK_METRIC) and: "Default BidRequest with cache, targeting" def bidRequest = BidRequest.defaultVideoRequest.tap { @@ -153,11 +169,11 @@ class CacheSpec extends BaseSpec { and: "prebid_cache.creative_size.json metric should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert metrics[PREBID_CACHE_REQUEST_OK_METRIC] == initialValue + 1 - assert metrics[PREBID_CACHE_XML_CREATIVE_SIZE_GLOBAL_METRIC] == creativeSize + assert metrics[REQUEST_OK_METRIC] == initialValue + 1 + assert metrics[XML_CREATIVE_SIZE_GLOBAL_METRIC] == creativeSize and: "account..prebid_cache.creative_size.json should be update" - assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[ACCOUNT_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 assert metrics[ACCOUNT_XML_CREATIVE_SIZE_METRIC.formatted(bidRequest.accountId)] == creativeSize } @@ -260,7 +276,7 @@ class CacheSpec extends BaseSpec { and: "PBS should include metrics for request" def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[ACCOUNT_JSON_CREATIVE_TTL_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl - assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[ACCOUNT_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(pbsConfig) @@ -303,11 +319,11 @@ class CacheSpec extends BaseSpec { def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[ACCOUNT_JSON_CREATIVE_TTL_METRIC.formatted(bidRequest.accountId)] == videoHostTtl assert metrics[ACCOUNT_XML_CREATIVE_TTL_METRIC.formatted(bidRequest.accountId)] == videoHostTtl - assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[ACCOUNT_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 and: "PBS should include metrics prebid_cache_creative.{xml,json}.creative.ttl for general" - assert metrics[PREBID_CACHE_JSON_CREATIVE_TTL_METRIC] == videoHostTtl - assert metrics[PREBID_CACHE_XML_CREATIVE_TTL_METRIC] == videoHostTtl + assert metrics[JSON_CREATIVE_TTL_METRIC] == videoHostTtl + assert metrics[XML_CREATIVE_TTL_METRIC] == videoHostTtl cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(pbsConfig) @@ -344,7 +360,7 @@ class CacheSpec extends BaseSpec { and: "PBS should include metrics for request" def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[ACCOUNT_JSON_CREATIVE_TTL_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl - assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[ACCOUNT_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(pbsConfig) @@ -380,7 +396,7 @@ class CacheSpec extends BaseSpec { and: "PBS should include metrics for request" def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[ACCOUNT_JSON_CREATIVE_TTL_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl - assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[ACCOUNT_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(pbsConfig) @@ -414,7 +430,7 @@ class CacheSpec extends BaseSpec { and: "PBS should include metrics for request" def metrics = pbsService.sendCollectedMetricsRequest() assert metrics[ACCOUNT_JSON_CREATIVE_TTL_METRIC.formatted(bidRequest.accountId)] == bannerHostTtl - assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[ACCOUNT_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 cleanup: "Stop and remove pbs container" pbsServiceFactory.removeContainer(pbsConfig) @@ -531,7 +547,7 @@ class CacheSpec extends BaseSpec { def "PBS should update prebid_cache.creative_size.xml metric and adding tracking xml when xml creative contain #wrapper and impression are valid xml value"() { given: "Current value of metric prebid_cache.vtrack.write.ok" - def initialOkVTrackValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_VTRACK_WRITE_OK_METRIC) + def initialOkVTrackValue = getCurrentMetricValue(defaultPbsService, VTRACK_WRITE_OK_METRIC) and: "Create and save enabled events config in account" def accountId = PBSUtils.randomNumber.toString() @@ -564,12 +580,12 @@ class CacheSpec extends BaseSpec { and: "prebid_cache.creative_size.xml metric should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() def ttlSeconds = request.puts[0].ttlseconds - assert metrics[PREBID_CACHE_VTRACK_WRITE_OK_METRIC] == initialOkVTrackValue + 1 - assert metrics[PREBID_CACHE_VTRACK_XML_CREATIVE_TTL_METRIC] == ttlSeconds + assert metrics[VTRACK_WRITE_OK_METRIC] == initialOkVTrackValue + 1 + assert metrics[VTRACK_XML_CREATIVE_TTL_METRIC] == ttlSeconds and: "account..prebid_cache.vtrack.creative_size.xml should be updated" - assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC.formatted(accountId) as String] == 1 - assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_CREATIVE_TTL_XML_METRIC.formatted(accountId) as String] == ttlSeconds + assert metrics[ACCOUNT_VTRACK_WRITE_OK_METRIC.formatted(accountId) as String] == 1 + assert metrics[ACCOUNT_VTRACK_CREATIVE_TTL_XML_METRIC.formatted(accountId) as String] == ttlSeconds where: wrapper | impression @@ -724,7 +740,7 @@ class CacheSpec extends BaseSpec { def "PBS should cache bids and add targeting values when account cache config #accountAuctionConfig"() { given: "Current value of metric prebid_cache.requests.ok" - def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_REQUEST_OK_METRIC) + def initialValue = getCurrentMetricValue(defaultPbsService, REQUEST_OK_METRIC) and: "Default BidRequest with cache, targeting" def bidRequest = BidRequest.getDefaultVideoRequest().tap { @@ -758,8 +774,8 @@ class CacheSpec extends BaseSpec { and: "Metrics should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert metrics[PREBID_CACHE_REQUEST_OK_METRIC] == initialValue + 1 - assert metrics[ACCOUNT_PREBID_CACHE_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 + assert metrics[REQUEST_OK_METRIC] == initialValue + 1 + assert metrics[ACCOUNT_REQUEST_OK_METRIC.formatted(bidRequest.accountId)] == 1 where: accountAuctionConfig << [ @@ -772,7 +788,7 @@ class CacheSpec extends BaseSpec { def "PBS shouldn't cache bids and add targeting values when account cache config disabled"() { given: "Current value of metric prebid_cache.requests.ok" - def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_VTRACK_WRITE_OK_METRIC) + def initialValue = getCurrentMetricValue(defaultPbsService, VTRACK_WRITE_OK_METRIC) and: "Default BidRequest with cache, targeting" def bidRequest = BidRequest.getDefaultVideoRequest().tap { @@ -807,13 +823,13 @@ class CacheSpec extends BaseSpec { and: "Metrics shouldn't be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert metrics[PREBID_CACHE_VTRACK_WRITE_OK_METRIC] == initialValue - assert !metrics[ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC.formatted(bidRequest.accountId)] + assert metrics[VTRACK_WRITE_OK_METRIC] == initialValue + assert !metrics[ACCOUNT_VTRACK_WRITE_OK_METRIC.formatted(bidRequest.accountId)] } def "PBS should update prebid_cache.creative_size.xml metric when account cache config #enabledCacheConcfig"() { given: "Current value of metric prebid_cache.requests.ok" - def okInitialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_VTRACK_WRITE_OK_METRIC) + def okInitialValue = getCurrentMetricValue(defaultPbsService, VTRACK_WRITE_OK_METRIC) and: "Default VtrackRequest" def accountId = PBSUtils.randomNumber.toString() @@ -838,11 +854,11 @@ class CacheSpec extends BaseSpec { then: "prebid_cache.creative_size.xml metric should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() def creativeSize = creative.bytes.length - assert metrics[PREBID_CACHE_VTRACK_WRITE_OK_METRIC] == okInitialValue + 1 + assert metrics[VTRACK_WRITE_OK_METRIC] == okInitialValue + 1 and: "account..prebid_cache.creative_size.xml should be updated" - assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_WRITE_OK_METRIC.formatted(accountId)] == 1 - assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_XML_CREATIVE_SIZE_METRIC.formatted(accountId)] == creativeSize + assert metrics[ACCOUNT_VTRACK_WRITE_OK_METRIC.formatted(accountId)] == 1 + assert metrics[ACCOUNT_VTRACK_XML_CREATIVE_SIZE_METRIC.formatted(accountId)] == creativeSize where: enabledCacheConcfig << [null, false, true] @@ -850,7 +866,7 @@ class CacheSpec extends BaseSpec { def "PBS should failed cache and update prebid_cache.vtrack.write.err metric when cache service respond with invalid status code"() { given: "Current value of metric prebid_cache.requests.ok" - def okInitialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_VTRACK_WRITE_ERROR_METRIC) + def okInitialValue = getCurrentMetricValue(defaultPbsService, VTRACK_WRITE_ERROR_METRIC) and: "Default VtrackRequest" def accountId = PBSUtils.randomNumber.toString() @@ -883,21 +899,23 @@ class CacheSpec extends BaseSpec { then: "prebid_cache.vtrack.write.err metric should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert metrics[PREBID_CACHE_VTRACK_WRITE_ERROR_METRIC] == okInitialValue + 1 + assert metrics[VTRACK_WRITE_ERROR_METRIC] == okInitialValue + 1 and: "account..prebid_cache.vtrack.write.err should be updated" - assert metrics[ACCOUNT_PREBID_CACHE_VTRACK_WRITE_ERR_METRIC.formatted(accountId)] == 1 + assert metrics[ACCOUNT_VTRACK_WRITE_ERR_METRIC.formatted(accountId)] == 1 cleanup: prebidCache.reset() } def "PBS should return 400 status code when get vtrack request without uuid"() { - given: "PBS processes get vtrack request" - def response = defaultPbsService.sendGetVtrackRequest(null) + when: "PBS processes get vtrack request" + defaultPbsService.sendGetVtrackRequest(null) - expect: "Response body should contain error status code" - assert response == HttpStatusCode.BAD_REQUEST_400.code() + then: "Request should fail with an error" + def exception = thrown(PrebidServerException) + assert exception.statusCode == BAD_REQUEST.code() + assert exception.responseBody == "'uuid' is a required query parameter and can't be empty" cleanup: prebidCache.reset(CACHE_ENDPOINT) @@ -918,7 +936,7 @@ class CacheSpec extends BaseSpec { and: "Metrics should contain ok metric" def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() - assert metricsRequest[PREBID_CACHE_VTRACK_READ_OK_METRIC] == 1 + assert metricsRequest[VTRACK_READ_OK_METRIC] == 1 cleanup: prebidCache.reset(CACHE_ENDPOINT) @@ -932,14 +950,16 @@ class CacheSpec extends BaseSpec { prebidCache.setInvalidVtrackResponse(uuid) when: "PBS processes get vtrack request" - def response = defaultPbsService.sendGetVtrackRequest(uuid) + defaultPbsService.sendGetVtrackRequest(uuid) - then: "Response body should contain error status code" - assert response == HttpStatusCode.INTERNAL_SERVER_ERROR_500.code() + then: "Request should fail with an error" + def exception = thrown(PrebidServerException) + assert exception.statusCode == INTERNAL_SERVER_ERROR.code() + assert exception.responseBody == "Error occurred while sending request to cache: Cannot parse response: " and: "Metrics should contain error metric" def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() - assert metricsRequest[PREBID_CACHE_VTRACK_READ_ERROR_METRIC] == 1 + assert metricsRequest[VTRACK_READ_ERROR_METRIC] == 1 cleanup: "Clean cache mock response" prebidCache.reset(CACHE_ENDPOINT) @@ -947,7 +967,10 @@ class CacheSpec extends BaseSpec { def "PBS should return 200 status code when get vtrack request with uuid and ch"() { given: "Current value of metric prebid_cache.vtrack.read.ok" - def initialValue = getCurrentMetricValue(defaultPbsService, PREBID_CACHE_VTRACK_READ_OK_METRIC) + def initialValue = getCurrentMetricValue(defaultPbsService, VTRACK_READ_OK_METRIC) + + and: "Clean cache mock response" + prebidCache.reset(CACHE_ENDPOINT) and: "Random uuid and cache host" def uuid = UUID.randomUUID().toString() @@ -964,9 +987,106 @@ class CacheSpec extends BaseSpec { and: "Metrics should contain ok metrics" def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() - assert metricsRequest[PREBID_CACHE_VTRACK_READ_OK_METRIC] == initialValue + 1 + assert metricsRequest[VTRACK_READ_OK_METRIC] == initialValue + 1 + + cleanup: "Clean cache mock response" + prebidCache.reset(CACHE_ENDPOINT) + } + + def "PBS should return 200 status code when internal cache configured and get vtrack request with uuid and ch"() { + given: "Current value of metric prebid_cache.vtrack.read.ok" + def initialValue = getCurrentMetricValue(pbsServiceWithInternalCache, VTRACK_READ_OK_METRIC) + + and: "Clean cache mock response" + prebidCache.reset(CACHE_ENDPOINT) + + and: "Flush metric" + flushMetrics(pbsServiceWithInternalCache) + + and: "Random uuid and cache host" + def uuid = UUID.randomUUID().toString() + def cacheHost = PBSUtils.randomString + + and: "Clean up and set up successful response" + prebidCache.setVtrackResponse(uuid) + + when: "PBS processes get vtrack request" + def response = pbsServiceWithInternalCache.sendGetVtrackRequest(uuid, cacheHost) + + then: "Response body should contain 200 status code" + assert response == HttpStatusCode.OK_200.code() + + and: "Metrics should contain ok metrics" + def metricsRequest = pbsServiceWithInternalCache.sendCollectedMetricsRequest() + assert metricsRequest[VTRACK_READ_OK_METRIC] == initialValue + 1 + + cleanup: "Clean cache mock response" + prebidCache.reset(CACHE_ENDPOINT) + } + + def "PBS should return 200 status code when internal cache and get vtrack request contain uuid"() { + given: "Current value of metric prebid_cache.vtrack.read.ok" + def initialValue = getCurrentMetricValue(pbsServiceWithInternalCache, VTRACK_READ_OK_METRIC) + + and: "Random uuid" + def uuid = UUID.randomUUID().toString() + + and: "Cache set up successful response" + prebidCache.setVtrackResponse(uuid) + + and: "Flush metric" + flushMetrics(pbsServiceWithInternalCache) + + when: "PBS processes get vtrack request" + def response = pbsServiceWithInternalCache.sendGetVtrackRequest(uuid) + + then: "Response body should contain 200 status code" + assert response == HttpStatusCode.OK_200.code() + + and: "Metrics should contain ok metrics" + def metricsRequest = pbsServiceWithInternalCache.sendCollectedMetricsRequest() + assert metricsRequest[VTRACK_READ_OK_METRIC] == initialValue + 1 + + cleanup: + prebidCache.reset(CACHE_ENDPOINT) + } + + def "PBS should return status code that came from pbc when internal cache and get vtrack request and response from pbc invalid"() { + given: "Random uuid" + def uuid = UUID.randomUUID().toString() + + and: "Cache set up invalid response" + prebidCache.setInvalidVtrackResponse(uuid) + + and: "Flush metric" + flushMetrics(pbsServiceWithInternalCache) + + when: "PBS processes get vtrack request" + pbsServiceWithInternalCache.sendGetVtrackRequest(uuid) + + then: "Request should fail with an error" + def exception = thrown(PrebidServerException) + assert exception.statusCode == INTERNAL_SERVER_ERROR.code() + assert exception.responseBody == "Error occurred while sending request to cache: Cannot parse response: " + + and: "Metrics should contain error metric" + def metricsRequest = pbsServiceWithInternalCache.sendCollectedMetricsRequest() + assert metricsRequest[VTRACK_READ_ERROR_METRIC] == 1 cleanup: "Clean cache mock response" prebidCache.reset(CACHE_ENDPOINT) } + + def "PBS should return 400 status code when internal cache and get vtrack request without uuid"() { + when: "PBS processes get vtrack request" + pbsServiceWithInternalCache.sendGetVtrackRequest(null) + + then: "Request should fail with an error" + def exception = thrown(PrebidServerException) + assert exception.statusCode == BAD_REQUEST.code() + assert exception.responseBody == "'uuid' is a required query parameter and can't be empty" + + cleanup: + prebidCache.reset(CACHE_ENDPOINT) + } } From 311989276e1297135e4f14c3cd3501ac12d11e39 Mon Sep 17 00:00:00 2001 From: markiian Date: Mon, 13 Oct 2025 20:12:23 +0300 Subject: [PATCH 08/16] Minor update --- .../groovy/org/prebid/server/functional/tests/CacheSpec.groovy | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy index 844189d9c25..166aff91dcf 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy @@ -67,13 +67,12 @@ class CacheSpec extends BaseSpec { private static final String HTTPS_SCHEME = 'https' private static final String CACHE_ENDPOINT = "/cache" - static Map getInternalPrebidCacheConfig(String host = networkServiceContainer.hostAndPort) { + private static final Map getInternalPrebidCacheConfig(String host = networkServiceContainer.hostAndPort) { ["cache.internal.scheme": "http", "cache.internal.host" : "$host".toString(), "cache.internal.path" : "/cache" ].asImmutable() } - private static PrebidServerService pbsServiceWithInternalCache def setupSpec() { From a7fdad481fd4338da7bc3e505ef5f4b5e1f207b7 Mon Sep 17 00:00:00 2001 From: markiian Date: Mon, 13 Oct 2025 22:52:41 +0300 Subject: [PATCH 09/16] Divide ft test for VTrack and Cache Spec --- .../server/functional/tests/CacheSpec.groovy | 410 +----------------- .../functional/tests/CacheVtrackSpec.groovy | 390 +++++++++++++++++ 2 files changed, 395 insertions(+), 405 deletions(-) create mode 100644 src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy index 166aff91dcf..f8b2b975514 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy @@ -1,25 +1,18 @@ package org.prebid.server.functional.tests -import org.mockserver.model.HttpStatusCode import org.prebid.server.functional.model.config.AccountAuctionConfig import org.prebid.server.functional.model.config.AccountCacheConfig import org.prebid.server.functional.model.config.AccountConfig -import org.prebid.server.functional.model.config.AccountEventsConfig import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.request.auction.Asset import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.Imp import org.prebid.server.functional.model.request.auction.Targeting -import org.prebid.server.functional.model.request.vtrack.VtrackRequest -import org.prebid.server.functional.model.request.vtrack.xml.Vast import org.prebid.server.functional.model.response.auction.Adm import org.prebid.server.functional.model.response.auction.BidResponse -import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.util.PBSUtils -import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST -import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR import static org.prebid.server.functional.model.response.auction.ErrorType.CACHE import static org.prebid.server.functional.model.AccountStatus.ACTIVE import static org.prebid.server.functional.model.bidder.BidderName.GENERIC @@ -34,17 +27,12 @@ class CacheSpec extends BaseSpec { private static final Integer DEFAULT_UUID_LENGTH = 36 private static final Integer TARGETING_PARAM_NAME_MAX_LENGTH = 20 - private static final String ACCOUNT_VTRACK_XML_CREATIVE_SIZE_METRIC = "account.%s.prebid_cache.vtrack.creative_size.xml" private static final String ACCOUNT_JSON_CREATIVE_SIZE_METRIC = "account.%s.prebid_cache.creative_size.json" private static final String ACCOUNT_XML_CREATIVE_SIZE_METRIC = "account.%s.prebid_cache.creative_size.xml" private static final String ACCOUNT_XML_CREATIVE_TTL_METRIC = "account.%s.prebid_cache.creative_ttl.xml" private static final String ACCOUNT_JSON_CREATIVE_TTL_METRIC = "account.%s.prebid_cache.creative_ttl.json" - private static final String ACCOUNT_VTRACK_CREATIVE_TTL_XML_METRIC = "account.%s.prebid_cache.vtrack.creative_ttl.xml" - private static final String ACCOUNT_VTRACK_WRITE_OK_METRIC = "account.%s.prebid_cache.vtrack.write.ok" - private static final String ACCOUNT_VTRACK_WRITE_ERR_METRIC = "account.%s.prebid_cache.vtrack.write.err" private static final String ACCOUNT_REQUEST_OK_METRIC = "account.%s.prebid_cache.requests.ok" - private static final String REQUEST_OK_METRIC = "prebid_cache.requests.ok" private static final String JSON_CREATIVE_SIZE_GLOBAL_METRIC = "prebid_cache.creative_size.json" @@ -52,58 +40,11 @@ class CacheSpec extends BaseSpec { private static final String XML_CREATIVE_TTL_METRIC = "prebid_cache.creative_ttl.xml" private static final String JSON_CREATIVE_TTL_METRIC = "prebid_cache.creative_ttl.json" - private static final String VTRACK_XML_CREATIVE_SIZE_METRIC = "prebid_cache.vtrack.creative_size.xml" - private static final String VTRACK_XML_CREATIVE_TTL_METRIC = "prebid_cache.vtrack.creative_ttl.xml" - - private static final String VTRACK_WRITE_OK_METRIC = "prebid_cache.vtrack.write.ok" - private static final String VTRACK_WRITE_ERROR_METRIC = "prebid_cache.vtrack.write.err" - private static final String VTRACK_READ_OK_METRIC = "prebid_cache.vtrack.read.ok" - private static final String VTRACK_READ_ERROR_METRIC = "prebid_cache.vtrack.read.err" - private static final String CACHE_PATH = "/${PBSUtils.randomString}".toString() private static final String CACHE_HOST = "${PBSUtils.randomString}:${PBSUtils.getRandomNumber(0, 65535)}".toString() private static final String INTERNAL_CACHE_PATH = '/cache' private static final String HTTP_SCHEME = 'http' private static final String HTTPS_SCHEME = 'https' - private static final String CACHE_ENDPOINT = "/cache" - - private static final Map getInternalPrebidCacheConfig(String host = networkServiceContainer.hostAndPort) { - ["cache.internal.scheme": "http", - "cache.internal.host" : "$host".toString(), - "cache.internal.path" : "/cache" - ].asImmutable() - } - private static PrebidServerService pbsServiceWithInternalCache - - def setupSpec() { - pbsServiceWithInternalCache = pbsServiceFactory.getService(getInternalPrebidCacheConfig()) - } - - def "PBS should update prebid_cache.creative_size.xml metric when xml creative is received"() { - given: "Current value of metric prebid_cache.requests.ok" - def initialValue = getCurrentMetricValue(defaultPbsService, VTRACK_WRITE_OK_METRIC) - - and: "Default VtrackRequest" - def accountId = PBSUtils.randomNumber.toString() - def creative = encodeXml(Vast.getDefaultVastModel(PBSUtils.randomString)) - def request = VtrackRequest.getDefaultVtrackRequest(creative) - - and: "Flush metrics" - flushMetrics(defaultPbsService) - - when: "PBS processes vtrack request" - defaultPbsService.sendPostVtrackRequest(request, accountId) - - then: "prebid_cache.vtrack.creative_size.xml metric should be updated" - def metrics = defaultPbsService.sendCollectedMetricsRequest() - def creativeSize = creative.bytes.length - assert metrics[VTRACK_WRITE_OK_METRIC] == initialValue + 1 - assert metrics[VTRACK_XML_CREATIVE_SIZE_METRIC] == creativeSize - - and: "account..prebid_cache.creative_size.xml should be updated" - assert metrics[ACCOUNT_VTRACK_WRITE_OK_METRIC.formatted(accountId)] == 1 - assert metrics[ACCOUNT_VTRACK_XML_CREATIVE_SIZE_METRIC.formatted(accountId)] == creativeSize - } def "PBS should update prebid_cache.creative_size.json metric when json creative is received"() { given: "Current value of metric prebid_cache.requests.ok" @@ -544,72 +485,14 @@ class CacheSpec extends BaseSpec { true | VIDEO } - def "PBS should update prebid_cache.creative_size.xml metric and adding tracking xml when xml creative contain #wrapper and impression are valid xml value"() { - given: "Current value of metric prebid_cache.vtrack.write.ok" - def initialOkVTrackValue = getCurrentMetricValue(defaultPbsService, VTRACK_WRITE_OK_METRIC) - - and: "Create and save enabled events config in account" - def accountId = PBSUtils.randomNumber.toString() - def account = new Account().tap { - uuid = accountId - config = new AccountConfig().tap { - auction = new AccountAuctionConfig(events: new AccountEventsConfig(enabled: true)) - } - } - accountDao.save(account) - - and: "Vtrack request with custom tags" - def payload = PBSUtils.randomString - def creative = "<${wrapper}>prebid.org wrapper" + - "<![CDATA[//${payload}]]>" + - "<${impression}> <![CDATA[ ]]> " - def request = VtrackRequest.getDefaultVtrackRequest(creative) - - and: "Flush metrics" - flushMetrics(defaultPbsService) - - when: "PBS processes vtrack request" - defaultPbsService.sendPostVtrackRequest(request, accountId) - - then: "Vast xml is modified" - def prebidCacheRequest = prebidCache.getXmlRecordedRequestsBody(payload) - assert prebidCacheRequest.size() == 1 - assert prebidCacheRequest[0].contains("/event?t=imp&b=${request.puts[0].bidid}&a=$accountId&bidder=${request.puts[0].bidder}") - - and: "prebid_cache.creative_size.xml metric should be updated" - def metrics = defaultPbsService.sendCollectedMetricsRequest() - def ttlSeconds = request.puts[0].ttlseconds - assert metrics[VTRACK_WRITE_OK_METRIC] == initialOkVTrackValue + 1 - assert metrics[VTRACK_XML_CREATIVE_TTL_METRIC] == ttlSeconds - - and: "account..prebid_cache.vtrack.creative_size.xml should be updated" - assert metrics[ACCOUNT_VTRACK_WRITE_OK_METRIC.formatted(accountId) as String] == 1 - assert metrics[ACCOUNT_VTRACK_CREATIVE_TTL_XML_METRIC.formatted(accountId) as String] == ttlSeconds - - where: - wrapper | impression - " wrapper " | " impression " - PBSUtils.getRandomCase(" wrapper ") | PBSUtils.getRandomCase(" impression ") - " wraPPer ${PBSUtils.getRandomString()} " | " imPreSSion ${PBSUtils.getRandomString()}" - " inLine " | " ImpreSSion $PBSUtils.randomNumber" - PBSUtils.getRandomCase(" inline ") | " ${PBSUtils.getRandomCase(" impression ")} $PBSUtils.randomNumber " - " inline ${PBSUtils.getRandomString()} " | " ImpreSSion " - } - def "PBS shouldn't cache bids when targeting is specified and config cache is invalid"() { - given: "Pbs config with cache" - def INVALID_PREBID_CACHE_CONFIG = ["cache.path" : CACHE_PATH, - "cache.scheme": HTTP_SCHEME, - "cache.host" : CACHE_HOST] - def pbsService = pbsServiceFactory.getService(INVALID_PREBID_CACHE_CONFIG) - - and: "Default BidRequest with cache, targeting" + given: "Default BidRequest with cache, targeting" def bidRequest = BidRequest.defaultBidRequest.tap { it.enableCache() } when: "PBS processes auction request" - def bidResponse = pbsService.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithInvalidCache.sendAuctionRequest(bidRequest) then: "Response should contain error" assert bidResponse.ext?.errors[CACHE]*.code == [999] @@ -620,25 +503,16 @@ class CacheSpec extends BaseSpec { and: "PBS shouldn't call PBC" assert prebidCache.getRequestCount(bidRequest.imp[0].id) == 0 - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(INVALID_PREBID_CACHE_CONFIG) } def "PBS should cache bids and emit error when targeting is specified and config cache is valid and internal is invalid"() { - given: "Pbs config with cache" - def INVALID_PREBID_CACHE_CONFIG = ["cache.internal.path" : CACHE_PATH, - "cache.internal.scheme": HTTP_SCHEME, - "cache.internal.host" : CACHE_HOST] - def pbsService = pbsServiceFactory.getService(INVALID_PREBID_CACHE_CONFIG) - - and: "Default BidRequest with cache, targeting" + given: "Default BidRequest with cache, targeting" def bidRequest = BidRequest.defaultBidRequest.tap { it.enableCache() } when: "PBS processes auction request" - def bidResponse = pbsService.sendAuctionRequest(bidRequest) + def bidResponse = pbsServiceWithInvalidCache.sendAuctionRequest(bidRequest) then: "PBS should call PBC" assert prebidCache.getRequestCount(bidRequest.imp[0].id) == 0 @@ -657,9 +531,6 @@ class CacheSpec extends BaseSpec { then: "Response should contain error" assert bidResponse.ext?.errors[CACHE]*.code == [999] assert bidResponse.ext?.errors[CACHE]*.message[0] == ("Failed to resolve '${CACHE_HOST.tokenize(":")[0]}' [A(1)]") - - cleanup: "Stop and remove pbs container" - pbsServiceFactory.removeContainer(INVALID_PREBID_CACHE_CONFIG) } def "PBS should cache bids when targeting is specified and config cache is invalid and internal cache config valid"() { @@ -786,10 +657,7 @@ class CacheSpec extends BaseSpec { } def "PBS shouldn't cache bids and add targeting values when account cache config disabled"() { - given: "Current value of metric prebid_cache.requests.ok" - def initialValue = getCurrentMetricValue(defaultPbsService, VTRACK_WRITE_OK_METRIC) - - and: "Default BidRequest with cache, targeting" + given: "Default BidRequest with cache, targeting" def bidRequest = BidRequest.getDefaultVideoRequest().tap { it.enableCache() } @@ -819,273 +687,5 @@ class CacheSpec extends BaseSpec { assert !targetingKeyMap.containsKey("hb_cache_id_${GENERIC}".toString()) assert !targetingKeyMap.containsKey('hb_uuid') assert !targetingKeyMap.containsKey("hb_uuid_${GENERIC}".toString()) - - and: "Metrics shouldn't be updated" - def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert metrics[VTRACK_WRITE_OK_METRIC] == initialValue - assert !metrics[ACCOUNT_VTRACK_WRITE_OK_METRIC.formatted(bidRequest.accountId)] - } - - def "PBS should update prebid_cache.creative_size.xml metric when account cache config #enabledCacheConcfig"() { - given: "Current value of metric prebid_cache.requests.ok" - def okInitialValue = getCurrentMetricValue(defaultPbsService, VTRACK_WRITE_OK_METRIC) - - and: "Default VtrackRequest" - def accountId = PBSUtils.randomNumber.toString() - def creative = encodeXml(Vast.getDefaultVastModel(PBSUtils.randomString)) - def request = VtrackRequest.getDefaultVtrackRequest(creative) - - and: "Create and save enabled events config in account" - def account = new Account().tap { - it.uuid = accountId - it.config = new AccountConfig().tap { - it.auction = new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: enabledCacheConcfig)) - } - } - accountDao.save(account) - - and: "Flush metrics" - flushMetrics(defaultPbsService) - - when: "PBS processes vtrack request" - defaultPbsService.sendPostVtrackRequest(request, accountId) - - then: "prebid_cache.creative_size.xml metric should be updated" - def metrics = defaultPbsService.sendCollectedMetricsRequest() - def creativeSize = creative.bytes.length - assert metrics[VTRACK_WRITE_OK_METRIC] == okInitialValue + 1 - - and: "account..prebid_cache.creative_size.xml should be updated" - assert metrics[ACCOUNT_VTRACK_WRITE_OK_METRIC.formatted(accountId)] == 1 - assert metrics[ACCOUNT_VTRACK_XML_CREATIVE_SIZE_METRIC.formatted(accountId)] == creativeSize - - where: - enabledCacheConcfig << [null, false, true] - } - - def "PBS should failed cache and update prebid_cache.vtrack.write.err metric when cache service respond with invalid status code"() { - given: "Current value of metric prebid_cache.requests.ok" - def okInitialValue = getCurrentMetricValue(defaultPbsService, VTRACK_WRITE_ERROR_METRIC) - - and: "Default VtrackRequest" - def accountId = PBSUtils.randomNumber.toString() - def creative = encodeXml(Vast.getDefaultVastModel(PBSUtils.randomString)) - def request = VtrackRequest.getDefaultVtrackRequest(creative) - - and: "Create and save enabled events config in account" - def account = new Account().tap { - it.uuid = accountId - it.config = new AccountConfig().tap { - it.auction = new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: true)) - } - } - accountDao.save(account) - - and: "Flush metrics" - flushMetrics(defaultPbsService) - - and: "Resent cache and set up invalid response" - prebidCache.reset() - prebidCache.setInvalidPostResponse() - - when: "PBS processes vtrack request" - defaultPbsService.sendPostVtrackRequest(request, accountId) - - then: "PBS throws an exception" - def exception = thrown(PrebidServerException) - assert exception.statusCode == 500 - assert exception.responseBody.contains("Error occurred while sending request to cache: HTTP status code 500") - - then: "prebid_cache.vtrack.write.err metric should be updated" - def metrics = defaultPbsService.sendCollectedMetricsRequest() - assert metrics[VTRACK_WRITE_ERROR_METRIC] == okInitialValue + 1 - - and: "account..prebid_cache.vtrack.write.err should be updated" - assert metrics[ACCOUNT_VTRACK_WRITE_ERR_METRIC.formatted(accountId)] == 1 - - cleanup: - prebidCache.reset() - } - - def "PBS should return 400 status code when get vtrack request without uuid"() { - when: "PBS processes get vtrack request" - defaultPbsService.sendGetVtrackRequest(null) - - then: "Request should fail with an error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == BAD_REQUEST.code() - assert exception.responseBody == "'uuid' is a required query parameter and can't be empty" - - cleanup: - prebidCache.reset(CACHE_ENDPOINT) - } - - def "PBS should return 200 status code when get vtrack request contain uuid"() { - given: "Random uuid" - def uuid = UUID.randomUUID().toString() - - and: "Cache set up successful response" - prebidCache.setVtrackResponse(uuid) - - when: "PBS processes get vtrack request" - def response = defaultPbsService.sendGetVtrackRequest(uuid) - - then: "Response body should contain 200 status code" - assert response == HttpStatusCode.OK_200.code() - - and: "Metrics should contain ok metric" - def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() - assert metricsRequest[VTRACK_READ_OK_METRIC] == 1 - - cleanup: - prebidCache.reset(CACHE_ENDPOINT) - } - - def "PBS should return status code that came from pbc when get vtrack request and response from pbc invalid"() { - given: "Random uuid" - def uuid = UUID.randomUUID().toString() - - and: "Cache set up invalid response" - prebidCache.setInvalidVtrackResponse(uuid) - - when: "PBS processes get vtrack request" - defaultPbsService.sendGetVtrackRequest(uuid) - - then: "Request should fail with an error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == INTERNAL_SERVER_ERROR.code() - assert exception.responseBody == "Error occurred while sending request to cache: Cannot parse response: " - - and: "Metrics should contain error metric" - def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() - assert metricsRequest[VTRACK_READ_ERROR_METRIC] == 1 - - cleanup: "Clean cache mock response" - prebidCache.reset(CACHE_ENDPOINT) - } - - def "PBS should return 200 status code when get vtrack request with uuid and ch"() { - given: "Current value of metric prebid_cache.vtrack.read.ok" - def initialValue = getCurrentMetricValue(defaultPbsService, VTRACK_READ_OK_METRIC) - - and: "Clean cache mock response" - prebidCache.reset(CACHE_ENDPOINT) - - and: "Random uuid and cache host" - def uuid = UUID.randomUUID().toString() - def cacheHost = PBSUtils.randomString - - and: "Clean up and set up successful response" - prebidCache.setVtrackResponse(uuid) - - when: "PBS processes get vtrack request" - def response = defaultPbsService.sendGetVtrackRequest(uuid, cacheHost) - - then: "Response body should contain 200 status code" - assert response == HttpStatusCode.OK_200.code() - - and: "Metrics should contain ok metrics" - def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() - assert metricsRequest[VTRACK_READ_OK_METRIC] == initialValue + 1 - - cleanup: "Clean cache mock response" - prebidCache.reset(CACHE_ENDPOINT) - } - - def "PBS should return 200 status code when internal cache configured and get vtrack request with uuid and ch"() { - given: "Current value of metric prebid_cache.vtrack.read.ok" - def initialValue = getCurrentMetricValue(pbsServiceWithInternalCache, VTRACK_READ_OK_METRIC) - - and: "Clean cache mock response" - prebidCache.reset(CACHE_ENDPOINT) - - and: "Flush metric" - flushMetrics(pbsServiceWithInternalCache) - - and: "Random uuid and cache host" - def uuid = UUID.randomUUID().toString() - def cacheHost = PBSUtils.randomString - - and: "Clean up and set up successful response" - prebidCache.setVtrackResponse(uuid) - - when: "PBS processes get vtrack request" - def response = pbsServiceWithInternalCache.sendGetVtrackRequest(uuid, cacheHost) - - then: "Response body should contain 200 status code" - assert response == HttpStatusCode.OK_200.code() - - and: "Metrics should contain ok metrics" - def metricsRequest = pbsServiceWithInternalCache.sendCollectedMetricsRequest() - assert metricsRequest[VTRACK_READ_OK_METRIC] == initialValue + 1 - - cleanup: "Clean cache mock response" - prebidCache.reset(CACHE_ENDPOINT) - } - - def "PBS should return 200 status code when internal cache and get vtrack request contain uuid"() { - given: "Current value of metric prebid_cache.vtrack.read.ok" - def initialValue = getCurrentMetricValue(pbsServiceWithInternalCache, VTRACK_READ_OK_METRIC) - - and: "Random uuid" - def uuid = UUID.randomUUID().toString() - - and: "Cache set up successful response" - prebidCache.setVtrackResponse(uuid) - - and: "Flush metric" - flushMetrics(pbsServiceWithInternalCache) - - when: "PBS processes get vtrack request" - def response = pbsServiceWithInternalCache.sendGetVtrackRequest(uuid) - - then: "Response body should contain 200 status code" - assert response == HttpStatusCode.OK_200.code() - - and: "Metrics should contain ok metrics" - def metricsRequest = pbsServiceWithInternalCache.sendCollectedMetricsRequest() - assert metricsRequest[VTRACK_READ_OK_METRIC] == initialValue + 1 - - cleanup: - prebidCache.reset(CACHE_ENDPOINT) - } - - def "PBS should return status code that came from pbc when internal cache and get vtrack request and response from pbc invalid"() { - given: "Random uuid" - def uuid = UUID.randomUUID().toString() - - and: "Cache set up invalid response" - prebidCache.setInvalidVtrackResponse(uuid) - - and: "Flush metric" - flushMetrics(pbsServiceWithInternalCache) - - when: "PBS processes get vtrack request" - pbsServiceWithInternalCache.sendGetVtrackRequest(uuid) - - then: "Request should fail with an error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == INTERNAL_SERVER_ERROR.code() - assert exception.responseBody == "Error occurred while sending request to cache: Cannot parse response: " - - and: "Metrics should contain error metric" - def metricsRequest = pbsServiceWithInternalCache.sendCollectedMetricsRequest() - assert metricsRequest[VTRACK_READ_ERROR_METRIC] == 1 - - cleanup: "Clean cache mock response" - prebidCache.reset(CACHE_ENDPOINT) - } - - def "PBS should return 400 status code when internal cache and get vtrack request without uuid"() { - when: "PBS processes get vtrack request" - pbsServiceWithInternalCache.sendGetVtrackRequest(null) - - then: "Request should fail with an error" - def exception = thrown(PrebidServerException) - assert exception.statusCode == BAD_REQUEST.code() - assert exception.responseBody == "'uuid' is a required query parameter and can't be empty" - - cleanup: - prebidCache.reset(CACHE_ENDPOINT) } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy new file mode 100644 index 00000000000..43be654b71f --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy @@ -0,0 +1,390 @@ +package org.prebid.server.functional.tests + +import org.mockserver.model.HttpStatusCode +import org.prebid.server.functional.model.config.AccountAuctionConfig +import org.prebid.server.functional.model.config.AccountCacheConfig +import org.prebid.server.functional.model.config.AccountConfig +import org.prebid.server.functional.model.config.AccountEventsConfig +import org.prebid.server.functional.model.db.Account +import org.prebid.server.functional.model.request.vtrack.VtrackRequest +import org.prebid.server.functional.model.request.vtrack.xml.Vast +import org.prebid.server.functional.service.PrebidServerException +import org.prebid.server.functional.service.PrebidServerService +import org.prebid.server.functional.util.PBSUtils + +import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST +import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR +import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer + +class CacheVtrackSpec extends BaseSpec { + + private static final String ACCOUNT_VTRACK_XML_CREATIVE_SIZE_METRIC = "account.%s.prebid_cache.vtrack.creative_size.xml" + private static final String ACCOUNT_VTRACK_CREATIVE_TTL_XML_METRIC = "account.%s.prebid_cache.vtrack.creative_ttl.xml" + private static final String ACCOUNT_VTRACK_WRITE_ERR_METRIC = "account.%s.prebid_cache.vtrack.write.err" + private static final String ACCOUNT_VTRACK_WRITE_OK_METRIC = "account.%s.prebid_cache.vtrack.write.ok" + + private static final String VTRACK_XML_CREATIVE_SIZE_METRIC = "prebid_cache.vtrack.creative_size.xml" + private static final String VTRACK_XML_CREATIVE_TTL_METRIC = "prebid_cache.vtrack.creative_ttl.xml" + private static final String VTRACK_WRITE_OK_METRIC = "prebid_cache.vtrack.write.ok" + private static final String VTRACK_WRITE_ERROR_METRIC = "prebid_cache.vtrack.write.err" + private static final String VTRACK_READ_OK_METRIC = "prebid_cache.vtrack.read.ok" + private static final String VTRACK_READ_ERROR_METRIC = "prebid_cache.vtrack.read.err" + + private static final String CACHE_ENDPOINT = "/cache" + private static final Map VALID_INTERNAL_CACHE = ["cache.internal.scheme": "http", + "cache.internal.host" : "$networkServiceContainer.hostAndPort".toString(), + "cache.internal.path" : "/cache"] + private static PrebidServerService pbsServiceWithInternalCache + + def setupSpec() { + pbsServiceWithInternalCache = pbsServiceFactory.getService(VALID_INTERNAL_CACHE) + } + + def cleanupSpec() { + pbsServiceFactory.removeContainer(VALID_INTERNAL_CACHE) + } + + def "PBS should return 400 status code when get vtrack request without uuid"() { + when: "PBS processes get vtrack request" + defaultPbsService.sendGetVtrackRequest(null) + + then: "Request should fail with an error" + def exception = thrown(PrebidServerException) + assert exception.statusCode == BAD_REQUEST.code() + assert exception.responseBody == "'uuid' is a required query parameter and can't be empty" + + cleanup: + prebidCache.reset(CACHE_ENDPOINT) + } + + def "PBS should return 200 status code when get vtrack request contain uuid"() { + given: "Random uuid" + def uuid = UUID.randomUUID().toString() + + and: "Cache set up successful response" + prebidCache.setVtrackResponse(uuid) + + when: "PBS processes get vtrack request" + def response = defaultPbsService.sendGetVtrackRequest(uuid) + + then: "Response body should contain 200 status code" + assert response == HttpStatusCode.OK_200.code() + + and: "Metrics should contain ok metric" + def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() + assert metricsRequest[VTRACK_READ_OK_METRIC] == 1 + + cleanup: + prebidCache.reset(CACHE_ENDPOINT) + } + + def "PBS should return status code that came from pbc when get vtrack request and response from pbc invalid"() { + given: "Random uuid" + def uuid = UUID.randomUUID().toString() + + and: "Cache set up invalid response" + prebidCache.setInvalidVtrackResponse(uuid) + + when: "PBS processes get vtrack request" + defaultPbsService.sendGetVtrackRequest(uuid) + + then: "Request should fail with an error" + def exception = thrown(PrebidServerException) + assert exception.statusCode == INTERNAL_SERVER_ERROR.code() + assert exception.responseBody == "Error occurred while sending request to cache: Cannot parse response: " + + and: "Metrics should contain error metric" + def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() + assert metricsRequest[VTRACK_READ_ERROR_METRIC] == 1 + + cleanup: "Clean cache mock response" + prebidCache.reset(CACHE_ENDPOINT) + } + + def "PBS should return 200 status code when get vtrack request with uuid and ch"() { + given: "Current value of metric prebid_cache.vtrack.read.ok" + def initialValue = getCurrentMetricValue(defaultPbsService, VTRACK_READ_OK_METRIC) + + and: "Clean cache mock response" + prebidCache.reset(CACHE_ENDPOINT) + + and: "Random uuid and cache host" + def uuid = UUID.randomUUID().toString() + def cacheHost = PBSUtils.randomString + + and: "Clean up and set up successful response" + prebidCache.setVtrackResponse(uuid) + + when: "PBS processes get vtrack request" + def response = defaultPbsService.sendGetVtrackRequest(uuid, cacheHost) + + then: "Response body should contain 200 status code" + assert response == HttpStatusCode.OK_200.code() + + and: "Metrics should contain ok metrics" + def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() + assert metricsRequest[VTRACK_READ_OK_METRIC] == initialValue + 1 + + cleanup: "Clean cache mock response" + prebidCache.reset(CACHE_ENDPOINT) + } + + def "PBS should return 200 status code when internal cache configured and get vtrack request with uuid and ch"() { + given: "Current value of metric prebid_cache.vtrack.read.ok" + def initialValue = getCurrentMetricValue(pbsServiceWithInternalCache, VTRACK_READ_OK_METRIC) + + and: "Clean cache mock response" + prebidCache.reset(CACHE_ENDPOINT) + + and: "Flush metric" + flushMetrics(pbsServiceWithInternalCache) + + and: "Random uuid and cache host" + def uuid = UUID.randomUUID().toString() + def cacheHost = PBSUtils.randomString + + and: "Clean up and set up successful response" + prebidCache.setVtrackResponse(uuid) + + when: "PBS processes get vtrack request" + def response = pbsServiceWithInternalCache.sendGetVtrackRequest(uuid, cacheHost) + + then: "Response body should contain 200 status code" + assert response == HttpStatusCode.OK_200.code() + + and: "Metrics should contain ok metrics" + def metricsRequest = pbsServiceWithInternalCache.sendCollectedMetricsRequest() + assert metricsRequest[VTRACK_READ_OK_METRIC] == initialValue + 1 + + cleanup: "Clean cache mock response" + prebidCache.reset(CACHE_ENDPOINT) + } + + def "PBS should return 200 status code when internal cache and get vtrack request contain uuid"() { + given: "Current value of metric prebid_cache.vtrack.read.ok" + def initialValue = getCurrentMetricValue(pbsServiceWithInternalCache, VTRACK_READ_OK_METRIC) + + and: "Random uuid" + def uuid = UUID.randomUUID().toString() + + and: "Cache set up successful response" + prebidCache.setVtrackResponse(uuid) + + and: "Flush metric" + flushMetrics(pbsServiceWithInternalCache) + + when: "PBS processes get vtrack request" + def response = pbsServiceWithInternalCache.sendGetVtrackRequest(uuid) + + then: "Response body should contain 200 status code" + assert response == HttpStatusCode.OK_200.code() + + and: "Metrics should contain ok metrics" + def metricsRequest = pbsServiceWithInternalCache.sendCollectedMetricsRequest() + assert metricsRequest[VTRACK_READ_OK_METRIC] == initialValue + 1 + + cleanup: + prebidCache.reset(CACHE_ENDPOINT) + } + + def "PBS should return status code that came from pbc when internal cache and get vtrack request and response from pbc invalid"() { + given: "Random uuid" + def uuid = UUID.randomUUID().toString() + + and: "Cache set up invalid response" + prebidCache.setInvalidVtrackResponse(uuid) + + and: "Flush metric" + flushMetrics(pbsServiceWithInternalCache) + + when: "PBS processes get vtrack request" + pbsServiceWithInternalCache.sendGetVtrackRequest(uuid) + + then: "Request should fail with an error" + def exception = thrown(PrebidServerException) + assert exception.statusCode == INTERNAL_SERVER_ERROR.code() + assert exception.responseBody == "Error occurred while sending request to cache: Cannot parse response: " + + and: "Metrics should contain error metric" + def metricsRequest = pbsServiceWithInternalCache.sendCollectedMetricsRequest() + assert metricsRequest[VTRACK_READ_ERROR_METRIC] == 1 + + cleanup: "Clean cache mock response" + prebidCache.reset(CACHE_ENDPOINT) + } + + def "PBS should return 400 status code when internal cache and get vtrack request without uuid"() { + when: "PBS processes get vtrack request" + pbsServiceWithInternalCache.sendGetVtrackRequest(null) + + then: "Request should fail with an error" + def exception = thrown(PrebidServerException) + assert exception.statusCode == BAD_REQUEST.code() + assert exception.responseBody == "'uuid' is a required query parameter and can't be empty" + + cleanup: + prebidCache.reset(CACHE_ENDPOINT) + } + + def "PBS should update prebid_cache.creative_size.xml metric when xml creative is received"() { + given: "Current value of metric prebid_cache.requests.ok" + def initialValue = getCurrentMetricValue(defaultPbsService, VTRACK_WRITE_OK_METRIC) + + and: "Cache set up response" + prebidCache.setResponse() + + and: "Default VtrackRequest" + def accountId = PBSUtils.randomNumber.toString() + def creative = encodeXml(Vast.getDefaultVastModel(PBSUtils.randomString)) + def request = VtrackRequest.getDefaultVtrackRequest(creative) + + and: "Flush metrics" + flushMetrics(defaultPbsService) + + when: "PBS processes vtrack request" + defaultPbsService.sendPostVtrackRequest(request, accountId) + + then: "prebid_cache.vtrack.creative_size.xml metric should be updated" + def metrics = defaultPbsService.sendCollectedMetricsRequest() + def creativeSize = creative.bytes.length + assert metrics[VTRACK_WRITE_OK_METRIC] == initialValue + 1 + assert metrics[VTRACK_XML_CREATIVE_SIZE_METRIC] == creativeSize + + and: "account..prebid_cache.creative_size.xml should be updated" + assert metrics[ACCOUNT_VTRACK_WRITE_OK_METRIC.formatted(accountId)] == 1 + assert metrics[ACCOUNT_VTRACK_XML_CREATIVE_SIZE_METRIC.formatted(accountId)] == creativeSize + } + + def "PBS should update prebid_cache.creative_size.xml metric and adding tracking xml when xml creative contain #wrapper and impression are valid xml value"() { + given: "Current value of metric prebid_cache.vtrack.write.ok" + def initialOkVTrackValue = getCurrentMetricValue(defaultPbsService, VTRACK_WRITE_OK_METRIC) + + and: "Create and save enabled events config in account" + def accountId = PBSUtils.randomNumber.toString() + def account = new Account().tap { + uuid = accountId + config = new AccountConfig().tap { + auction = new AccountAuctionConfig(events: new AccountEventsConfig(enabled: true)) + } + } + accountDao.save(account) + + and: "Vtrack request with custom tags" + def payload = PBSUtils.randomString + def creative = "<${wrapper}>prebid.org wrapper" + + "<![CDATA[//${payload}]]>" + + "<${impression}> <![CDATA[ ]]> " + def request = VtrackRequest.getDefaultVtrackRequest(creative) + + and: "Flush metrics" + flushMetrics(defaultPbsService) + + when: "PBS processes vtrack request" + defaultPbsService.sendPostVtrackRequest(request, accountId) + + then: "Vast xml is modified" + def prebidCacheRequest = prebidCache.getXmlRecordedRequestsBody(payload) + assert prebidCacheRequest.size() == 1 + assert prebidCacheRequest[0].contains("/event?t=imp&b=${request.puts[0].bidid}&a=$accountId&bidder=${request.puts[0].bidder}") + + and: "prebid_cache.creative_size.xml metric should be updated" + def metrics = defaultPbsService.sendCollectedMetricsRequest() + def ttlSeconds = request.puts[0].ttlseconds + assert metrics[VTRACK_WRITE_OK_METRIC] == initialOkVTrackValue + 1 + assert metrics[VTRACK_XML_CREATIVE_TTL_METRIC] == ttlSeconds + + and: "account..prebid_cache.vtrack.creative_size.xml should be updated" + assert metrics[ACCOUNT_VTRACK_WRITE_OK_METRIC.formatted(accountId) as String] == 1 + assert metrics[ACCOUNT_VTRACK_CREATIVE_TTL_XML_METRIC.formatted(accountId) as String] == ttlSeconds + + where: + wrapper | impression + " wrapper " | " impression " + PBSUtils.getRandomCase(" wrapper ") | PBSUtils.getRandomCase(" impression ") + " wraPPer ${PBSUtils.getRandomString()} " | " imPreSSion ${PBSUtils.getRandomString()}" + " inLine " | " ImpreSSion $PBSUtils.randomNumber" + PBSUtils.getRandomCase(" inline ") | " ${PBSUtils.getRandomCase(" impression ")} $PBSUtils.randomNumber " + " inline ${PBSUtils.getRandomString()} " | " ImpreSSion " + } + + def "PBS should update prebid_cache.creative_size.xml metric when account cache config #enabledCacheConcfig"() { + given: "Current value of metric prebid_cache.requests.ok" + def okInitialValue = getCurrentMetricValue(defaultPbsService, VTRACK_WRITE_OK_METRIC) + + and: "Default VtrackRequest" + def accountId = PBSUtils.randomNumber.toString() + def creative = encodeXml(Vast.getDefaultVastModel(PBSUtils.randomString)) + def request = VtrackRequest.getDefaultVtrackRequest(creative) + + and: "Create and save enabled events config in account" + def account = new Account().tap { + it.uuid = accountId + it.config = new AccountConfig().tap { + it.auction = new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: enabledCacheConcfig)) + } + } + accountDao.save(account) + + and: "Flush metrics" + flushMetrics(defaultPbsService) + + when: "PBS processes vtrack request" + defaultPbsService.sendPostVtrackRequest(request, accountId) + + then: "prebid_cache.creative_size.xml metric should be updated" + def metrics = defaultPbsService.sendCollectedMetricsRequest() + def creativeSize = creative.bytes.length + assert metrics[VTRACK_WRITE_OK_METRIC] == okInitialValue + 1 + + and: "account..prebid_cache.creative_size.xml should be updated" + assert metrics[ACCOUNT_VTRACK_WRITE_OK_METRIC.formatted(accountId)] == 1 + assert metrics[ACCOUNT_VTRACK_XML_CREATIVE_SIZE_METRIC.formatted(accountId)] == creativeSize + + where: + enabledCacheConcfig << [null, false, true] + } + + def "PBS should failed cache and update prebid_cache.vtrack.write.err metric when cache service respond with invalid status code"() { + given: "Current value of metric prebid_cache.requests.ok" + def okInitialValue = getCurrentMetricValue(defaultPbsService, VTRACK_WRITE_ERROR_METRIC) + + and: "Default VtrackRequest" + def accountId = PBSUtils.randomNumber.toString() + def creative = encodeXml(Vast.getDefaultVastModel(PBSUtils.randomString)) + def request = VtrackRequest.getDefaultVtrackRequest(creative) + + and: "Create and save enabled events config in account" + def account = new Account().tap { + it.uuid = accountId + it.config = new AccountConfig().tap { + it.auction = new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: true)) + } + } + accountDao.save(account) + + and: "Flush metrics" + flushMetrics(defaultPbsService) + + and: "Resent cache and set up invalid response" + prebidCache.reset() + prebidCache.setInvalidPostResponse() + + when: "PBS processes vtrack request" + defaultPbsService.sendPostVtrackRequest(request, accountId) + + then: "PBS throws an exception" + def exception = thrown(PrebidServerException) + assert exception.statusCode == 500 + assert exception.responseBody.contains("Error occurred while sending request to cache: HTTP status code 500") + + then: "prebid_cache.vtrack.write.err metric should be updated" + def metrics = defaultPbsService.sendCollectedMetricsRequest() + assert metrics[VTRACK_WRITE_ERROR_METRIC] == okInitialValue + 1 + + and: "account..prebid_cache.vtrack.write.err should be updated" + assert metrics[ACCOUNT_VTRACK_WRITE_ERR_METRIC.formatted(accountId)] == 1 + + cleanup: + prebidCache.reset() + } +} From 82b8b319260a741a7e5f416acbdaced28ece6bca Mon Sep 17 00:00:00 2001 From: markiian Date: Tue, 14 Oct 2025 19:34:55 +0300 Subject: [PATCH 10/16] Update after review --- .../service/PrebidServerService.groovy | 22 ++--------- .../scaffolding/PrebidCache.groovy | 5 +++ .../server/functional/tests/CacheSpec.groovy | 21 +++++++--- .../functional/tests/CacheVtrackSpec.groovy | 38 +++++++++++++------ 4 files changed, 52 insertions(+), 34 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy index 85cf21914af..88813a7f1e6 100644 --- a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy +++ b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy @@ -222,28 +222,14 @@ class PrebidServerService implements ObjectMapperWrapper { decode(response.body.asString(), PrebidCacheResponse) } - int sendGetVtrackRequest(String uuid, String cacheHost = null) { - def requestSpecification = given(requestSpecification) - setUpUuidIfPresent(uuid, requestSpecification) - setUpCacheHostIfPresent(cacheHost, requestSpecification) - - def response = requestSpecification.get(VTRACK_ENDPOINT) + int sendGetVtrackRequest(Map parameters) { + def response = given(requestSpecification) + .queryParams(parameters) + .get(VTRACK_ENDPOINT) checkResponseStatusCode(response) response.statusCode() } - private static void setUpUuidIfPresent(String uuid, RequestSpecification requestSpecification) { - if (uuid != null) { - requestSpecification.queryParam("uuid", uuid) - } - } - - private static void setUpCacheHostIfPresent(String cacheHost, RequestSpecification requestSpecification) { - if (cacheHost != null) { - requestSpecification.queryParam("ch", cacheHost) - } - } - StatusResponse sendStatusRequest() { def response = given(requestSpecification).get(STATUS_ENDPOINT) diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy index ad0636c923f..18d7435072f 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy @@ -25,6 +25,11 @@ class PrebidCache extends NetworkScaffolding { super(mockServerContainer, CACHE_ENDPOINT) } + int getVTracGetRequestCount() { + getRequestCount(request().withMethod("GET") + .withPath(CACHE_ENDPOINT)) + } + void setXmlCacheResponse(String payload, PrebidCacheResponse prebidCacheResponse) { setResponse(getXmlCacheRequest(payload), prebidCacheResponse) } diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy index f8b2b975514..d6ea45d74bc 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy @@ -10,7 +10,6 @@ import org.prebid.server.functional.model.request.auction.Imp import org.prebid.server.functional.model.request.auction.Targeting import org.prebid.server.functional.model.response.auction.Adm import org.prebid.server.functional.model.response.auction.BidResponse -import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.util.PBSUtils import static org.prebid.server.functional.model.response.auction.ErrorType.CACHE @@ -486,13 +485,19 @@ class CacheSpec extends BaseSpec { } def "PBS shouldn't cache bids when targeting is specified and config cache is invalid"() { - given: "Default BidRequest with cache, targeting" + given: "Pbs config with cache" + def INVALID_PREBID_CACHE_CONFIG = ["cache.path" : CACHE_PATH, + "cache.scheme": HTTP_SCHEME, + "cache.host" : CACHE_HOST] + def pbsService = pbsServiceFactory.getService(INVALID_PREBID_CACHE_CONFIG) + + and: "Default BidRequest with cache, targeting" def bidRequest = BidRequest.defaultBidRequest.tap { it.enableCache() } when: "PBS processes auction request" - def bidResponse = pbsServiceWithInvalidCache.sendAuctionRequest(bidRequest) + def bidResponse = pbsService.sendAuctionRequest(bidRequest) then: "Response should contain error" assert bidResponse.ext?.errors[CACHE]*.code == [999] @@ -506,13 +511,19 @@ class CacheSpec extends BaseSpec { } def "PBS should cache bids and emit error when targeting is specified and config cache is valid and internal is invalid"() { - given: "Default BidRequest with cache, targeting" + given: "Pbs config with cache" + def INVALID_PREBID_CACHE_CONFIG = ["cache.internal.path" : CACHE_PATH, + "cache.internal.scheme": HTTP_SCHEME, + "cache.internal.host" : CACHE_HOST] + def pbsService = pbsServiceFactory.getService(INVALID_PREBID_CACHE_CONFIG) + + and: "Default BidRequest with cache, targeting" def bidRequest = BidRequest.defaultBidRequest.tap { it.enableCache() } when: "PBS processes auction request" - def bidResponse = pbsServiceWithInvalidCache.sendAuctionRequest(bidRequest) + def bidResponse = pbsService.sendAuctionRequest(bidRequest) then: "PBS should call PBC" assert prebidCache.getRequestCount(bidRequest.imp[0].id) == 0 diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy index 43be654b71f..1ed9914f5ff 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy @@ -31,22 +31,29 @@ class CacheVtrackSpec extends BaseSpec { private static final String VTRACK_READ_ERROR_METRIC = "prebid_cache.vtrack.read.err" private static final String CACHE_ENDPOINT = "/cache" + private static final String CACHE_PATH = "/${PBSUtils.randomString}".toString() + private static final String CACHE_HOST = "${PBSUtils.randomString}:${PBSUtils.getRandomNumber(0, 65535)}".toString() + private static final String HTTP_SCHEME = 'http' + + private static final Map INVALID_PREBID_CACHE_CONFIG = ["cache.path" : CACHE_PATH, + "cache.scheme": HTTP_SCHEME, + "cache.host" : CACHE_HOST] private static final Map VALID_INTERNAL_CACHE = ["cache.internal.scheme": "http", "cache.internal.host" : "$networkServiceContainer.hostAndPort".toString(), "cache.internal.path" : "/cache"] private static PrebidServerService pbsServiceWithInternalCache def setupSpec() { - pbsServiceWithInternalCache = pbsServiceFactory.getService(VALID_INTERNAL_CACHE) + pbsServiceWithInternalCache = pbsServiceFactory.getService(VALID_INTERNAL_CACHE + INVALID_PREBID_CACHE_CONFIG) } def cleanupSpec() { - pbsServiceFactory.removeContainer(VALID_INTERNAL_CACHE) + pbsServiceFactory.removeContainer(VALID_INTERNAL_CACHE + INVALID_PREBID_CACHE_CONFIG) } def "PBS should return 400 status code when get vtrack request without uuid"() { when: "PBS processes get vtrack request" - defaultPbsService.sendGetVtrackRequest(null) + defaultPbsService.sendGetVtrackRequest(["uuid": null]) then: "Request should fail with an error" def exception = thrown(PrebidServerException) @@ -65,7 +72,7 @@ class CacheVtrackSpec extends BaseSpec { prebidCache.setVtrackResponse(uuid) when: "PBS processes get vtrack request" - def response = defaultPbsService.sendGetVtrackRequest(uuid) + def response = defaultPbsService.sendGetVtrackRequest(["uuid": uuid]) then: "Response body should contain 200 status code" assert response == HttpStatusCode.OK_200.code() @@ -86,7 +93,7 @@ class CacheVtrackSpec extends BaseSpec { prebidCache.setInvalidVtrackResponse(uuid) when: "PBS processes get vtrack request" - defaultPbsService.sendGetVtrackRequest(uuid) + defaultPbsService.sendGetVtrackRequest(["uuid": uuid]) then: "Request should fail with an error" def exception = thrown(PrebidServerException) @@ -116,7 +123,7 @@ class CacheVtrackSpec extends BaseSpec { prebidCache.setVtrackResponse(uuid) when: "PBS processes get vtrack request" - def response = defaultPbsService.sendGetVtrackRequest(uuid, cacheHost) + def response = defaultPbsService.sendGetVtrackRequest(["uuid": uuid, cacheHost: cacheHost]) then: "Response body should contain 200 status code" assert response == HttpStatusCode.OK_200.code() @@ -147,7 +154,7 @@ class CacheVtrackSpec extends BaseSpec { prebidCache.setVtrackResponse(uuid) when: "PBS processes get vtrack request" - def response = pbsServiceWithInternalCache.sendGetVtrackRequest(uuid, cacheHost) + def response = pbsServiceWithInternalCache.sendGetVtrackRequest(["uuid": uuid, "cacheHost": cacheHost]) then: "Response body should contain 200 status code" assert response == HttpStatusCode.OK_200.code() @@ -156,6 +163,9 @@ class CacheVtrackSpec extends BaseSpec { def metricsRequest = pbsServiceWithInternalCache.sendCollectedMetricsRequest() assert metricsRequest[VTRACK_READ_OK_METRIC] == initialValue + 1 + and: "VTrack should call internal cache" + assert prebidCache.getVTracGetRequestCount() == 1 + cleanup: "Clean cache mock response" prebidCache.reset(CACHE_ENDPOINT) } @@ -174,7 +184,7 @@ class CacheVtrackSpec extends BaseSpec { flushMetrics(pbsServiceWithInternalCache) when: "PBS processes get vtrack request" - def response = pbsServiceWithInternalCache.sendGetVtrackRequest(uuid) + def response = pbsServiceWithInternalCache.sendGetVtrackRequest(["uuid": uuid]) then: "Response body should contain 200 status code" assert response == HttpStatusCode.OK_200.code() @@ -183,6 +193,9 @@ class CacheVtrackSpec extends BaseSpec { def metricsRequest = pbsServiceWithInternalCache.sendCollectedMetricsRequest() assert metricsRequest[VTRACK_READ_OK_METRIC] == initialValue + 1 + and: "VTrack should call internal cache" + assert prebidCache.getVTracGetRequestCount() == 1 + cleanup: prebidCache.reset(CACHE_ENDPOINT) } @@ -198,7 +211,7 @@ class CacheVtrackSpec extends BaseSpec { flushMetrics(pbsServiceWithInternalCache) when: "PBS processes get vtrack request" - pbsServiceWithInternalCache.sendGetVtrackRequest(uuid) + pbsServiceWithInternalCache.sendGetVtrackRequest(["uuid": uuid]) then: "Request should fail with an error" def exception = thrown(PrebidServerException) @@ -209,13 +222,16 @@ class CacheVtrackSpec extends BaseSpec { def metricsRequest = pbsServiceWithInternalCache.sendCollectedMetricsRequest() assert metricsRequest[VTRACK_READ_ERROR_METRIC] == 1 + and: "VTrack should call internal cache" + assert prebidCache.getVTracGetRequestCount() == 1 + cleanup: "Clean cache mock response" prebidCache.reset(CACHE_ENDPOINT) } def "PBS should return 400 status code when internal cache and get vtrack request without uuid"() { when: "PBS processes get vtrack request" - pbsServiceWithInternalCache.sendGetVtrackRequest(null) + pbsServiceWithInternalCache.sendGetVtrackRequest(["uuid": null]) then: "Request should fail with an error" def exception = thrown(PrebidServerException) @@ -365,7 +381,7 @@ class CacheVtrackSpec extends BaseSpec { and: "Flush metrics" flushMetrics(defaultPbsService) - and: "Resent cache and set up invalid response" + and: "Reset cache and set up invalid response" prebidCache.reset() prebidCache.setInvalidPostResponse() From 54ce21f3bc9765e42249ce524547bf7eec805801 Mon Sep 17 00:00:00 2001 From: markiian Date: Wed, 15 Oct 2025 16:44:32 +0300 Subject: [PATCH 11/16] Minor update --- .../service/PrebidServerService.groovy | 36 +++++++++++-------- .../scaffolding/PrebidCache.groovy | 2 +- .../server/functional/tests/CacheSpec.groovy | 6 ++++ .../functional/tests/CacheVtrackSpec.groovy | 10 +++--- 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy index 88813a7f1e6..308ced6ee24 100644 --- a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy +++ b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy @@ -28,6 +28,7 @@ import org.prebid.server.functional.model.response.getuids.GetuidResponse import org.prebid.server.functional.model.response.infobidders.BidderInfoResponse import org.prebid.server.functional.model.response.setuid.SetuidResponse import org.prebid.server.functional.model.response.status.StatusResponse + import org.prebid.server.functional.testcontainers.container.PrebidServerContainer import org.prebid.server.functional.util.ObjectMapperWrapper import org.prebid.server.functional.util.PBSUtils @@ -41,6 +42,7 @@ import java.time.format.DateTimeFormatter import static io.restassured.RestAssured.given import static java.time.ZoneOffset.UTC +import static org.mockserver.model.HttpStatusCode.OK_200 class PrebidServerService implements ObjectMapperWrapper { @@ -73,7 +75,7 @@ class PrebidServerService implements ObjectMapperWrapper { authenticationScheme.password = pbsContainer.ADMIN_ENDPOINT_PASSWORD this.pbsContainer = pbsContainer requestSpecification = new RequestSpecBuilder().setBaseUri(pbsContainer.rootUri) - .build() + .build() adminRequestSpecification = buildAndGetRequestSpecification(pbsContainer.adminRootUri, authenticationScheme) prometheusRequestSpecification = buildAndGetRequestSpecification(pbsContainer.prometheusRootUri, authenticationScheme) } @@ -198,7 +200,7 @@ class PrebidServerService implements ObjectMapperWrapper { def uidsCookieAsEncodedJson = Base64.urlEncoder.encodeToString(uidsCookieAsJson.bytes) def response = given(requestSpecification).cookie(UIDS_COOKIE_NAME, uidsCookieAsEncodedJson) - .get(GET_UIDS_ENDPOINT) + .get(GET_UIDS_ENDPOINT) checkResponseStatusCode(response) decode(response.body.asString(), GetuidResponse) @@ -206,8 +208,8 @@ class PrebidServerService implements ObjectMapperWrapper { byte[] sendEventRequest(EventRequest eventRequest, Map headers = [:]) { def response = given(requestSpecification).headers(headers) - .queryParams(toMap(eventRequest)) - .get(EVENT_ENDPOINT) + .queryParams(toMap(eventRequest)) + .get(EVENT_ENDPOINT) checkResponseStatusCode(response) response.body.asByteArray() @@ -215,8 +217,8 @@ class PrebidServerService implements ObjectMapperWrapper { PrebidCacheResponse sendPostVtrackRequest(VtrackRequest request, String account) { def response = given(requestSpecification).queryParam("a", account) - .body(request) - .post(VTRACK_ENDPOINT) + .body(request) + .post(VTRACK_ENDPOINT) checkResponseStatusCode(response) decode(response.body.asString(), PrebidCacheResponse) @@ -226,8 +228,14 @@ class PrebidServerService implements ObjectMapperWrapper { def response = given(requestSpecification) .queryParams(parameters) .get(VTRACK_ENDPOINT) - checkResponseStatusCode(response) - response.statusCode() + + def responseStatusCode = response.statusCode + if (responseStatusCode != OK_200.code()) { + def responseBody = response.body.asString() + log.error(responseBody) + throw new PrebidServerException(responseStatusCode, responseBody, getHeaders(response)) + } + responseStatusCode } StatusResponse sendStatusRequest() { @@ -275,7 +283,7 @@ class PrebidServerService implements ObjectMapperWrapper { String sendLoggingHttpInteractionRequest(HttpInteractionRequest httpInteractionRequest) { def response = given(adminRequestSpecification).queryParams(toMap(httpInteractionRequest)) - .get(HTTP_INTERACTION_ENDPOINT) + .get(HTTP_INTERACTION_ENDPOINT) checkResponseStatusCode(response) response.body().asString() @@ -304,8 +312,8 @@ class PrebidServerService implements ObjectMapperWrapper { def payload = encode(bidRequest) given(requestSpecification).headers(headers) - .body(payload) - .post(AUCTION_ENDPOINT) + .body(payload) + .post(AUCTION_ENDPOINT) } private Response postCookieSync(CookieSyncRequest cookieSyncRequest, @@ -396,7 +404,7 @@ class PrebidServerService implements ObjectMapperWrapper { throw new IllegalArgumentException("The end time of the test is less than the start time") } def formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss") - .withZone(ZoneId.from(UTC)) + .withZone(ZoneId.from(UTC)) def logs = Arrays.asList(pbsContainer.logs.split("\n")) def filteredLogs = [] @@ -449,7 +457,7 @@ class PrebidServerService implements ObjectMapperWrapper { private static RequestSpecification buildAndGetRequestSpecification(String uri, AuthenticationScheme authScheme) { new RequestSpecBuilder().setBaseUri(uri) - .setAuth(authScheme) - .build() + .setAuth(authScheme) + .build() } } diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy index 18d7435072f..e05575d2529 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy @@ -90,7 +90,7 @@ class PrebidCache extends NetworkScaffolding { .withQueryStringParameter("uuid", uuid), Times.unlimited(), TimeToLive.unlimited(), -10) .respond { request -> request.withPath(endpoint) - ? response().withStatusCode(OK_200.code()) + ? response().withStatusCode(OK_200.code()).withBody("{}") : HttpResponse.notFoundResponse() } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy index d6ea45d74bc..d77f9601abc 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy @@ -508,6 +508,9 @@ class CacheSpec extends BaseSpec { and: "PBS shouldn't call PBC" assert prebidCache.getRequestCount(bidRequest.imp[0].id) == 0 + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(INVALID_PREBID_CACHE_CONFIG) } def "PBS should cache bids and emit error when targeting is specified and config cache is valid and internal is invalid"() { @@ -542,6 +545,9 @@ class CacheSpec extends BaseSpec { then: "Response should contain error" assert bidResponse.ext?.errors[CACHE]*.code == [999] assert bidResponse.ext?.errors[CACHE]*.message[0] == ("Failed to resolve '${CACHE_HOST.tokenize(":")[0]}' [A(1)]") + + cleanup: "Stop and remove pbs container" + pbsServiceFactory.removeContainer(INVALID_PREBID_CACHE_CONFIG) } def "PBS should cache bids when targeting is specified and config cache is invalid and internal cache config valid"() { diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy index 1ed9914f5ff..fe44e3e2551 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy @@ -11,6 +11,7 @@ import org.prebid.server.functional.model.request.vtrack.xml.Vast import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.util.PBSUtils +import spock.lang.IgnoreRest import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR @@ -64,6 +65,7 @@ class CacheVtrackSpec extends BaseSpec { prebidCache.reset(CACHE_ENDPOINT) } + @IgnoreRest def "PBS should return 200 status code when get vtrack request contain uuid"() { given: "Random uuid" def uuid = UUID.randomUUID().toString() @@ -74,7 +76,7 @@ class CacheVtrackSpec extends BaseSpec { when: "PBS processes get vtrack request" def response = defaultPbsService.sendGetVtrackRequest(["uuid": uuid]) - then: "Response body should contain 200 status code" + then: "Response should contain 200 status code" assert response == HttpStatusCode.OK_200.code() and: "Metrics should contain ok metric" @@ -125,7 +127,7 @@ class CacheVtrackSpec extends BaseSpec { when: "PBS processes get vtrack request" def response = defaultPbsService.sendGetVtrackRequest(["uuid": uuid, cacheHost: cacheHost]) - then: "Response body should contain 200 status code" + then: "Response should contain 200 status code" assert response == HttpStatusCode.OK_200.code() and: "Metrics should contain ok metrics" @@ -156,7 +158,7 @@ class CacheVtrackSpec extends BaseSpec { when: "PBS processes get vtrack request" def response = pbsServiceWithInternalCache.sendGetVtrackRequest(["uuid": uuid, "cacheHost": cacheHost]) - then: "Response body should contain 200 status code" + then: "Response should contain 200 status code" assert response == HttpStatusCode.OK_200.code() and: "Metrics should contain ok metrics" @@ -186,7 +188,7 @@ class CacheVtrackSpec extends BaseSpec { when: "PBS processes get vtrack request" def response = pbsServiceWithInternalCache.sendGetVtrackRequest(["uuid": uuid]) - then: "Response body should contain 200 status code" + then: "Response should contain 200 status code" assert response == HttpStatusCode.OK_200.code() and: "Metrics should contain ok metrics" From 550dc60bf2ea9d70e8f20280efde84c1f02846f3 Mon Sep 17 00:00:00 2001 From: markiian Date: Wed, 15 Oct 2025 21:10:44 +0300 Subject: [PATCH 12/16] Few update mock cache logic --- .../response/vtrack/VTrackResponse.groovy | 10 +++ .../service/PrebidServerService.groovy | 6 +- .../scaffolding/PrebidCache.groovy | 17 ++-- .../functional/tests/CacheVtrackSpec.groovy | 78 ++++++++----------- 4 files changed, 53 insertions(+), 58 deletions(-) create mode 100644 src/test/groovy/org/prebid/server/functional/model/response/vtrack/VTrackResponse.groovy diff --git a/src/test/groovy/org/prebid/server/functional/model/response/vtrack/VTrackResponse.groovy b/src/test/groovy/org/prebid/server/functional/model/response/vtrack/VTrackResponse.groovy new file mode 100644 index 00000000000..3a3e47011c1 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/response/vtrack/VTrackResponse.groovy @@ -0,0 +1,10 @@ +package org.prebid.server.functional.model.response.vtrack + +import groovy.transform.ToString + +@ToString(includeNames = true, ignoreNulls = true) +class VTrackResponse { + + Integer statusCode + String responseBody +} diff --git a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy index 308ced6ee24..6ac61208c1d 100644 --- a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy +++ b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy @@ -28,7 +28,7 @@ import org.prebid.server.functional.model.response.getuids.GetuidResponse import org.prebid.server.functional.model.response.infobidders.BidderInfoResponse import org.prebid.server.functional.model.response.setuid.SetuidResponse import org.prebid.server.functional.model.response.status.StatusResponse - +import org.prebid.server.functional.model.response.vtrack.VTrackResponse import org.prebid.server.functional.testcontainers.container.PrebidServerContainer import org.prebid.server.functional.util.ObjectMapperWrapper import org.prebid.server.functional.util.PBSUtils @@ -224,7 +224,7 @@ class PrebidServerService implements ObjectMapperWrapper { decode(response.body.asString(), PrebidCacheResponse) } - int sendGetVtrackRequest(Map parameters) { + VTrackResponse sendGetVtrackRequest(Map parameters) { def response = given(requestSpecification) .queryParams(parameters) .get(VTRACK_ENDPOINT) @@ -235,7 +235,7 @@ class PrebidServerService implements ObjectMapperWrapper { log.error(responseBody) throw new PrebidServerException(responseStatusCode, responseBody, getHeaders(response)) } - responseStatusCode + new VTrackResponse(statusCode: response.statusCode, responseBody: response.body.asString()) } StatusResponse sendStatusRequest() { diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy index e05575d2529..69a9d7738a1 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy @@ -78,23 +78,20 @@ class PrebidCache extends NetworkScaffolding { } } - void setInvalidPostResponse() { + void setResponse(String responseBody) { mockServerClient.when(request().withPath(endpoint), Times.unlimited(), TimeToLive.unlimited(), -10) - .respond { response().withStatusCode(INTERNAL_SERVER_ERROR_500.code()) } - } - - void setVtrackResponse(String uuid) { - mockServerClient.when(request() - .withMethod("GET") - .withPath(endpoint) - .withQueryStringParameter("uuid", uuid), Times.unlimited(), TimeToLive.unlimited(), -10) .respond { request -> request.withPath(endpoint) - ? response().withStatusCode(OK_200.code()).withBody("{}") + ? response().withStatusCode(OK_200.code()).withBody(responseBody) : HttpResponse.notFoundResponse() } } + void setInvalidPostResponse() { + mockServerClient.when(request().withPath(endpoint), Times.unlimited(), TimeToLive.unlimited(), -10) + .respond { response().withStatusCode(INTERNAL_SERVER_ERROR_500.code()) } + } + void setInvalidVtrackResponse(String uuid) { mockServerClient.when(request() .withMethod("GET") diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy index fe44e3e2551..5262d40fa4b 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy @@ -1,6 +1,5 @@ package org.prebid.server.functional.tests -import org.mockserver.model.HttpStatusCode import org.prebid.server.functional.model.config.AccountAuctionConfig import org.prebid.server.functional.model.config.AccountCacheConfig import org.prebid.server.functional.model.config.AccountConfig @@ -11,10 +10,10 @@ import org.prebid.server.functional.model.request.vtrack.xml.Vast import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.util.PBSUtils -import spock.lang.IgnoreRest import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR +import static org.mockserver.model.HttpStatusCode.OK_200 import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer class CacheVtrackSpec extends BaseSpec { @@ -52,6 +51,10 @@ class CacheVtrackSpec extends BaseSpec { pbsServiceFactory.removeContainer(VALID_INTERNAL_CACHE + INVALID_PREBID_CACHE_CONFIG) } + void cleanup() { + prebidCache.reset() + } + def "PBS should return 400 status code when get vtrack request without uuid"() { when: "PBS processes get vtrack request" defaultPbsService.sendGetVtrackRequest(["uuid": null]) @@ -60,31 +63,26 @@ class CacheVtrackSpec extends BaseSpec { def exception = thrown(PrebidServerException) assert exception.statusCode == BAD_REQUEST.code() assert exception.responseBody == "'uuid' is a required query parameter and can't be empty" - - cleanup: - prebidCache.reset(CACHE_ENDPOINT) } - @IgnoreRest def "PBS should return 200 status code when get vtrack request contain uuid"() { given: "Random uuid" def uuid = UUID.randomUUID().toString() - and: "Cache set up successful response" - prebidCache.setVtrackResponse(uuid) + and: "Cache response with random body" + def randomBody = PBSUtils.randomString + prebidCache.setResponse(randomBody) when: "PBS processes get vtrack request" def response = defaultPbsService.sendGetVtrackRequest(["uuid": uuid]) - then: "Response should contain 200 status code" - assert response == HttpStatusCode.OK_200.code() + then: "Response should contain 200 status code and body" + assert response.statusCode == OK_200.code() + assert response.responseBody == randomBody and: "Metrics should contain ok metric" def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() assert metricsRequest[VTRACK_READ_OK_METRIC] == 1 - - cleanup: - prebidCache.reset(CACHE_ENDPOINT) } def "PBS should return status code that came from pbc when get vtrack request and response from pbc invalid"() { @@ -105,12 +103,9 @@ class CacheVtrackSpec extends BaseSpec { and: "Metrics should contain error metric" def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() assert metricsRequest[VTRACK_READ_ERROR_METRIC] == 1 - - cleanup: "Clean cache mock response" - prebidCache.reset(CACHE_ENDPOINT) } - def "PBS should return 200 status code when get vtrack request with uuid and ch"() { + def "PBS should return 200 status code and body when get vtrack request with uuid and ch"() { given: "Current value of metric prebid_cache.vtrack.read.ok" def initialValue = getCurrentMetricValue(defaultPbsService, VTRACK_READ_OK_METRIC) @@ -122,23 +117,22 @@ class CacheVtrackSpec extends BaseSpec { def cacheHost = PBSUtils.randomString and: "Clean up and set up successful response" - prebidCache.setVtrackResponse(uuid) + def responseBody = PBSUtils.getRandomString() + prebidCache.setResponse(responseBody) when: "PBS processes get vtrack request" def response = defaultPbsService.sendGetVtrackRequest(["uuid": uuid, cacheHost: cacheHost]) - then: "Response should contain 200 status code" - assert response == HttpStatusCode.OK_200.code() + then: "Response should contain 200 status code and body" + assert response.statusCode == OK_200.code() + assert response.responseBody == responseBody and: "Metrics should contain ok metrics" def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() assert metricsRequest[VTRACK_READ_OK_METRIC] == initialValue + 1 - - cleanup: "Clean cache mock response" - prebidCache.reset(CACHE_ENDPOINT) } - def "PBS should return 200 status code when internal cache configured and get vtrack request with uuid and ch"() { + def "PBS should return 200 status code and body when internal cache configured and get vtrack request with uuid and ch"() { given: "Current value of metric prebid_cache.vtrack.read.ok" def initialValue = getCurrentMetricValue(pbsServiceWithInternalCache, VTRACK_READ_OK_METRIC) @@ -153,13 +147,15 @@ class CacheVtrackSpec extends BaseSpec { def cacheHost = PBSUtils.randomString and: "Clean up and set up successful response" - prebidCache.setVtrackResponse(uuid) + def responseBody = PBSUtils.getRandomString() + prebidCache.setResponse(responseBody) when: "PBS processes get vtrack request" def response = pbsServiceWithInternalCache.sendGetVtrackRequest(["uuid": uuid, "cacheHost": cacheHost]) - then: "Response should contain 200 status code" - assert response == HttpStatusCode.OK_200.code() + then: "Response should contain 200 status code and body" + assert response.statusCode == OK_200.code() + assert response.responseBody == responseBody and: "Metrics should contain ok metrics" def metricsRequest = pbsServiceWithInternalCache.sendCollectedMetricsRequest() @@ -167,9 +163,6 @@ class CacheVtrackSpec extends BaseSpec { and: "VTrack should call internal cache" assert prebidCache.getVTracGetRequestCount() == 1 - - cleanup: "Clean cache mock response" - prebidCache.reset(CACHE_ENDPOINT) } def "PBS should return 200 status code when internal cache and get vtrack request contain uuid"() { @@ -180,7 +173,8 @@ class CacheVtrackSpec extends BaseSpec { def uuid = UUID.randomUUID().toString() and: "Cache set up successful response" - prebidCache.setVtrackResponse(uuid) + def randomBody = PBSUtils.getRandomString() + prebidCache.setResponse(randomBody) and: "Flush metric" flushMetrics(pbsServiceWithInternalCache) @@ -189,7 +183,8 @@ class CacheVtrackSpec extends BaseSpec { def response = pbsServiceWithInternalCache.sendGetVtrackRequest(["uuid": uuid]) then: "Response should contain 200 status code" - assert response == HttpStatusCode.OK_200.code() + assert response.statusCode == OK_200.code() + assert response.responseBody == randomBody and: "Metrics should contain ok metrics" def metricsRequest = pbsServiceWithInternalCache.sendCollectedMetricsRequest() @@ -197,9 +192,6 @@ class CacheVtrackSpec extends BaseSpec { and: "VTrack should call internal cache" assert prebidCache.getVTracGetRequestCount() == 1 - - cleanup: - prebidCache.reset(CACHE_ENDPOINT) } def "PBS should return status code that came from pbc when internal cache and get vtrack request and response from pbc invalid"() { @@ -226,9 +218,6 @@ class CacheVtrackSpec extends BaseSpec { and: "VTrack should call internal cache" assert prebidCache.getVTracGetRequestCount() == 1 - - cleanup: "Clean cache mock response" - prebidCache.reset(CACHE_ENDPOINT) } def "PBS should return 400 status code when internal cache and get vtrack request without uuid"() { @@ -239,9 +228,6 @@ class CacheVtrackSpec extends BaseSpec { def exception = thrown(PrebidServerException) assert exception.statusCode == BAD_REQUEST.code() assert exception.responseBody == "'uuid' is a required query parameter and can't be empty" - - cleanup: - prebidCache.reset(CACHE_ENDPOINT) } def "PBS should update prebid_cache.creative_size.xml metric when xml creative is received"() { @@ -287,6 +273,9 @@ class CacheVtrackSpec extends BaseSpec { } accountDao.save(account) + and: "Set up prebid cache" + prebidCache.setResponse() + and: "Vtrack request with custom tags" def payload = PBSUtils.randomString def creative = "<${wrapper}>prebid.org wrapper" + @@ -346,6 +335,9 @@ class CacheVtrackSpec extends BaseSpec { and: "Flush metrics" flushMetrics(defaultPbsService) + and: "Set up prebid cache" + prebidCache.setResponse() + when: "PBS processes vtrack request" defaultPbsService.sendPostVtrackRequest(request, accountId) @@ -384,7 +376,6 @@ class CacheVtrackSpec extends BaseSpec { flushMetrics(defaultPbsService) and: "Reset cache and set up invalid response" - prebidCache.reset() prebidCache.setInvalidPostResponse() when: "PBS processes vtrack request" @@ -401,8 +392,5 @@ class CacheVtrackSpec extends BaseSpec { and: "account..prebid_cache.vtrack.write.err should be updated" assert metrics[ACCOUNT_VTRACK_WRITE_ERR_METRIC.formatted(accountId)] == 1 - - cleanup: - prebidCache.reset() } } From b7955a2eb05022b557f295f19459efab075412ef Mon Sep 17 00:00:00 2001 From: markiian Date: Thu, 16 Oct 2025 18:25:07 +0300 Subject: [PATCH 13/16] Update after review --- .../response/vtrack/TransferValue.groovy | 21 ++++++++++++ .../response/vtrack/VTrackResponse.groovy | 2 +- .../service/PrebidServerService.groovy | 12 +++---- .../scaffolding/PrebidCache.groovy | 9 ++++-- .../functional/tests/CacheVtrackSpec.groovy | 32 +++++++++---------- 5 files changed, 48 insertions(+), 28 deletions(-) create mode 100644 src/test/groovy/org/prebid/server/functional/model/response/vtrack/TransferValue.groovy diff --git a/src/test/groovy/org/prebid/server/functional/model/response/vtrack/TransferValue.groovy b/src/test/groovy/org/prebid/server/functional/model/response/vtrack/TransferValue.groovy new file mode 100644 index 00000000000..afe390ab4dd --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/response/vtrack/TransferValue.groovy @@ -0,0 +1,21 @@ +package org.prebid.server.functional.model.response.vtrack + +import groovy.transform.EqualsAndHashCode +import groovy.transform.ToString + +@ToString(includeNames = true, ignoreNulls = true) +@EqualsAndHashCode +class TransferValue { + + String adm + Integer width + Integer height + + static final TransferValue getTransferValue(){ + return new TransferValue().tap { + adm = "\\n
\\\"\\\"
\\n\\n\\n\\\"\\\"
\\n\",\n" + width = 300 + height = 250 + } + } +} diff --git a/src/test/groovy/org/prebid/server/functional/model/response/vtrack/VTrackResponse.groovy b/src/test/groovy/org/prebid/server/functional/model/response/vtrack/VTrackResponse.groovy index 3a3e47011c1..a6f4f0cfa49 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/vtrack/VTrackResponse.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/vtrack/VTrackResponse.groovy @@ -6,5 +6,5 @@ import groovy.transform.ToString class VTrackResponse { Integer statusCode - String responseBody + TransferValue responseBody } diff --git a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy index 6ac61208c1d..aef0a469fac 100644 --- a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy +++ b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy @@ -28,6 +28,7 @@ import org.prebid.server.functional.model.response.getuids.GetuidResponse import org.prebid.server.functional.model.response.infobidders.BidderInfoResponse import org.prebid.server.functional.model.response.setuid.SetuidResponse import org.prebid.server.functional.model.response.status.StatusResponse +import org.prebid.server.functional.model.response.vtrack.TransferValue import org.prebid.server.functional.model.response.vtrack.VTrackResponse import org.prebid.server.functional.testcontainers.container.PrebidServerContainer import org.prebid.server.functional.util.ObjectMapperWrapper @@ -42,7 +43,6 @@ import java.time.format.DateTimeFormatter import static io.restassured.RestAssured.given import static java.time.ZoneOffset.UTC -import static org.mockserver.model.HttpStatusCode.OK_200 class PrebidServerService implements ObjectMapperWrapper { @@ -229,13 +229,11 @@ class PrebidServerService implements ObjectMapperWrapper { .queryParams(parameters) .get(VTRACK_ENDPOINT) - def responseStatusCode = response.statusCode - if (responseStatusCode != OK_200.code()) { - def responseBody = response.body.asString() - log.error(responseBody) - throw new PrebidServerException(responseStatusCode, responseBody, getHeaders(response)) + checkResponseStatusCode(response) + new VTrackResponse().tap { + statusCode = response.statusCode() + responseBody = decode(response.body.asString(), TransferValue) } - new VTrackResponse(statusCode: response.statusCode, responseBody: response.body.asString()) } StatusResponse sendStatusRequest() { diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy index 69a9d7738a1..f44cdbb7e9a 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy @@ -7,6 +7,7 @@ import org.mockserver.model.HttpResponse import org.prebid.server.functional.model.mock.services.prebidcache.response.CacheObject import org.prebid.server.functional.model.mock.services.prebidcache.response.PrebidCacheResponse import org.prebid.server.functional.model.request.cache.BidCacheRequest +import org.prebid.server.functional.model.response.vtrack.TransferValue import org.testcontainers.containers.MockServerContainer import java.util.stream.Stream @@ -78,17 +79,19 @@ class PrebidCache extends NetworkScaffolding { } } - void setResponse(String responseBody) { + void setResponse(TransferValue vTrackResponse) { mockServerClient.when(request().withPath(endpoint), Times.unlimited(), TimeToLive.unlimited(), -10) .respond { request -> request.withPath(endpoint) - ? response().withStatusCode(OK_200.code()).withBody(responseBody) + ? response().withStatusCode(OK_200.code()).withBody(encode(vTrackResponse)) : HttpResponse.notFoundResponse() } } void setInvalidPostResponse() { - mockServerClient.when(request().withPath(endpoint), Times.unlimited(), TimeToLive.unlimited(), -10) + mockServerClient.when(request() + .withMethod("POST") + .withPath(endpoint), Times.unlimited(), TimeToLive.unlimited(), -10) .respond { response().withStatusCode(INTERNAL_SERVER_ERROR_500.code()) } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy index 5262d40fa4b..e23960953d7 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy @@ -7,6 +7,7 @@ import org.prebid.server.functional.model.config.AccountEventsConfig import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.request.vtrack.VtrackRequest import org.prebid.server.functional.model.request.vtrack.xml.Vast +import org.prebid.server.functional.model.response.vtrack.TransferValue import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.util.PBSUtils @@ -38,9 +39,9 @@ class CacheVtrackSpec extends BaseSpec { private static final Map INVALID_PREBID_CACHE_CONFIG = ["cache.path" : CACHE_PATH, "cache.scheme": HTTP_SCHEME, "cache.host" : CACHE_HOST] - private static final Map VALID_INTERNAL_CACHE = ["cache.internal.scheme": "http", + private static final Map VALID_INTERNAL_CACHE = ["cache.internal.scheme": HTTP_SCHEME, "cache.internal.host" : "$networkServiceContainer.hostAndPort".toString(), - "cache.internal.path" : "/cache"] + "cache.internal.path" : CACHE_ENDPOINT] private static PrebidServerService pbsServiceWithInternalCache def setupSpec() { @@ -66,19 +67,16 @@ class CacheVtrackSpec extends BaseSpec { } def "PBS should return 200 status code when get vtrack request contain uuid"() { - given: "Random uuid" - def uuid = UUID.randomUUID().toString() - - and: "Cache response with random body" - def randomBody = PBSUtils.randomString - prebidCache.setResponse(randomBody) + given: "Clean up and set up successful response" + def responseBody = TransferValue.getTransferValue() + prebidCache.setResponse(responseBody) when: "PBS processes get vtrack request" - def response = defaultPbsService.sendGetVtrackRequest(["uuid": uuid]) + def response = defaultPbsService.sendGetVtrackRequest(["uuid": UUID.randomUUID().toString()]) then: "Response should contain 200 status code and body" assert response.statusCode == OK_200.code() - assert response.responseBody == randomBody + assert response.responseBody == responseBody and: "Metrics should contain ok metric" def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() @@ -117,11 +115,11 @@ class CacheVtrackSpec extends BaseSpec { def cacheHost = PBSUtils.randomString and: "Clean up and set up successful response" - def responseBody = PBSUtils.getRandomString() + def responseBody = TransferValue.getTransferValue() prebidCache.setResponse(responseBody) when: "PBS processes get vtrack request" - def response = defaultPbsService.sendGetVtrackRequest(["uuid": uuid, cacheHost: cacheHost]) + def response = defaultPbsService.sendGetVtrackRequest(["uuid": uuid, ch: cacheHost]) then: "Response should contain 200 status code and body" assert response.statusCode == OK_200.code() @@ -147,7 +145,7 @@ class CacheVtrackSpec extends BaseSpec { def cacheHost = PBSUtils.randomString and: "Clean up and set up successful response" - def responseBody = PBSUtils.getRandomString() + def responseBody = TransferValue.getTransferValue() prebidCache.setResponse(responseBody) when: "PBS processes get vtrack request" @@ -172,9 +170,9 @@ class CacheVtrackSpec extends BaseSpec { and: "Random uuid" def uuid = UUID.randomUUID().toString() - and: "Cache set up successful response" - def randomBody = PBSUtils.getRandomString() - prebidCache.setResponse(randomBody) + and: "Clean up and set up successful response" + def responseBody = TransferValue.getTransferValue() + prebidCache.setResponse(responseBody) and: "Flush metric" flushMetrics(pbsServiceWithInternalCache) @@ -184,7 +182,7 @@ class CacheVtrackSpec extends BaseSpec { then: "Response should contain 200 status code" assert response.statusCode == OK_200.code() - assert response.responseBody == randomBody + assert response.responseBody == responseBody and: "Metrics should contain ok metrics" def metricsRequest = pbsServiceWithInternalCache.sendCollectedMetricsRequest() From ba3175420387efb54008f2e3b204bf258ac7c2fd Mon Sep 17 00:00:00 2001 From: markiian Date: Tue, 21 Oct 2025 11:24:25 +0300 Subject: [PATCH 14/16] Update after review --- .../response/vtrack/TransferValue.groovy | 3 +- .../response/vtrack/VTrackResponse.groovy | 10 --- .../service/PrebidServerService.groovy | 8 +-- .../scaffolding/NetworkScaffolding.groovy | 49 +++++++------ .../scaffolding/PrebidCache.groovy | 19 +++-- .../functional/tests/CacheVtrackSpec.groovy | 72 +++++++++---------- 6 files changed, 76 insertions(+), 85 deletions(-) delete mode 100644 src/test/groovy/org/prebid/server/functional/model/response/vtrack/VTrackResponse.groovy diff --git a/src/test/groovy/org/prebid/server/functional/model/response/vtrack/TransferValue.groovy b/src/test/groovy/org/prebid/server/functional/model/response/vtrack/TransferValue.groovy index afe390ab4dd..1a7f24177dd 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/vtrack/TransferValue.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/vtrack/TransferValue.groovy @@ -2,6 +2,7 @@ package org.prebid.server.functional.model.response.vtrack import groovy.transform.EqualsAndHashCode import groovy.transform.ToString +import org.prebid.server.functional.util.PBSUtils @ToString(includeNames = true, ignoreNulls = true) @EqualsAndHashCode @@ -13,7 +14,7 @@ class TransferValue { static final TransferValue getTransferValue(){ return new TransferValue().tap { - adm = "\\n
\\\"\\\"
\\n\\n\\n\\\"\\\"
\\n\",\n" + adm = PBSUtils.randomString width = 300 height = 250 } diff --git a/src/test/groovy/org/prebid/server/functional/model/response/vtrack/VTrackResponse.groovy b/src/test/groovy/org/prebid/server/functional/model/response/vtrack/VTrackResponse.groovy deleted file mode 100644 index a6f4f0cfa49..00000000000 --- a/src/test/groovy/org/prebid/server/functional/model/response/vtrack/VTrackResponse.groovy +++ /dev/null @@ -1,10 +0,0 @@ -package org.prebid.server.functional.model.response.vtrack - -import groovy.transform.ToString - -@ToString(includeNames = true, ignoreNulls = true) -class VTrackResponse { - - Integer statusCode - TransferValue responseBody -} diff --git a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy index aef0a469fac..45a1138cf71 100644 --- a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy +++ b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy @@ -29,7 +29,6 @@ import org.prebid.server.functional.model.response.infobidders.BidderInfoRespons import org.prebid.server.functional.model.response.setuid.SetuidResponse import org.prebid.server.functional.model.response.status.StatusResponse import org.prebid.server.functional.model.response.vtrack.TransferValue -import org.prebid.server.functional.model.response.vtrack.VTrackResponse import org.prebid.server.functional.testcontainers.container.PrebidServerContainer import org.prebid.server.functional.util.ObjectMapperWrapper import org.prebid.server.functional.util.PBSUtils @@ -224,16 +223,13 @@ class PrebidServerService implements ObjectMapperWrapper { decode(response.body.asString(), PrebidCacheResponse) } - VTrackResponse sendGetVtrackRequest(Map parameters) { + TransferValue sendGetVtrackRequest(Map parameters) { def response = given(requestSpecification) .queryParams(parameters) .get(VTRACK_ENDPOINT) checkResponseStatusCode(response) - new VTrackResponse().tap { - statusCode = response.statusCode() - responseBody = decode(response.body.asString(), TransferValue) - } + decode(response.body.asString(), TransferValue) } StatusResponse sendStatusRequest() { diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/NetworkScaffolding.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/NetworkScaffolding.groovy index 7eea7536dfb..8ac5ad41483 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/NetworkScaffolding.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/NetworkScaffolding.groovy @@ -37,17 +37,17 @@ abstract class NetworkScaffolding implements ObjectMapperWrapper { int getRequestCount(HttpRequest httpRequest) { mockServerClient.retrieveRecordedRequests(httpRequest) - .size() + .size() } int getRequestCount(String value) { mockServerClient.retrieveRecordedRequests(getRequest(value)) - .size() + .size() } int getRequestCount() { mockServerClient.retrieveRecordedRequests(request) - .size() + .size() } void setResponse(HttpRequest httpRequest, @@ -56,8 +56,8 @@ abstract class NetworkScaffolding implements ObjectMapperWrapper { Times times = Times.exactly(1)) { def mockResponse = encode(responseModel) mockServerClient.when(httpRequest, times) - .respond(response().withStatusCode(statusCode.code()) - .withBody(mockResponse, APPLICATION_JSON)) + .respond(response().withStatusCode(statusCode.code()) + .withBody(mockResponse, APPLICATION_JSON)) } void setResponse(String value, @@ -73,9 +73,9 @@ abstract class NetworkScaffolding implements ObjectMapperWrapper { def responseHeaders = headers.collect { new Header(it.key, it.value) } def mockResponse = encode(responseModel) mockServerClient.when(getRequest(value), Times.unlimited()) - .respond(response().withStatusCode(statusCode.code()) - .withBody(mockResponse, APPLICATION_JSON) - .withHeaders(responseHeaders)) + .respond(response().withStatusCode(statusCode.code()) + .withBody(mockResponse, APPLICATION_JSON) + .withHeaders(responseHeaders)) } void setResponse(String value, @@ -86,39 +86,39 @@ abstract class NetworkScaffolding implements ObjectMapperWrapper { def responseHeaders = headers.collect { new Header(it.key, it.value) } def mockResponse = encode(responseModel) mockServerClient.when(getRequest(value), Times.unlimited()) - .respond(response().withStatusCode(statusCode.code()) - .withBody(mockResponse, APPLICATION_JSON) - .withHeaders(responseHeaders) - .withDelay(TimeUnit.MILLISECONDS, responseDelay)) + .respond(response().withStatusCode(statusCode.code()) + .withBody(mockResponse, APPLICATION_JSON) + .withHeaders(responseHeaders) + .withDelay(TimeUnit.MILLISECONDS, responseDelay)) } void setResponse(String value, String mockResponse) { mockServerClient.when(getRequest(value), Times.exactly(1)) - .respond(response().withStatusCode(OK_200.code()) - .withBody(mockResponse, APPLICATION_JSON)) + .respond(response().withStatusCode(OK_200.code()) + .withBody(mockResponse, APPLICATION_JSON)) } void setResponse(ResponseModel responseModel) { def mockResponse = encode(responseModel) mockServerClient.when(request().withPath(endpoint)) - .respond(response().withStatusCode(OK_200.code()) - .withBody(mockResponse, APPLICATION_JSON)) + .respond(response().withStatusCode(OK_200.code()) + .withBody(mockResponse, APPLICATION_JSON)) } void setResponse(String value, HttpStatusCode httpStatusCode) { mockServerClient.when(getRequest(value), Times.exactly(1)) - .respond(response().withStatusCode(httpStatusCode.code())) + .respond(response().withStatusCode(httpStatusCode.code())) } void setResponse(String value, HttpStatusCode httpStatusCode, String errorText) { mockServerClient.when(getRequest(value), Times.exactly(1)) - .respond(response().withStatusCode(httpStatusCode.code()) - .withBody(errorText, APPLICATION_JSON)) + .respond(response().withStatusCode(httpStatusCode.code()) + .withBody(errorText, APPLICATION_JSON)) } void setResponseWithTimeout(String value, int timeoutSec = 5) { mockServerClient.when(getRequest(value), Times.exactly(1)) - .respond(response().withDelay(SECONDS, timeoutSec)) + .respond(response().withDelay(SECONDS, timeoutSec)) } protected def getRequestAndResponse() { @@ -130,14 +130,19 @@ abstract class NetworkScaffolding implements ObjectMapperWrapper { .collect { it.body.toString() } } + String getRecordedRequestsQueryParameters(HttpRequest httpRequest) { + mockServerClient.retrieveRecordedRequests(httpRequest) + .collect { it -> it.queryStringParameters.multimap.toString()} + } + List getRecordedRequestsBody(String value) { mockServerClient.retrieveRecordedRequests(getRequest(value)) - .collect { it.body.toString() } + .collect { it.body.toString() } } List getRecordedRequestsBody() { mockServerClient.retrieveRecordedRequests(request) - .collect { it.body.toString() } + .collect { it.body.toString() } } Map> getLastRecordedRequestHeaders(HttpRequest httpRequest) { diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy index f44cdbb7e9a..66ce54a9531 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy @@ -8,6 +8,7 @@ import org.prebid.server.functional.model.mock.services.prebidcache.response.Cac import org.prebid.server.functional.model.mock.services.prebidcache.response.PrebidCacheResponse import org.prebid.server.functional.model.request.cache.BidCacheRequest import org.prebid.server.functional.model.response.vtrack.TransferValue +import org.prebid.server.functional.util.PBSUtils import org.testcontainers.containers.MockServerContainer import java.util.stream.Stream @@ -26,8 +27,8 @@ class PrebidCache extends NetworkScaffolding { super(mockServerContainer, CACHE_ENDPOINT) } - int getVTracGetRequestCount() { - getRequestCount(request().withMethod("GET") + String getVTracGetRequestParams() { + getRecordedRequestsQueryParameters(request().withMethod("GET") .withPath(CACHE_ENDPOINT)) } @@ -71,7 +72,9 @@ class PrebidCache extends NetworkScaffolding { @Override void setResponse() { - mockServerClient.when(request().withPath(endpoint), Times.unlimited(), TimeToLive.unlimited(), -10) + mockServerClient.when(request() + .withMethod("POST") + .withPath(endpoint), Times.unlimited(), TimeToLive.unlimited(), -10) .respond { request -> request.withPath(endpoint) ? response().withStatusCode(OK_200.code()).withBody(getBodyByRequest(request)) @@ -79,8 +82,10 @@ class PrebidCache extends NetworkScaffolding { } } - void setResponse(TransferValue vTrackResponse) { - mockServerClient.when(request().withPath(endpoint), Times.unlimited(), TimeToLive.unlimited(), -10) + void setGetResponse(TransferValue vTrackResponse) { + mockServerClient.when(request() + .withMethod("GET") + .withPath(endpoint), Times.unlimited(), TimeToLive.unlimited(), -10) .respond { request -> request.withPath(endpoint) ? response().withStatusCode(OK_200.code()).withBody(encode(vTrackResponse)) @@ -95,12 +100,12 @@ class PrebidCache extends NetworkScaffolding { .respond { response().withStatusCode(INTERNAL_SERVER_ERROR_500.code()) } } - void setInvalidVtrackResponse(String uuid) { + void setInvalidGetResponse(String uuid, String errorMessage = PBSUtils.randomString) { mockServerClient.when(request() .withMethod("GET") .withPath(endpoint) .withQueryStringParameter("uuid", uuid), Times.unlimited(), TimeToLive.unlimited(), -10) - .respond { response().withStatusCode(INTERNAL_SERVER_ERROR_500.code()) } + .respond { response().withBody(errorMessage).withStatusCode(INTERNAL_SERVER_ERROR_500.code()) } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy index e23960953d7..e96fc519fe5 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheVtrackSpec.groovy @@ -14,7 +14,6 @@ import org.prebid.server.functional.util.PBSUtils import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR -import static org.mockserver.model.HttpStatusCode.OK_200 import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer class CacheVtrackSpec extends BaseSpec { @@ -69,16 +68,15 @@ class CacheVtrackSpec extends BaseSpec { def "PBS should return 200 status code when get vtrack request contain uuid"() { given: "Clean up and set up successful response" def responseBody = TransferValue.getTransferValue() - prebidCache.setResponse(responseBody) + prebidCache.setGetResponse(responseBody) when: "PBS processes get vtrack request" def response = defaultPbsService.sendGetVtrackRequest(["uuid": UUID.randomUUID().toString()]) - then: "Response should contain 200 status code and body" - assert response.statusCode == OK_200.code() - assert response.responseBody == responseBody + then: "Response should contain response from pbc" + assert response == responseBody - and: "Metrics should contain ok metric" + then: "Metrics should contain ok metric" def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() assert metricsRequest[VTRACK_READ_OK_METRIC] == 1 } @@ -88,7 +86,8 @@ class CacheVtrackSpec extends BaseSpec { def uuid = UUID.randomUUID().toString() and: "Cache set up invalid response" - prebidCache.setInvalidVtrackResponse(uuid) + def randomErrorMessage = PBSUtils.randomString + prebidCache.setInvalidGetResponse(uuid, randomErrorMessage) when: "PBS processes get vtrack request" defaultPbsService.sendGetVtrackRequest(["uuid": uuid]) @@ -96,7 +95,7 @@ class CacheVtrackSpec extends BaseSpec { then: "Request should fail with an error" def exception = thrown(PrebidServerException) assert exception.statusCode == INTERNAL_SERVER_ERROR.code() - assert exception.responseBody == "Error occurred while sending request to cache: Cannot parse response: " + assert exception.responseBody == "Error occurred while sending request to cache: Cannot parse response: $randomErrorMessage" and: "Metrics should contain error metric" def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() @@ -107,23 +106,19 @@ class CacheVtrackSpec extends BaseSpec { given: "Current value of metric prebid_cache.vtrack.read.ok" def initialValue = getCurrentMetricValue(defaultPbsService, VTRACK_READ_OK_METRIC) - and: "Clean cache mock response" - prebidCache.reset(CACHE_ENDPOINT) - and: "Random uuid and cache host" def uuid = UUID.randomUUID().toString() def cacheHost = PBSUtils.randomString - and: "Clean up and set up successful response" + and: "Set up response body" def responseBody = TransferValue.getTransferValue() - prebidCache.setResponse(responseBody) + prebidCache.setGetResponse(responseBody) when: "PBS processes get vtrack request" - def response = defaultPbsService.sendGetVtrackRequest(["uuid": uuid, ch: cacheHost]) + def response = defaultPbsService.sendGetVtrackRequest(["uuid": uuid, "ch": cacheHost]) - then: "Response should contain 200 status code and body" - assert response.statusCode == OK_200.code() - assert response.responseBody == responseBody + then: "Response should contain response from pbc" + assert response == responseBody and: "Metrics should contain ok metrics" def metricsRequest = defaultPbsService.sendCollectedMetricsRequest() @@ -134,9 +129,6 @@ class CacheVtrackSpec extends BaseSpec { given: "Current value of metric prebid_cache.vtrack.read.ok" def initialValue = getCurrentMetricValue(pbsServiceWithInternalCache, VTRACK_READ_OK_METRIC) - and: "Clean cache mock response" - prebidCache.reset(CACHE_ENDPOINT) - and: "Flush metric" flushMetrics(pbsServiceWithInternalCache) @@ -144,23 +136,23 @@ class CacheVtrackSpec extends BaseSpec { def uuid = UUID.randomUUID().toString() def cacheHost = PBSUtils.randomString - and: "Clean up and set up successful response" + and: "Mock set up successful response" def responseBody = TransferValue.getTransferValue() - prebidCache.setResponse(responseBody) + prebidCache.setGetResponse(responseBody) when: "PBS processes get vtrack request" - def response = pbsServiceWithInternalCache.sendGetVtrackRequest(["uuid": uuid, "cacheHost": cacheHost]) + def response = pbsServiceWithInternalCache.sendGetVtrackRequest(["uuid": uuid, "ch": cacheHost]) - then: "Response should contain 200 status code and body" - assert response.statusCode == OK_200.code() - assert response.responseBody == responseBody + then: "Response should contain response from pbc" + assert response == responseBody and: "Metrics should contain ok metrics" def metricsRequest = pbsServiceWithInternalCache.sendCollectedMetricsRequest() assert metricsRequest[VTRACK_READ_OK_METRIC] == initialValue + 1 - and: "VTrack should call internal cache" - assert prebidCache.getVTracGetRequestCount() == 1 + and: "Verify parameters that came to external cache services" + def requestParams = prebidCache.getVTracGetRequestParams() + assert requestParams == "[{ch=[$cacheHost], uuid=[$uuid]}]" } def "PBS should return 200 status code when internal cache and get vtrack request contain uuid"() { @@ -170,9 +162,9 @@ class CacheVtrackSpec extends BaseSpec { and: "Random uuid" def uuid = UUID.randomUUID().toString() - and: "Clean up and set up successful response" + and: "Set up response body" def responseBody = TransferValue.getTransferValue() - prebidCache.setResponse(responseBody) + prebidCache.setGetResponse(responseBody) and: "Flush metric" flushMetrics(pbsServiceWithInternalCache) @@ -180,16 +172,16 @@ class CacheVtrackSpec extends BaseSpec { when: "PBS processes get vtrack request" def response = pbsServiceWithInternalCache.sendGetVtrackRequest(["uuid": uuid]) - then: "Response should contain 200 status code" - assert response.statusCode == OK_200.code() - assert response.responseBody == responseBody + then: "Response should contain response from pbc" + assert response == responseBody and: "Metrics should contain ok metrics" def metricsRequest = pbsServiceWithInternalCache.sendCollectedMetricsRequest() assert metricsRequest[VTRACK_READ_OK_METRIC] == initialValue + 1 - and: "VTrack should call internal cache" - assert prebidCache.getVTracGetRequestCount() == 1 + and: "Verify parameters that came to external cache services" + def requestParams = prebidCache.getVTracGetRequestParams() + assert requestParams == "[{uuid=[$uuid]}]" } def "PBS should return status code that came from pbc when internal cache and get vtrack request and response from pbc invalid"() { @@ -197,7 +189,8 @@ class CacheVtrackSpec extends BaseSpec { def uuid = UUID.randomUUID().toString() and: "Cache set up invalid response" - prebidCache.setInvalidVtrackResponse(uuid) + def randomErrorMessage = PBSUtils.randomString + prebidCache.setInvalidGetResponse(uuid, randomErrorMessage) and: "Flush metric" flushMetrics(pbsServiceWithInternalCache) @@ -208,14 +201,15 @@ class CacheVtrackSpec extends BaseSpec { then: "Request should fail with an error" def exception = thrown(PrebidServerException) assert exception.statusCode == INTERNAL_SERVER_ERROR.code() - assert exception.responseBody == "Error occurred while sending request to cache: Cannot parse response: " + assert exception.responseBody == "Error occurred while sending request to cache: Cannot parse response: $randomErrorMessage" and: "Metrics should contain error metric" def metricsRequest = pbsServiceWithInternalCache.sendCollectedMetricsRequest() assert metricsRequest[VTRACK_READ_ERROR_METRIC] == 1 - and: "VTrack should call internal cache" - assert prebidCache.getVTracGetRequestCount() == 1 + and: "Verify parameters that came to external cache services" + def requestParams = prebidCache.getVTracGetRequestParams() + assert requestParams == "[{uuid=[$uuid]}]" } def "PBS should return 400 status code when internal cache and get vtrack request without uuid"() { From db1a7d790d4608cf48aca8b1c6fafee8a237766e Mon Sep 17 00:00:00 2001 From: markiian Date: Tue, 21 Oct 2025 11:25:56 +0300 Subject: [PATCH 15/16] Update after review --- .../functional/testcontainers/scaffolding/PrebidCache.groovy | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy index 66ce54a9531..5b4e03e0609 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy @@ -73,7 +73,6 @@ class PrebidCache extends NetworkScaffolding { @Override void setResponse() { mockServerClient.when(request() - .withMethod("POST") .withPath(endpoint), Times.unlimited(), TimeToLive.unlimited(), -10) .respond { request -> request.withPath(endpoint) From 7af6891986ee75cbfa8a6cde03da7139e2f4fc03 Mon Sep 17 00:00:00 2001 From: markiian Date: Tue, 21 Oct 2025 11:39:17 +0300 Subject: [PATCH 16/16] Add method POST --- .../functional/testcontainers/scaffolding/PrebidCache.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy index 5b4e03e0609..66ce54a9531 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/PrebidCache.groovy @@ -73,6 +73,7 @@ class PrebidCache extends NetworkScaffolding { @Override void setResponse() { mockServerClient.when(request() + .withMethod("POST") .withPath(endpoint), Times.unlimited(), TimeToLive.unlimited(), -10) .respond { request -> request.withPath(endpoint)