Skip to content

Commit c962080

Browse files
marki1anosulzhenko
andauthored
Test: Add Influx db coverage (#4284)
Co-authored-by: osulzhenko <osulzhenko@magnite.com>
1 parent daec7f5 commit c962080

File tree

10 files changed

+168
-4
lines changed

10 files changed

+168
-4
lines changed

pom.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,11 +345,22 @@
345345
<artifactId>postgresql</artifactId>
346346
<scope>test</scope>
347347
</dependency>
348+
<dependency>
349+
<groupId>org.testcontainers</groupId>
350+
<artifactId>influxdb</artifactId>
351+
<scope>test</scope>
352+
</dependency>
348353
<dependency>
349354
<groupId>org.mock-server</groupId>
350355
<artifactId>mockserver-client-java</artifactId>
351356
<scope>test</scope>
352357
</dependency>
358+
<dependency>
359+
<groupId>org.influxdb</groupId>
360+
<artifactId>influxdb-java</artifactId>
361+
<version>2.23</version> <!-- works well with iZettle 1.1.1 and later -->
362+
<scope>test</scope>
363+
</dependency>
353364
</dependencies>
354365

355366
<build>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package org.prebid.server.functional.model.response.influx
2+
3+
class InfluxResponse {
4+
5+
List<InfluxResult> results
6+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.prebid.server.functional.model.response.influx
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty
4+
5+
class InfluxResult {
6+
7+
@JsonProperty("statement_id")
8+
Integer statementId
9+
List<Series> series
10+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.prebid.server.functional.model.response.influx
2+
3+
class Series {
4+
5+
String name
6+
Tags tags
7+
List<String> columns
8+
List<List<String>> values
9+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package org.prebid.server.functional.model.response.influx
2+
3+
class Tags {
4+
5+
String measurement
6+
}

src/test/groovy/org/prebid/server/functional/service/PrebidServerService.groovy

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import org.prebid.server.functional.model.response.cookiesync.CookieSyncResponse
2525
import org.prebid.server.functional.model.response.cookiesync.RawCookieSyncResponse
2626
import org.prebid.server.functional.model.response.currencyrates.CurrencyRatesResponse
2727
import org.prebid.server.functional.model.response.getuids.GetuidResponse
28+
import org.prebid.server.functional.model.response.influx.InfluxResponse
2829
import org.prebid.server.functional.model.response.infobidders.BidderInfoResponse
2930
import org.prebid.server.functional.model.response.setuid.SetuidResponse
3031
import org.prebid.server.functional.model.response.status.StatusResponse
@@ -42,6 +43,8 @@ import java.time.format.DateTimeFormatter
4243

4344
import static io.restassured.RestAssured.given
4445
import static java.time.ZoneOffset.UTC
46+
import static org.prebid.server.functional.testcontainers.Dependencies.influxdbContainer
47+
4548

4649
class PrebidServerService implements ObjectMapperWrapper {
4750

@@ -59,10 +62,12 @@ class PrebidServerService implements ObjectMapperWrapper {
5962
static final String HTTP_INTERACTION_ENDPOINT = "/logging/httpinteraction"
6063
static final String COLLECTED_METRICS_ENDPOINT = "/collected-metrics"
6164
static final String PROMETHEUS_METRICS_ENDPOINT = "/metrics"
65+
static final String INFLUX_DB_ENDPOINT = "/query"
6266
static final String UIDS_COOKIE_NAME = "uids"
6367

6468
private final PrebidServerContainer pbsContainer
6569
private final RequestSpecification requestSpecification
70+
private final RequestSpecification influxRequestSpecification
6671
private final RequestSpecification adminRequestSpecification
6772
private final RequestSpecification prometheusRequestSpecification
6873

@@ -75,6 +80,8 @@ class PrebidServerService implements ObjectMapperWrapper {
7580
this.pbsContainer = pbsContainer
7681
requestSpecification = new RequestSpecBuilder().setBaseUri(pbsContainer.rootUri)
7782
.build()
83+
influxRequestSpecification = new RequestSpecBuilder().setBaseUri(pbsContainer.influxUri)
84+
.build()
7885
adminRequestSpecification = buildAndGetRequestSpecification(pbsContainer.adminRootUri, authenticationScheme)
7986
prometheusRequestSpecification = buildAndGetRequestSpecification(pbsContainer.prometheusRootUri, authenticationScheme)
8087
}
@@ -290,6 +297,16 @@ class PrebidServerService implements ObjectMapperWrapper {
290297
decode(response.asString(), new TypeReference<Map<String, Number>>() {})
291298
}
292299

300+
Map<String, Number> sendInfluxMetricsRequest() {
301+
def response = given(influxRequestSpecification)
302+
.queryParams(["db": influxdbContainer.getDatabase(),
303+
"q" : "SELECT COUNT(count) FROM /.*/ WHERE count >= 1 GROUP BY \"measurement\""])
304+
.get(INFLUX_DB_ENDPOINT)
305+
306+
checkResponseStatusCode(response)
307+
collectInToMap(decode(response.getBody().asString(), InfluxResponse))
308+
}
309+
293310
String sendPrometheusMetricsRequest() {
294311
def response = given(prometheusRequestSpecification).get(PROMETHEUS_METRICS_ENDPOINT)
295312

@@ -431,6 +448,15 @@ class PrebidServerService implements ObjectMapperWrapper {
431448
}
432449
}
433450

451+
Boolean isContainMetricByValue(String value) {
452+
try {
453+
PBSUtils.waitUntil({ sendInfluxMetricsRequest()[value] != null })
454+
true
455+
} catch (IllegalStateException ignored) {
456+
false
457+
}
458+
}
459+
434460
private String getPbsLogsByValue(String value) {
435461
pbsContainer.logs.split("\n").find { it.contains(value) }
436462
}
@@ -454,4 +480,10 @@ class PrebidServerService implements ObjectMapperWrapper {
454480
.setAuth(authScheme)
455481
.build()
456482
}
483+
484+
private static Map<String, Number> collectInToMap(InfluxResponse responseBody) {
485+
responseBody?.results?.first()?.series?.collectEntries {
486+
[(it.name): it.values?.first()?.getAt(1) as Integer]
487+
} ?: [:]
488+
}
457489
}

src/test/groovy/org/prebid/server/functional/testcontainers/Dependencies.groovy

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

33
import org.prebid.server.functional.testcontainers.container.NetworkServiceContainer
44
import org.prebid.server.functional.util.SystemProperties
5+
import org.testcontainers.containers.InfluxDBContainer
56
import org.testcontainers.containers.MySQLContainer
67
import org.testcontainers.containers.Network
78
import org.testcontainers.containers.localstack.LocalStackContainer
@@ -34,6 +35,13 @@ class Dependencies {
3435
.withInitScript("org/prebid/server/functional/db_psql_schema.sql")
3536
.withNetwork(network)
3637

38+
static final InfluxDBContainer influxdbContainer = new InfluxDBContainer<>(DockerImageName.parse("influxdb:1.8.10"))
39+
.withUsername("prebid")
40+
.withPassword("prebid")
41+
.withAuthEnabled(false)
42+
.withDatabase("prebid")
43+
.withNetwork(network)
44+
3745
static final NetworkServiceContainer networkServiceContainer = new NetworkServiceContainer(MOCKSERVER_VERSION)
3846
.withNetwork(network)
3947

@@ -44,13 +52,13 @@ class Dependencies {
4452
localStackContainer = new LocalStackContainer(DockerImageName.parse("localstack/localstack:s3-latest"))
4553
.withNetwork(network)
4654
.withServices(S3)
47-
Startables.deepStart([networkServiceContainer, mysqlContainer, localStackContainer]).join()
55+
Startables.deepStart([networkServiceContainer, mysqlContainer, localStackContainer, influxdbContainer]).join()
4856
}
4957
}
5058

5159
static void stop() {
5260
if (IS_LAUNCH_CONTAINERS) {
53-
[networkServiceContainer, mysqlContainer, localStackContainer].parallelStream()
61+
[networkServiceContainer, mysqlContainer, localStackContainer, influxdbContainer].parallelStream()
5462
.forEach({ it.stop() })
5563
}
5664
}

src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy

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

3+
import org.testcontainers.containers.InfluxDBContainer
34
import org.testcontainers.containers.MySQLContainer
45
import org.testcontainers.containers.PostgreSQLContainer
56

@@ -100,7 +101,6 @@ LIMIT 1
100101
"settings.database.idle-connection-timeout": "300"
101102
].asImmutable()
102103
}
103-
104104
static Map<String, String> getPostgreSqlConfig(PostgreSQLContainer postgres = Dependencies.postgresqlContainer) {
105105
["settings.database.type" : "postgres",
106106
"settings.database.host" : postgres.getNetworkAliases().get(0),
@@ -145,7 +145,7 @@ LIMIT 1
145145
"currency-converter.external-rates.refresh-period-ms" : "900000"]
146146
}
147147

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

src/test/groovy/org/prebid/server/functional/testcontainers/container/PrebidServerContainer.groovy

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ class PrebidServerContainer extends GenericContainer<PrebidServerContainer> {
7575
getMappedPort(PROMETHEUS_PORT)
7676
}
7777

78+
String getInfluxUri() {
79+
return "http://$host:$Dependencies.influxdbContainer.firstMappedPort"
80+
}
81+
7882
String getRootUri() {
7983
return "http://$host:$port"
8084
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package org.prebid.server.functional.tests
2+
3+
import org.prebid.server.functional.model.AccountStatus
4+
import org.prebid.server.functional.model.config.AccountConfig
5+
import org.prebid.server.functional.model.db.Account
6+
import org.prebid.server.functional.model.request.auction.BidRequest
7+
import org.prebid.server.functional.service.PrebidServerException
8+
import org.prebid.server.functional.service.PrebidServerService
9+
10+
import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED
11+
import static org.prebid.server.functional.testcontainers.Dependencies.influxdbContainer
12+
13+
class InfluxDBSpec extends BaseSpec {
14+
15+
private static final String ACCOUNT_REJECTED_METRIC = "influx.metric.account.%s.requests.rejected.invalid-account"
16+
17+
private static final Map<String, String> PBS_CONFIG_WITH_INFLUX_AND_ENFORCE_VALIDATION_ACCOUNTANT = [
18+
"metrics.influxdb.enabled" : "true",
19+
"metrics.influxdb.prefix" : "influx.metric.",
20+
"metrics.influxdb.host" : influxdbContainer.getNetworkAliases().get(0),
21+
"metrics.influxdb.port" : influxdbContainer.getExposedPorts().get(0) as String,
22+
"metrics.influxdb.protocol" : "http",
23+
"metrics.influxdb.database" : influxdbContainer.database as String,
24+
"metrics.influxdb.auth" : "${influxdbContainer.username}:${influxdbContainer.password}" as String,
25+
"metrics.influxdb.interval" : "1",
26+
"metrics.influxdb.connectTimeout": "5000",
27+
"metrics.influxdb.readTimeout" : "100",
28+
"settings.enforce-valid-account": true as String]
29+
30+
private static final PrebidServerService pbsServiceWithEnforceValidAccount
31+
= pbsServiceFactory.getService(PBS_CONFIG_WITH_INFLUX_AND_ENFORCE_VALIDATION_ACCOUNTANT)
32+
33+
def cleanupSpec() {
34+
pbsServiceFactory.removeContainer(PBS_CONFIG_WITH_INFLUX_AND_ENFORCE_VALIDATION_ACCOUNTANT)
35+
}
36+
37+
def "PBS should reject request with error and metrics when inactive account"() {
38+
given: "Default basic BidRequest with inactive account id"
39+
def bidRequest = BidRequest.defaultBidRequest
40+
41+
and: "Inactive account id"
42+
def account = new Account(uuid: bidRequest.accountId, config: new AccountConfig(status: AccountStatus.INACTIVE))
43+
accountDao.save(account)
44+
45+
when: "PBS processes auction request"
46+
pbsServiceWithEnforceValidAccount.sendAuctionRequest(bidRequest)
47+
48+
then: "PBS should reject the entire auction"
49+
def exception = thrown(PrebidServerException)
50+
assert exception.statusCode == UNAUTHORIZED.code()
51+
assert exception.responseBody == "Account $bidRequest.accountId is inactive"
52+
53+
and: "PBS wait until get metric"
54+
assert pbsServiceWithEnforceValidAccount.isContainMetricByValue(ACCOUNT_REJECTED_METRIC.formatted(bidRequest.accountId))
55+
56+
and: "PBS metrics populated correctly"
57+
def influxMetricsRequest = pbsServiceWithEnforceValidAccount.sendInfluxMetricsRequest()
58+
assert influxMetricsRequest[ACCOUNT_REJECTED_METRIC.formatted(bidRequest.accountId)] == 1
59+
}
60+
61+
def "PBS shouldn't reject request with error and metrics when active account"() {
62+
given: "Default basic BidRequest with inactive account id"
63+
def bidRequest = BidRequest.defaultBidRequest
64+
65+
and: "Inactive account id"
66+
def account = new Account(uuid: bidRequest.accountId, config: new AccountConfig(status: AccountStatus.ACTIVE))
67+
accountDao.save(account)
68+
69+
when: "PBS processes auction request"
70+
def response = pbsServiceWithEnforceValidAccount.sendAuctionRequest(bidRequest)
71+
72+
then: "Bid response should contain seatBid"
73+
assert response.seatbid.size() == 1
74+
75+
and: "PBs shouldn't emit metric"
76+
assert !pbsServiceWithEnforceValidAccount.isContainMetricByValue(ACCOUNT_REJECTED_METRIC.formatted(bidRequest.accountId))
77+
}
78+
}

0 commit comments

Comments
 (0)