Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -345,11 +345,22 @@
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>influxdb</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-client-java</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.influxdb</groupId>
<artifactId>influxdb-java</artifactId>
<version>2.23</version> <!-- works well with iZettle 1.1.1 and later -->
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.prebid.server.functional.model.response.influx

class InfluxResponse {

List<InfluxResult> results
}
Original file line number Diff line number Diff line change
@@ -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> series
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.prebid.server.functional.model.response.influx

class Series {

String name
List<String> columns
List<List<String>> values
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -42,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 {

Expand All @@ -60,9 +62,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

Expand All @@ -75,6 +79,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)
}
Expand Down Expand Up @@ -290,6 +296,26 @@ class PrebidServerService implements ObjectMapperWrapper {
decode(response.asString(), new TypeReference<Map<String, Number>>() {})
}

Map<String, Number> sendInfluxMetricsRequest() {
def response = given(influxRequestSpecification)
.queryParams(["db": PREBID_DATABASE, "q": "SHOW MEASUREMENTS"])
.get(INFLUX_DB_ENDPOINT)

checkResponseStatusCode(response)
def responseBody = decode(response.getBody().asString(), InfluxResponse)

Map<String, Number> 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
}

String sendPrometheusMetricsRequest() {
def response = given(prometheusRequestSpecification).get(PROMETHEUS_METRICS_ENDPOINT)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)

Expand All @@ -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() })
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -10,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,
Expand Down Expand Up @@ -101,6 +103,20 @@ LIMIT 1
].asImmutable()
}

static Map<String, String> 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<String, String> getPostgreSqlConfig(PostgreSQLContainer postgres = Dependencies.postgresqlContainer) {
["settings.database.type" : "postgres",
"settings.database.host" : postgres.getNetworkAliases().get(0),
Expand Down Expand Up @@ -145,7 +161,7 @@ LIMIT 1
"currency-converter.external-rates.refresh-period-ms" : "900000"]
}

static Map<String,String> getTargetingConfig() {
static Map<String, String> getTargetingConfig() {
["settings.targeting.truncate-attr-chars": '255']
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class PrebidServerContainer extends GenericContainer<PrebidServerContainer> {
<< PbsConfig.prebidCacheConfig
<< PbsConfig.mySqlConfig
<< PbsConfig.targetingConfig
<< PbsConfig.influxContainer
withConfig(commonConfig)
withConfig(customConfig)
}
Expand Down Expand Up @@ -75,6 +76,10 @@ class PrebidServerContainer extends GenericContainer<PrebidServerContainer> {
getMappedPort(PROMETHEUS_PORT)
}

String getInfluxUri() {
return "http://$host:$Dependencies.influxdbContainer.firstMappedPort"
}

String getRootUri() {
return "http://$host:$port"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
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.service.PrebidServerService
import org.prebid.server.functional.util.PBSUtils

import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED

class InfluxDBSpec extends BaseSpec {

private static final PrebidServerService pbsServiceWithEnforceValidAccount
= pbsServiceFactory.getService(["settings.enforce-valid-account": true as String])
private static final Closure<String> REJECT_INVALID_ACCOUNT_METRIC = { accountId ->
"influx.metric.account.${accountId}.requests.rejected.invalid-account"
}

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)

and: "Default basic BidRequest with inactive account id"
def bidRequest = BidRequest.defaultBidRequest.tap {
site.publisher.id = accountId
}

when: "PBS processes auction request"
pbsServiceWithEnforceValidAccount.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({
pbsServiceWithEnforceValidAccount.sendInfluxMetricsRequest()
.containsKey(REJECT_INVALID_ACCOUNT_METRIC(bidRequest.accountId) as String)
})
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: "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 = pbsServiceWithEnforceValidAccount.sendAuctionRequest(bidRequest)

then: "Bid response should contain seatBid"
assert response.seatbid.size() == 1

and: "PBs shouldn't emit metric"
PBSUtils.waitUntil({
!pbsServiceWithEnforceValidAccount.sendInfluxMetricsRequest()
.containsKey(REJECT_INVALID_ACCOUNT_METRIC(bidRequest.accountId) as String)
})
}
}
Loading