From 53e95990bd52fa89621802a195ae94c14ea3ffaa Mon Sep 17 00:00:00 2001 From: markiian Date: Mon, 17 Nov 2025 01:55:36 +0200 Subject: [PATCH 1/6] Add tests for influx db --- .../response/influx/InfluxResponse.groovy | 6 ++ .../model/response/influx/InfluxResult.groovy | 10 +++ .../model/response/influx/Series.groovy | 8 ++ .../service/PrebidServerService.groovy | 25 ++++++ .../testcontainers/Dependencies.groovy | 13 +++- .../testcontainers/PbsConfig.groovy | 17 +++- .../container/PrebidServerContainer.groovy | 5 ++ .../functional/tests/InfluxDBSpec.groovy | 77 +++++++++++++++++++ 8 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 src/test/groovy/org/prebid/server/functional/model/response/influx/InfluxResponse.groovy create mode 100644 src/test/groovy/org/prebid/server/functional/model/response/influx/InfluxResult.groovy create mode 100644 src/test/groovy/org/prebid/server/functional/model/response/influx/Series.groovy create mode 100644 src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy diff --git a/src/test/groovy/org/prebid/server/functional/model/response/influx/InfluxResponse.groovy b/src/test/groovy/org/prebid/server/functional/model/response/influx/InfluxResponse.groovy new file mode 100644 index 00000000000..c2fc5b0c6c2 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/response/influx/InfluxResponse.groovy @@ -0,0 +1,6 @@ +package org.prebid.server.functional.model.response.influx + +class InfluxResponse { + + List results +} diff --git a/src/test/groovy/org/prebid/server/functional/model/response/influx/InfluxResult.groovy b/src/test/groovy/org/prebid/server/functional/model/response/influx/InfluxResult.groovy new file mode 100644 index 00000000000..ae6f6864334 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/response/influx/InfluxResult.groovy @@ -0,0 +1,10 @@ +package org.prebid.server.functional.model.response.influx + +import com.fasterxml.jackson.annotation.JsonProperty + +class InfluxResult { + + @JsonProperty("statement_id") + Integer statementId + List series +} diff --git a/src/test/groovy/org/prebid/server/functional/model/response/influx/Series.groovy b/src/test/groovy/org/prebid/server/functional/model/response/influx/Series.groovy new file mode 100644 index 00000000000..6d5dd2c5860 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/response/influx/Series.groovy @@ -0,0 +1,8 @@ +package org.prebid.server.functional.model.response.influx + +class Series { + + String name + List columns + List> values +} 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 9e760b7173e..c6e48d491c1 100644 --- a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy +++ b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy @@ -25,6 +25,7 @@ import org.prebid.server.functional.model.response.cookiesync.CookieSyncResponse import org.prebid.server.functional.model.response.cookiesync.RawCookieSyncResponse import org.prebid.server.functional.model.response.currencyrates.CurrencyRatesResponse import org.prebid.server.functional.model.response.getuids.GetuidResponse +import org.prebid.server.functional.model.response.influx.InfluxResponse 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 @@ -60,9 +61,11 @@ class PrebidServerService implements ObjectMapperWrapper { static final String COLLECTED_METRICS_ENDPOINT = "/collected-metrics" static final String PROMETHEUS_METRICS_ENDPOINT = "/metrics" static final String UIDS_COOKIE_NAME = "uids" + static final String INFLUX_DB_ENDPOINT = "/query" private final PrebidServerContainer pbsContainer private final RequestSpecification requestSpecification + private final RequestSpecification influxRequestSpecification private final RequestSpecification adminRequestSpecification private final RequestSpecification prometheusRequestSpecification @@ -75,6 +78,8 @@ class PrebidServerService implements ObjectMapperWrapper { this.pbsContainer = pbsContainer requestSpecification = new RequestSpecBuilder().setBaseUri(pbsContainer.rootUri) .build() + influxRequestSpecification = new RequestSpecBuilder().setBaseUri(pbsContainer.influxUri) + .build() adminRequestSpecification = buildAndGetRequestSpecification(pbsContainer.adminRootUri, authenticationScheme) prometheusRequestSpecification = buildAndGetRequestSpecification(pbsContainer.prometheusRootUri, authenticationScheme) } @@ -290,6 +295,26 @@ class PrebidServerService implements ObjectMapperWrapper { decode(response.asString(), new TypeReference>() {}) } + Map sendInfluxMetricsRequest() { + def response = given(influxRequestSpecification) + .queryParams(["db": "prebid", "q": "SHOW MEASUREMENTS"]) + .get(INFLUX_DB_ENDPOINT) + + checkResponseStatusCode(response) + def responseBody = decode(response.getBody().asString(), InfluxResponse) + + def metricNameToCountOfCall = new HashMap() + responseBody.results.first().series.first.values.flatten().each { it -> + def influxResponse = decode(given(influxRequestSpecification) + .queryParams(["db": "prebid", "q": "SELECT COUNT(count) FROM \"$it\""]) + .get(INFLUX_DB_ENDPOINT).getBody().asString(), InfluxResponse) + + metricNameToCountOfCall.put(influxResponse?.results?.first?.series?.name?.first, + influxResponse?.results?.first?.series?.values?.flatten()?.last()) + } + metricNameToCountOfCall + } + String sendPrometheusMetricsRequest() { def response = given(prometheusRequestSpecification).get(PROMETHEUS_METRICS_ENDPOINT) diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/Dependencies.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/Dependencies.groovy index 70c99a2a833..936507fd1f9 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/Dependencies.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/Dependencies.groovy @@ -2,6 +2,7 @@ package org.prebid.server.functional.testcontainers import org.prebid.server.functional.testcontainers.container.NetworkServiceContainer import org.prebid.server.functional.util.SystemProperties +import org.testcontainers.containers.InfluxDBContainer import org.testcontainers.containers.MySQLContainer import org.testcontainers.containers.Network import org.testcontainers.containers.localstack.LocalStackContainer @@ -34,6 +35,14 @@ class Dependencies { .withInitScript("org/prebid/server/functional/db_psql_schema.sql") .withNetwork(network) + static final InfluxDBContainer influxdbContainer = new InfluxDBContainer<>(DockerImageName.parse("influxdb:1.8.10")) + .withUsername("prebid") + .withUsername("prebid") + .withPassword("prebid") + .withAuthEnabled(false) + .withDatabase("prebid") + .withNetwork(network) + static final NetworkServiceContainer networkServiceContainer = new NetworkServiceContainer(MOCKSERVER_VERSION) .withNetwork(network) @@ -44,13 +53,13 @@ class Dependencies { localStackContainer = new LocalStackContainer(DockerImageName.parse("localstack/localstack:s3-latest")) .withNetwork(network) .withServices(S3) - Startables.deepStart([networkServiceContainer, mysqlContainer, localStackContainer]).join() + Startables.deepStart([networkServiceContainer, mysqlContainer, localStackContainer, influxdbContainer]).join() } } static void stop() { if (IS_LAUNCH_CONTAINERS) { - [networkServiceContainer, mysqlContainer, localStackContainer].parallelStream() + [networkServiceContainer, mysqlContainer, localStackContainer, influxdbContainer].parallelStream() .forEach({ it.stop() }) } } diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy index a63039f3416..d6b0a65c03f 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy @@ -1,5 +1,6 @@ package org.prebid.server.functional.testcontainers +import org.testcontainers.containers.InfluxDBContainer import org.testcontainers.containers.MySQLContainer import org.testcontainers.containers.PostgreSQLContainer @@ -101,6 +102,20 @@ LIMIT 1 ].asImmutable() } + static Map getInfluxContainer(InfluxDBContainer influx = Dependencies.influxdbContainer) { + ["metrics.influxdb.enabled" : "true", + "metrics.influxdb.prefix" : "influx.metric.", + "metrics.influxdb.host" : influx.getNetworkAliases().get(0), + "metrics.influxdb.port" : influx.getExposedPorts().get(0) as String, + "metrics.influxdb.protocol" : "http", + "metrics.influxdb.database" : "prebid", + "metrics.influxdb.auth" : "prebid:prebid", + "metrics.influxdb.interval" : "1", + "metrics.influxdb.connectTimeout": "5000", + "metrics.influxdb.readTimeout" : "100", + ].asImmutable() + } + static Map getPostgreSqlConfig(PostgreSQLContainer postgres = Dependencies.postgresqlContainer) { ["settings.database.type" : "postgres", "settings.database.host" : postgres.getNetworkAliases().get(0), @@ -145,7 +160,7 @@ LIMIT 1 "currency-converter.external-rates.refresh-period-ms" : "900000"] } - static Map getTargetingConfig() { + static Map getTargetingConfig() { ["settings.targeting.truncate-attr-chars": '255'] } diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/container/PrebidServerContainer.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/container/PrebidServerContainer.groovy index 0daa6883acf..43630d3616a 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/container/PrebidServerContainer.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/container/PrebidServerContainer.groovy @@ -43,6 +43,7 @@ class PrebidServerContainer extends GenericContainer { << PbsConfig.prebidCacheConfig << PbsConfig.mySqlConfig << PbsConfig.targetingConfig + << PbsConfig.influxContainer withConfig(commonConfig) withConfig(customConfig) } @@ -75,6 +76,10 @@ class PrebidServerContainer extends GenericContainer { getMappedPort(PROMETHEUS_PORT) } + String getInfluxUri() { + return "http://$host:$Dependencies.influxdbContainer.firstMappedPort" + } + String getRootUri() { return "http://$host:$port" } diff --git a/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy new file mode 100644 index 00000000000..d787bb07f84 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy @@ -0,0 +1,77 @@ +package org.prebid.server.functional.tests + +import org.prebid.server.functional.model.AccountStatus +import org.prebid.server.functional.model.config.AccountConfig +import org.prebid.server.functional.model.db.Account +import org.prebid.server.functional.model.request.auction.BidRequest +import org.prebid.server.functional.service.PrebidServerException +import org.prebid.server.functional.util.PBSUtils + +import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED + +class InfluxDBSpec extends BaseSpec { + + def "PBS should reject request with error and metrics when inactive account"() { + given: "Pbs config with enforce-valid-account and default-account-config" + def pbsService = pbsServiceFactory.getService( + ["settings.enforce-valid-account": enforceValidAccount as String]) + + and: "Inactive account id" + def accountId = PBSUtils.randomNumber + def account = new Account(uuid: accountId, config: new AccountConfig(status: AccountStatus.INACTIVE)) + accountDao.save(account) + + and: "Default basic BidRequest with inactive account id" + def bidRequest = BidRequest.defaultBidRequest.tap { + site.publisher.id = accountId + } + + when: "PBS processes auction request" + pbsService.sendAuctionRequest(bidRequest) + + then: "PBS should reject the entire auction" + def exception = thrown(PrebidServerException) + assert exception.statusCode == UNAUTHORIZED.code() + assert exception.responseBody == "Account $accountId is inactive" + + and: "PBs should emit proper metric" + PBSUtils.waitUntil({ + def metricsRequest = pbsService.sendInfluxMetricsRequest() + metricsRequest["influx.metric.account.${bidRequest.accountId}.requests.rejected.invalid-account"] != null + }) + + where: + enforceValidAccount << [true, false] + } + + def "PBS shouldn't reject request with error and metrics when active account"() { + given: "Pbs config with enforce-valid-account and default-account-config" + def pbsService = pbsServiceFactory.getService( + ["settings.enforce-valid-account": enforceValidAccount as String]) + + and: "Inactive account id" + def accountId = PBSUtils.randomNumber + def account = new Account(uuid: accountId, config: new AccountConfig(status: AccountStatus.ACTIVE)) + accountDao.save(account) + + and: "Default basic BidRequest with inactive account id" + def bidRequest = BidRequest.defaultBidRequest.tap { + site.publisher.id = accountId + } + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "Bid response should contain seatBid" + assert response.seatbid.size() == 1 + + and: "PBs should emit proper metric" + PBSUtils.waitUntil({ + def metricsRequest = pbsService.sendInfluxMetricsRequest() + metricsRequest["influx.metric.account.${bidRequest.accountId}.requests.rejected.invalid-account"] == null + }) + + where: + enforceValidAccount << [true, false] + } +} From 3504d22fdc9d57275571479804b4f188f4178e4e Mon Sep 17 00:00:00 2001 From: markiian Date: Mon, 17 Nov 2025 17:56:04 +0200 Subject: [PATCH 2/6] Improving tests for influxDb --- .../service/PrebidServerService.groovy | 11 ++--- .../testcontainers/PbsConfig.groovy | 3 +- .../functional/tests/InfluxDBSpec.groovy | 41 ++++++++----------- 3 files changed, 26 insertions(+), 29 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 c6e48d491c1..77e9e31594a 100644 --- a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy +++ b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy @@ -43,6 +43,7 @@ import java.time.format.DateTimeFormatter import static io.restassured.RestAssured.given import static java.time.ZoneOffset.UTC +import static org.prebid.server.functional.testcontainers.PbsConfig.PREBID_DATABASE class PrebidServerService implements ObjectMapperWrapper { @@ -297,20 +298,20 @@ class PrebidServerService implements ObjectMapperWrapper { Map sendInfluxMetricsRequest() { def response = given(influxRequestSpecification) - .queryParams(["db": "prebid", "q": "SHOW MEASUREMENTS"]) + .queryParams(["db": PREBID_DATABASE, "q": "SHOW MEASUREMENTS"]) .get(INFLUX_DB_ENDPOINT) checkResponseStatusCode(response) def responseBody = decode(response.getBody().asString(), InfluxResponse) - def metricNameToCountOfCall = new HashMap() + Map metricNameToCountOfCall = [:] responseBody.results.first().series.first.values.flatten().each { it -> def influxResponse = decode(given(influxRequestSpecification) - .queryParams(["db": "prebid", "q": "SELECT COUNT(count) FROM \"$it\""]) + .queryParams(["db": PREBID_DATABASE, "q": "SELECT COUNT(count) FROM \"$it\" WHERE count >= 1"]) .get(INFLUX_DB_ENDPOINT).getBody().asString(), InfluxResponse) - metricNameToCountOfCall.put(influxResponse?.results?.first?.series?.name?.first, - influxResponse?.results?.first?.series?.values?.flatten()?.last()) + def series = influxResponse?.results?.first?.series + metricNameToCountOfCall.put(series?.name?.first, series?.values?.flatten()?[1] as Integer) } metricNameToCountOfCall } diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy index d6b0a65c03f..f3d36ebc328 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy @@ -11,6 +11,7 @@ import static org.prebid.server.functional.util.CurrencyUtil.DEFAULT_CURRENCY final class PbsConfig { + static final String PREBID_DATABASE = "prebid" private static final String DB_ACCOUNT_QUERY = """ SELECT JSON_MERGE_PATCH(JSON_OBJECT('id', uuid, 'status', status, @@ -108,7 +109,7 @@ LIMIT 1 "metrics.influxdb.host" : influx.getNetworkAliases().get(0), "metrics.influxdb.port" : influx.getExposedPorts().get(0) as String, "metrics.influxdb.protocol" : "http", - "metrics.influxdb.database" : "prebid", + "metrics.influxdb.database" : PREBID_DATABASE, "metrics.influxdb.auth" : "prebid:prebid", "metrics.influxdb.interval" : "1", "metrics.influxdb.connectTimeout": "5000", diff --git a/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy index d787bb07f84..93a798fed5d 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy @@ -5,18 +5,21 @@ import org.prebid.server.functional.model.config.AccountConfig import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.request.auction.BidRequest 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.UNAUTHORIZED class InfluxDBSpec extends BaseSpec { - def "PBS should reject request with error and metrics when inactive account"() { - given: "Pbs config with enforce-valid-account and default-account-config" - def pbsService = pbsServiceFactory.getService( - ["settings.enforce-valid-account": enforceValidAccount as String]) + private static final PrebidServerService pbsServiceWithEnforceValidAccount + = pbsServiceFactory.getService(["settings.enforce-valid-account": true as String]) + private static final Closure REJECT_INVALID_ACCOUNT_METRIC = { accountId -> + "influx.metric.account.${accountId}.requests.rejected.invalid-account" + } - and: "Inactive account id" + def "PBS should reject request with error and metrics when inactive account"() { + given: "Inactive account id" def accountId = PBSUtils.randomNumber def account = new Account(uuid: accountId, config: new AccountConfig(status: AccountStatus.INACTIVE)) accountDao.save(account) @@ -27,7 +30,7 @@ class InfluxDBSpec extends BaseSpec { } when: "PBS processes auction request" - pbsService.sendAuctionRequest(bidRequest) + pbsServiceWithEnforceValidAccount.sendAuctionRequest(bidRequest) then: "PBS should reject the entire auction" def exception = thrown(PrebidServerException) @@ -36,20 +39,15 @@ class InfluxDBSpec extends BaseSpec { and: "PBs should emit proper metric" PBSUtils.waitUntil({ - def metricsRequest = pbsService.sendInfluxMetricsRequest() - metricsRequest["influx.metric.account.${bidRequest.accountId}.requests.rejected.invalid-account"] != null + pbsServiceWithEnforceValidAccount.sendInfluxMetricsRequest() + .containsKey(REJECT_INVALID_ACCOUNT_METRIC(bidRequest.accountId) as String) }) - - where: - enforceValidAccount << [true, false] + def influxMetricsRequest = pbsServiceWithEnforceValidAccount.sendInfluxMetricsRequest() + assert influxMetricsRequest[REJECT_INVALID_ACCOUNT_METRIC(bidRequest.accountId) as String] == 1 } def "PBS shouldn't reject request with error and metrics when active account"() { - given: "Pbs config with enforce-valid-account and default-account-config" - def pbsService = pbsServiceFactory.getService( - ["settings.enforce-valid-account": enforceValidAccount as String]) - - and: "Inactive account id" + given: "Inactive account id" def accountId = PBSUtils.randomNumber def account = new Account(uuid: accountId, config: new AccountConfig(status: AccountStatus.ACTIVE)) accountDao.save(account) @@ -60,18 +58,15 @@ class InfluxDBSpec extends BaseSpec { } when: "PBS processes auction request" - def response = pbsService.sendAuctionRequest(bidRequest) + def response = pbsServiceWithEnforceValidAccount.sendAuctionRequest(bidRequest) then: "Bid response should contain seatBid" assert response.seatbid.size() == 1 - and: "PBs should emit proper metric" + and: "PBs shouldn't emit metric" PBSUtils.waitUntil({ - def metricsRequest = pbsService.sendInfluxMetricsRequest() - metricsRequest["influx.metric.account.${bidRequest.accountId}.requests.rejected.invalid-account"] == null + !pbsServiceWithEnforceValidAccount.sendInfluxMetricsRequest() + .containsKey(REJECT_INVALID_ACCOUNT_METRIC(bidRequest.accountId) as String) }) - - where: - enforceValidAccount << [true, false] } } From 2d0a8e93145a817a43f88b2a8e0cc929b150c396 Mon Sep 17 00:00:00 2001 From: markiian Date: Mon, 17 Nov 2025 18:26:01 +0200 Subject: [PATCH 3/6] Updating pom with influx DB --- pom.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pom.xml b/pom.xml index d2851e0de74..79edf89b10b 100644 --- a/pom.xml +++ b/pom.xml @@ -345,11 +345,22 @@ postgresql test + + org.testcontainers + influxdb + test + org.mock-server mockserver-client-java test + + org.influxdb + influxdb-java + 2.23 + test + From 34a2b3c2ec95493d44a517a4ee4f7c746efb754d Mon Sep 17 00:00:00 2001 From: markiian Date: Mon, 1 Dec 2025 18:42:37 +0200 Subject: [PATCH 4/6] Update after review --- .../model/response/influx/Series.groovy | 1 + .../model/response/influx/Tags.groovy | 6 ++ .../service/PrebidServerService.groovy | 36 ++++++----- .../testcontainers/Dependencies.groovy | 1 - .../testcontainers/PbsConfig.groovy | 16 ----- .../container/PrebidServerContainer.groovy | 1 - .../functional/tests/InfluxDBSpec.groovy | 59 +++++++++++-------- 7 files changed, 64 insertions(+), 56 deletions(-) create mode 100644 src/test/groovy/org/prebid/server/functional/model/response/influx/Tags.groovy diff --git a/src/test/groovy/org/prebid/server/functional/model/response/influx/Series.groovy b/src/test/groovy/org/prebid/server/functional/model/response/influx/Series.groovy index 6d5dd2c5860..30b4cf86e61 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/influx/Series.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/influx/Series.groovy @@ -3,6 +3,7 @@ package org.prebid.server.functional.model.response.influx class Series { String name + Tags tags List columns List> values } diff --git a/src/test/groovy/org/prebid/server/functional/model/response/influx/Tags.groovy b/src/test/groovy/org/prebid/server/functional/model/response/influx/Tags.groovy new file mode 100644 index 00000000000..a88807ad8b4 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/response/influx/Tags.groovy @@ -0,0 +1,6 @@ +package org.prebid.server.functional.model.response.influx + +class Tags { + + String measurement +} 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 77e9e31594a..e327d054166 100644 --- a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy +++ b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy @@ -43,7 +43,6 @@ import java.time.format.DateTimeFormatter import static io.restassured.RestAssured.given import static java.time.ZoneOffset.UTC -import static org.prebid.server.functional.testcontainers.PbsConfig.PREBID_DATABASE class PrebidServerService implements ObjectMapperWrapper { @@ -61,8 +60,8 @@ class PrebidServerService implements ObjectMapperWrapper { static final String HTTP_INTERACTION_ENDPOINT = "/logging/httpinteraction" static final String COLLECTED_METRICS_ENDPOINT = "/collected-metrics" static final String PROMETHEUS_METRICS_ENDPOINT = "/metrics" - static final String UIDS_COOKIE_NAME = "uids" static final String INFLUX_DB_ENDPOINT = "/query" + static final String UIDS_COOKIE_NAME = "uids" private final PrebidServerContainer pbsContainer private final RequestSpecification requestSpecification @@ -298,22 +297,12 @@ class PrebidServerService implements ObjectMapperWrapper { Map sendInfluxMetricsRequest() { def response = given(influxRequestSpecification) - .queryParams(["db": PREBID_DATABASE, "q": "SHOW MEASUREMENTS"]) + .queryParams(["db": "prebid", + "q" : "SELECT COUNT(count) FROM /.*/ WHERE count >= 1 GROUP BY \"measurement\""]) .get(INFLUX_DB_ENDPOINT) checkResponseStatusCode(response) - def responseBody = decode(response.getBody().asString(), InfluxResponse) - - Map metricNameToCountOfCall = [:] - responseBody.results.first().series.first.values.flatten().each { it -> - def influxResponse = decode(given(influxRequestSpecification) - .queryParams(["db": PREBID_DATABASE, "q": "SELECT COUNT(count) FROM \"$it\" WHERE count >= 1"]) - .get(INFLUX_DB_ENDPOINT).getBody().asString(), InfluxResponse) - - def series = influxResponse?.results?.first?.series - metricNameToCountOfCall.put(series?.name?.first, series?.values?.flatten()?[1] as Integer) - } - metricNameToCountOfCall + collectInToMap(decode(response.getBody().asString(), InfluxResponse)) } String sendPrometheusMetricsRequest() { @@ -457,6 +446,15 @@ class PrebidServerService implements ObjectMapperWrapper { } } + Boolean isContainMetricByValue(String value) { + try { + PBSUtils.waitUntil({ sendInfluxMetricsRequest()[value] != null }) + true + } catch (IllegalStateException ignored) { + false + } + } + private String getPbsLogsByValue(String value) { pbsContainer.logs.split("\n").find { it.contains(value) } } @@ -480,4 +478,12 @@ class PrebidServerService implements ObjectMapperWrapper { .setAuth(authScheme) .build() } + + private static Map collectInToMap(InfluxResponse responseBody) { + final Map metrics = [:] + responseBody?.results?.first?.series?.collect { + metrics.put(it?.name as String, it?.values?.first[1] as Integer) + } + metrics + } } diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/Dependencies.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/Dependencies.groovy index 936507fd1f9..ab614e0ca5f 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/Dependencies.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/Dependencies.groovy @@ -36,7 +36,6 @@ class Dependencies { .withNetwork(network) static final InfluxDBContainer influxdbContainer = new InfluxDBContainer<>(DockerImageName.parse("influxdb:1.8.10")) - .withUsername("prebid") .withUsername("prebid") .withPassword("prebid") .withAuthEnabled(false) diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy index f3d36ebc328..02d627f141a 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy @@ -11,7 +11,6 @@ import static org.prebid.server.functional.util.CurrencyUtil.DEFAULT_CURRENCY final class PbsConfig { - static final String PREBID_DATABASE = "prebid" private static final String DB_ACCOUNT_QUERY = """ SELECT JSON_MERGE_PATCH(JSON_OBJECT('id', uuid, 'status', status, @@ -102,21 +101,6 @@ LIMIT 1 "settings.database.idle-connection-timeout": "300" ].asImmutable() } - - static Map getInfluxContainer(InfluxDBContainer influx = Dependencies.influxdbContainer) { - ["metrics.influxdb.enabled" : "true", - "metrics.influxdb.prefix" : "influx.metric.", - "metrics.influxdb.host" : influx.getNetworkAliases().get(0), - "metrics.influxdb.port" : influx.getExposedPorts().get(0) as String, - "metrics.influxdb.protocol" : "http", - "metrics.influxdb.database" : PREBID_DATABASE, - "metrics.influxdb.auth" : "prebid:prebid", - "metrics.influxdb.interval" : "1", - "metrics.influxdb.connectTimeout": "5000", - "metrics.influxdb.readTimeout" : "100", - ].asImmutable() - } - static Map getPostgreSqlConfig(PostgreSQLContainer postgres = Dependencies.postgresqlContainer) { ["settings.database.type" : "postgres", "settings.database.host" : postgres.getNetworkAliases().get(0), diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/container/PrebidServerContainer.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/container/PrebidServerContainer.groovy index 43630d3616a..70509252af6 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/container/PrebidServerContainer.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/container/PrebidServerContainer.groovy @@ -43,7 +43,6 @@ class PrebidServerContainer extends GenericContainer { << PbsConfig.prebidCacheConfig << PbsConfig.mySqlConfig << PbsConfig.targetingConfig - << PbsConfig.influxContainer withConfig(commonConfig) withConfig(customConfig) } diff --git a/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy index 93a798fed5d..ab5fece82a0 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy @@ -9,26 +9,41 @@ import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.util.PBSUtils import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED +import static org.prebid.server.functional.testcontainers.Dependencies.influxdbContainer class InfluxDBSpec extends BaseSpec { + private static final Map PBS_CONFIG_WITH_INFLUX_AND_ENFORCE_VALIDATION_ACCOUNTANT = [ + "metrics.influxdb.enabled" : "true", + "metrics.influxdb.prefix" : "influx.metric.", + "metrics.influxdb.host" : influxdbContainer.getNetworkAliases().get(0), + "metrics.influxdb.port" : influxdbContainer.getExposedPorts().get(0) as String, + "metrics.influxdb.protocol" : "http", + "metrics.influxdb.database" : influxdbContainer.database as String, + "metrics.influxdb.auth" : "${influxdbContainer.username}:${influxdbContainer.password}" as String, + "metrics.influxdb.interval" : "1", + "metrics.influxdb.connectTimeout": "5000", + "metrics.influxdb.readTimeout" : "100", + + "settings.enforce-valid-account": true as String] private static final PrebidServerService pbsServiceWithEnforceValidAccount - = pbsServiceFactory.getService(["settings.enforce-valid-account": true as String]) - private static final Closure REJECT_INVALID_ACCOUNT_METRIC = { accountId -> - "influx.metric.account.${accountId}.requests.rejected.invalid-account" + = pbsServiceFactory.getService(PBS_CONFIG_WITH_INFLUX_AND_ENFORCE_VALIDATION_ACCOUNTANT) + + def cleanupSpec() { + pbsServiceFactory.removeContainer(PBS_CONFIG_WITH_INFLUX_AND_ENFORCE_VALIDATION_ACCOUNTANT) } def "PBS should reject request with error and metrics when inactive account"() { - given: "Inactive account id" + given: "Default basic BidRequest with inactive account id" def accountId = PBSUtils.randomNumber - def account = new Account(uuid: accountId, config: new AccountConfig(status: AccountStatus.INACTIVE)) - accountDao.save(account) - - and: "Default basic BidRequest with inactive account id" def bidRequest = BidRequest.defaultBidRequest.tap { site.publisher.id = accountId } + and: "Inactive account id" + def account = new Account(uuid: accountId, config: new AccountConfig(status: AccountStatus.INACTIVE)) + accountDao.save(account) + when: "PBS processes auction request" pbsServiceWithEnforceValidAccount.sendAuctionRequest(bidRequest) @@ -37,26 +52,26 @@ class InfluxDBSpec extends BaseSpec { assert exception.statusCode == UNAUTHORIZED.code() assert exception.responseBody == "Account $accountId is inactive" - and: "PBs should emit proper metric" - PBSUtils.waitUntil({ - pbsServiceWithEnforceValidAccount.sendInfluxMetricsRequest() - .containsKey(REJECT_INVALID_ACCOUNT_METRIC(bidRequest.accountId) as String) - }) + and: "PBS wait until get metric" + assert pbsServiceWithEnforceValidAccount.isContainMetricByValue( + "influx.metric.account.${bidRequest.accountId}.requests.rejected.invalid-account" as String) + + and: "PBS metrics populated correctly" def influxMetricsRequest = pbsServiceWithEnforceValidAccount.sendInfluxMetricsRequest() - assert influxMetricsRequest[REJECT_INVALID_ACCOUNT_METRIC(bidRequest.accountId) as String] == 1 + assert influxMetricsRequest["influx.metric.account.${bidRequest.accountId}.requests.rejected.invalid-account" as String] == 1 } def "PBS shouldn't reject request with error and metrics when active account"() { - given: "Inactive account id" + given: "Default basic BidRequest with inactive account id" def accountId = PBSUtils.randomNumber - def account = new Account(uuid: accountId, config: new AccountConfig(status: AccountStatus.ACTIVE)) - accountDao.save(account) - - and: "Default basic BidRequest with inactive account id" def bidRequest = BidRequest.defaultBidRequest.tap { site.publisher.id = accountId } + and: "Inactive account id" + def account = new Account(uuid: accountId, config: new AccountConfig(status: AccountStatus.ACTIVE)) + accountDao.save(account) + when: "PBS processes auction request" def response = pbsServiceWithEnforceValidAccount.sendAuctionRequest(bidRequest) @@ -64,9 +79,7 @@ class InfluxDBSpec extends BaseSpec { assert response.seatbid.size() == 1 and: "PBs shouldn't emit metric" - PBSUtils.waitUntil({ - !pbsServiceWithEnforceValidAccount.sendInfluxMetricsRequest() - .containsKey(REJECT_INVALID_ACCOUNT_METRIC(bidRequest.accountId) as String) - }) + assert !pbsServiceWithEnforceValidAccount.isContainMetricByValue( + "influx.metric.account.${bidRequest.accountId}.requests.rejected.invalid-account" as String) } } From aa507fc5d9a00f8b72802bbce3bf95c2582f013c Mon Sep 17 00:00:00 2001 From: markiian Date: Tue, 2 Dec 2025 13:45:13 +0200 Subject: [PATCH 5/6] Update after review --- .../service/PrebidServerService.groovy | 12 ++++++------ .../functional/tests/InfluxDBSpec.groovy | 18 +++++------------- 2 files changed, 11 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 e327d054166..249d6fa3f13 100644 --- a/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy +++ b/src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy @@ -43,6 +43,8 @@ import java.time.format.DateTimeFormatter import static io.restassured.RestAssured.given import static java.time.ZoneOffset.UTC +import static org.prebid.server.functional.testcontainers.Dependencies.influxdbContainer + class PrebidServerService implements ObjectMapperWrapper { @@ -297,7 +299,7 @@ class PrebidServerService implements ObjectMapperWrapper { Map sendInfluxMetricsRequest() { def response = given(influxRequestSpecification) - .queryParams(["db": "prebid", + .queryParams(["db": influxdbContainer.getDatabase(), "q" : "SELECT COUNT(count) FROM /.*/ WHERE count >= 1 GROUP BY \"measurement\""]) .get(INFLUX_DB_ENDPOINT) @@ -480,10 +482,8 @@ class PrebidServerService implements ObjectMapperWrapper { } private static Map collectInToMap(InfluxResponse responseBody) { - final Map metrics = [:] - responseBody?.results?.first?.series?.collect { - metrics.put(it?.name as String, it?.values?.first[1] as Integer) - } - metrics + responseBody?.results?.first()?.series?.collectEntries { + [(it.name): it.values?.first()?.getAt(1) as Integer] + } ?: [:] } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy index ab5fece82a0..5bf081d064d 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy @@ -6,7 +6,6 @@ import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.request.auction.BidRequest 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.UNAUTHORIZED import static org.prebid.server.functional.testcontainers.Dependencies.influxdbContainer @@ -24,7 +23,6 @@ class InfluxDBSpec extends BaseSpec { "metrics.influxdb.interval" : "1", "metrics.influxdb.connectTimeout": "5000", "metrics.influxdb.readTimeout" : "100", - "settings.enforce-valid-account": true as String] private static final PrebidServerService pbsServiceWithEnforceValidAccount = pbsServiceFactory.getService(PBS_CONFIG_WITH_INFLUX_AND_ENFORCE_VALIDATION_ACCOUNTANT) @@ -35,13 +33,10 @@ class InfluxDBSpec extends BaseSpec { def "PBS should reject request with error and metrics when inactive account"() { given: "Default basic BidRequest with inactive account id" - def accountId = PBSUtils.randomNumber - def bidRequest = BidRequest.defaultBidRequest.tap { - site.publisher.id = accountId - } + def bidRequest = BidRequest.defaultBidRequest and: "Inactive account id" - def account = new Account(uuid: accountId, config: new AccountConfig(status: AccountStatus.INACTIVE)) + def account = new Account(uuid: bidRequest.accountId, config: new AccountConfig(status: AccountStatus.INACTIVE)) accountDao.save(account) when: "PBS processes auction request" @@ -50,7 +45,7 @@ class InfluxDBSpec extends BaseSpec { then: "PBS should reject the entire auction" def exception = thrown(PrebidServerException) assert exception.statusCode == UNAUTHORIZED.code() - assert exception.responseBody == "Account $accountId is inactive" + assert exception.responseBody == "Account $bidRequest.accountId is inactive" and: "PBS wait until get metric" assert pbsServiceWithEnforceValidAccount.isContainMetricByValue( @@ -63,13 +58,10 @@ class InfluxDBSpec extends BaseSpec { def "PBS shouldn't reject request with error and metrics when active account"() { given: "Default basic BidRequest with inactive account id" - def accountId = PBSUtils.randomNumber - def bidRequest = BidRequest.defaultBidRequest.tap { - site.publisher.id = accountId - } + def bidRequest = BidRequest.defaultBidRequest and: "Inactive account id" - def account = new Account(uuid: accountId, config: new AccountConfig(status: AccountStatus.ACTIVE)) + def account = new Account(uuid: bidRequest.accountId, config: new AccountConfig(status: AccountStatus.ACTIVE)) accountDao.save(account) when: "PBS processes auction request" From 8ecb203f2a8189c50fb7b438289d31f666f833a0 Mon Sep 17 00:00:00 2001 From: osulzhenko Date: Tue, 2 Dec 2025 14:37:39 +0200 Subject: [PATCH 6/6] minor update --- .../server/functional/tests/InfluxDBSpec.groovy | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy index 5bf081d064d..4e0253c1f95 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/InfluxDBSpec.groovy @@ -12,7 +12,9 @@ import static org.prebid.server.functional.testcontainers.Dependencies.influxdbC class InfluxDBSpec extends BaseSpec { - private static final Map PBS_CONFIG_WITH_INFLUX_AND_ENFORCE_VALIDATION_ACCOUNTANT = [ + private static final String ACCOUNT_REJECTED_METRIC = "influx.metric.account.%s.requests.rejected.invalid-account" + + private static final Map PBS_CONFIG_WITH_INFLUX_AND_ENFORCE_VALIDATION_ACCOUNTANT = [ "metrics.influxdb.enabled" : "true", "metrics.influxdb.prefix" : "influx.metric.", "metrics.influxdb.host" : influxdbContainer.getNetworkAliases().get(0), @@ -24,6 +26,7 @@ class InfluxDBSpec extends BaseSpec { "metrics.influxdb.connectTimeout": "5000", "metrics.influxdb.readTimeout" : "100", "settings.enforce-valid-account": true as String] + private static final PrebidServerService pbsServiceWithEnforceValidAccount = pbsServiceFactory.getService(PBS_CONFIG_WITH_INFLUX_AND_ENFORCE_VALIDATION_ACCOUNTANT) @@ -48,12 +51,11 @@ class InfluxDBSpec extends BaseSpec { assert exception.responseBody == "Account $bidRequest.accountId is inactive" and: "PBS wait until get metric" - assert pbsServiceWithEnforceValidAccount.isContainMetricByValue( - "influx.metric.account.${bidRequest.accountId}.requests.rejected.invalid-account" as String) + assert pbsServiceWithEnforceValidAccount.isContainMetricByValue(ACCOUNT_REJECTED_METRIC.formatted(bidRequest.accountId)) and: "PBS metrics populated correctly" def influxMetricsRequest = pbsServiceWithEnforceValidAccount.sendInfluxMetricsRequest() - assert influxMetricsRequest["influx.metric.account.${bidRequest.accountId}.requests.rejected.invalid-account" as String] == 1 + assert influxMetricsRequest[ACCOUNT_REJECTED_METRIC.formatted(bidRequest.accountId)] == 1 } def "PBS shouldn't reject request with error and metrics when active account"() { @@ -71,7 +73,6 @@ class InfluxDBSpec extends BaseSpec { assert response.seatbid.size() == 1 and: "PBs shouldn't emit metric" - assert !pbsServiceWithEnforceValidAccount.isContainMetricByValue( - "influx.metric.account.${bidRequest.accountId}.requests.rejected.invalid-account" as String) + assert !pbsServiceWithEnforceValidAccount.isContainMetricByValue(ACCOUNT_REJECTED_METRIC.formatted(bidRequest.accountId)) } }