Skip to content

Commit ba1822f

Browse files
authored
Tests: RFC 3986 compatibility as optional for HttpApplicationSettings (#4069)
1 parent 0e45c99 commit ba1822f

File tree

3 files changed

+215
-8
lines changed

3 files changed

+215
-8
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ class NetworkServiceContainer extends MockServerContainer {
88

99
NetworkServiceContainer(String version) {
1010
super(DockerImageName.parse("mockserver/mockserver:mockserver-$version"))
11+
def aliasWithTopLevelDomain = "${getNetworkAliases().first()}.com".toString()
12+
withCreateContainerCmdModifier { it.withHostName(aliasWithTopLevelDomain) }
13+
setNetworkAliases([aliasWithTopLevelDomain])
1114
}
1215

1316
String getHostAndPort() {

src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/HttpSettings.groovy

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
package org.prebid.server.functional.testcontainers.scaffolding
22

3+
import org.mockserver.matchers.Times
4+
import org.mockserver.model.Header
35
import org.mockserver.model.HttpRequest
6+
import org.mockserver.model.HttpStatusCode
7+
import org.prebid.server.functional.model.ResponseModel
48
import org.testcontainers.containers.MockServerContainer
59

610
import static org.mockserver.model.HttpRequest.request
11+
import static org.mockserver.model.HttpResponse.response
12+
import static org.mockserver.model.HttpStatusCode.OK_200
13+
import static org.mockserver.model.MediaType.APPLICATION_JSON
714

815
class HttpSettings extends NetworkScaffolding {
916

1017
private static final String ENDPOINT = "/stored-requests"
18+
private static final String RFC_ENDPOINT = "/stored-requests-rfc"
1119
private static final String AMP_ENDPOINT = "/amp-stored-requests"
1220

1321
HttpSettings(MockServerContainer mockServerContainer) {
@@ -27,12 +35,47 @@ class HttpSettings extends NetworkScaffolding {
2735

2836
@Override
2937
void setResponse() {
38+
}
39+
40+
protected HttpRequest getRfcRequest(String accountId) {
41+
request().withPath(RFC_ENDPOINT)
42+
.withQueryStringParameter("account-id", accountId)
43+
}
44+
45+
46+
void setRfcResponse(String value,
47+
ResponseModel responseModel,
48+
HttpStatusCode statusCode = OK_200,
49+
Map<String, String> headers = [:]) {
50+
def responseHeaders = headers.collect { new Header(it.key, it.value) }
51+
def mockResponse = encode(responseModel)
52+
mockServerClient.when(getRfcRequest(value), Times.unlimited())
53+
.respond(response().withStatusCode(statusCode.code())
54+
.withBody(mockResponse, APPLICATION_JSON)
55+
.withHeaders(responseHeaders))
56+
}
3057

58+
int getRfcRequestCount(String value) {
59+
mockServerClient.retrieveRecordedRequests(getRfcRequest(value))
60+
.size()
3161
}
3262

3363
@Override
3464
void reset() {
3565
super.reset(ENDPOINT)
66+
super.reset(RFC_ENDPOINT)
3667
super.reset(AMP_ENDPOINT)
3768
}
69+
70+
static String getEndpoint() {
71+
return ENDPOINT
72+
}
73+
74+
static String getAmpEndpoint() {
75+
return AMP_ENDPOINT
76+
}
77+
78+
static String getRfcEndpoint() {
79+
return RFC_ENDPOINT
80+
}
3881
}

src/test/groovy/org/prebid/server/functional/tests/HttpSettingsSpec.groovy

Lines changed: 169 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,28 +15,41 @@ import org.prebid.server.functional.testcontainers.PbsConfig
1515
import org.prebid.server.functional.testcontainers.scaffolding.HttpSettings
1616
import org.prebid.server.functional.util.PBSUtils
1717
import org.prebid.server.util.ResourceUtil
18-
import spock.lang.Shared
1918

2019
import static org.prebid.server.functional.model.bidder.BidderName.GENERIC
2120
import static org.prebid.server.functional.testcontainers.Dependencies.networkServiceContainer
2221

2322
class HttpSettingsSpec extends BaseSpec {
2423
// Check that PBS actually applied account config only possible by relying on side effects.
2524

26-
@Shared
27-
HttpSettings httpSettings = new HttpSettings(networkServiceContainer)
25+
static PrebidServerService prebidServerService
26+
static PrebidServerService prebidServerServiceWithRfc
2827

29-
@Shared
30-
PrebidServerService prebidServerService = pbsServiceFactory.getService(PbsConfig.httpSettingsConfig)
28+
private static final HttpSettings httpSettings = new HttpSettings(networkServiceContainer)
29+
private static final Map<String, String> PBS_CONFIG_WITH_RFC = new HashMap<>(PbsConfig.httpSettingsConfig) +
30+
['settings.http.endpoint': "${networkServiceContainer.rootUri}${HttpSettings.rfcEndpoint}".toString(),
31+
'settings.http.rfc3986-compatible': 'true']
32+
33+
def setupSpec() {
34+
prebidServerService = pbsServiceFactory.getService(PbsConfig.httpSettingsConfig)
35+
prebidServerServiceWithRfc = pbsServiceFactory.getService(PBS_CONFIG_WITH_RFC)
36+
bidder.setResponse()
37+
vendorList.setResponse()
38+
}
39+
40+
def cleanupSpec() {
41+
prebidServerService = pbsServiceFactory.removeContainer(PbsConfig.httpSettingsConfig)
42+
prebidServerService = pbsServiceFactory.removeContainer(PBS_CONFIG_WITH_RFC)
43+
}
3144

3245
def "PBS should take account information from http data source on auction request"() {
3346
given: "Get basic BidRequest with generic bidder and set gdpr = 1"
3447
def bidRequest = BidRequest.defaultBidRequest
3548
bidRequest.regs.gdpr = 1
3649

3750
and: "Prepare default account response with gdpr = 0"
38-
def httpSettingsResponse = HttpAccountsResponse.getDefaultHttpAccountsResponse(bidRequest?.site?.publisher?.id)
39-
httpSettings.setResponse(bidRequest?.site?.publisher?.id, httpSettingsResponse)
51+
def httpSettingsResponse = HttpAccountsResponse.getDefaultHttpAccountsResponse(bidRequest.accountId)
52+
httpSettings.setResponse(bidRequest.accountId, httpSettingsResponse)
4053

4154
when: "PBS processes auction request"
4255
def response = prebidServerService.sendAuctionRequest(bidRequest)
@@ -51,7 +64,32 @@ class HttpSettingsSpec extends BaseSpec {
5164
assert bidder.getRequestCount(bidRequest.id) == 1
5265

5366
and: "There should be only one account request"
54-
assert httpSettings.getRequestCount(bidRequest?.site?.publisher?.id) == 1
67+
assert httpSettings.getRequestCount(bidRequest.accountId) == 1
68+
}
69+
70+
def "PBS should take account information from http data source on auction request when rfc3986 enabled"() {
71+
given: "Get basic BidRequest with generic bidder and set gdpr = 1"
72+
def bidRequest = BidRequest.defaultBidRequest
73+
bidRequest.regs.gdpr = 1
74+
75+
and: "Prepare default account response with gdpr = 0"
76+
def httpSettingsResponse = HttpAccountsResponse.getDefaultHttpAccountsResponse(bidRequest.accountId)
77+
httpSettings.setRfcResponse(bidRequest.accountId, httpSettingsResponse)
78+
79+
when: "PBS processes auction request"
80+
def response = prebidServerServiceWithRfc.sendAuctionRequest(bidRequest)
81+
82+
then: "Response should contain basic fields"
83+
assert response.id
84+
assert response.seatbid?.size() == 1
85+
assert response.seatbid.first().seat == GENERIC
86+
assert response.seatbid?.first()?.bid?.size() == 1
87+
88+
and: "There should be only one call to bidder"
89+
assert bidder.getRequestCount(bidRequest.id) == 1
90+
91+
and: "There should be only one account request"
92+
assert httpSettings.getRfcRequestCount(bidRequest.accountId) == 1
5593
}
5694

5795
def "PBS should take account information from http data source on AMP request"() {
@@ -84,6 +122,36 @@ class HttpSettingsSpec extends BaseSpec {
84122
assert !response.ext?.debug?.httpcalls?.isEmpty()
85123
}
86124

125+
def "PBS should take account information from http data source on AMP request when rfc3986 enabled"() {
126+
given: "Default AmpRequest"
127+
def ampRequest = AmpRequest.defaultAmpRequest
128+
129+
and: "Get basic stored request and set gdpr = 1"
130+
def ampStoredRequest = BidRequest.defaultBidRequest
131+
ampStoredRequest.site.publisher.id = ampRequest.account
132+
ampStoredRequest.regs.gdpr = 1
133+
134+
and: "Save storedRequest into DB"
135+
def storedRequest = StoredRequest.getStoredRequest(ampRequest, ampStoredRequest)
136+
storedRequestDao.save(storedRequest)
137+
138+
and: "Prepare default account response with gdpr = 0"
139+
def httpSettingsResponse = HttpAccountsResponse.getDefaultHttpAccountsResponse(ampRequest.account.toString())
140+
httpSettings.setRfcResponse(ampRequest.account.toString(), httpSettingsResponse)
141+
142+
when: "PBS processes amp request"
143+
def response = prebidServerServiceWithRfc.sendAmpRequest(ampRequest)
144+
145+
then: "Response should contain httpcalls"
146+
assert !response.ext?.debug?.httpcalls?.isEmpty()
147+
148+
and: "There should be only one account request"
149+
assert httpSettings.getRfcRequestCount(ampRequest.account.toString()) == 1
150+
151+
then: "Response should contain targeting"
152+
assert !response.ext?.debug?.httpcalls?.isEmpty()
153+
}
154+
87155
def "PBS should take account information from http data source on event request"() {
88156
given: "Default EventRequest"
89157
def eventRequest = EventRequest.defaultEventRequest
@@ -103,6 +171,25 @@ class HttpSettingsSpec extends BaseSpec {
103171
assert httpSettings.getRequestCount(eventRequest.accountId.toString()) == 1
104172
}
105173

174+
def "PBS should take account information from http data source on event request when rfc3986 enabled"() {
175+
given: "Default EventRequest"
176+
def eventRequest = EventRequest.defaultEventRequest
177+
178+
and: "Prepare default account response"
179+
def httpSettingsResponse = HttpAccountsResponse.getDefaultHttpAccountsResponse(eventRequest.accountId.toString())
180+
httpSettings.setRfcResponse(eventRequest.accountId.toString(), httpSettingsResponse)
181+
182+
when: "PBS processes event request"
183+
def responseBody = prebidServerServiceWithRfc.sendEventRequest(eventRequest)
184+
185+
then: "Event response should contain and corresponding content-type"
186+
assert responseBody ==
187+
ResourceUtil.readByteArrayFromClassPath("org/prebid/server/functional/tracking-pixel.png")
188+
189+
and: "There should be only one account request"
190+
assert httpSettings.getRfcRequestCount(eventRequest.accountId.toString()) == 1
191+
}
192+
106193
def "PBS should take account information from http data source on setuid request"() {
107194
given: "Pbs config with adapters.generic.usersync.redirect.*"
108195
def pbsConfig = PbsConfig.httpSettingsConfig +
@@ -137,6 +224,42 @@ class HttpSettingsSpec extends BaseSpec {
137224
pbsServiceFactory.removeContainer(pbsConfig)
138225
}
139226

227+
def "PBS should take account information from http data source on setuid request when rfc3986 enabled"() {
228+
given: "Pbs config with adapters.generic.usersync.redirect.*"
229+
def pbsConfig = new HashMap<>(PbsConfig.httpSettingsConfig) +
230+
['settings.http.endpoint': "${networkServiceContainer.rootUri}${HttpSettings.rfcEndpoint}".toString(),
231+
'settings.http.rfc3986-compatible': 'true',
232+
'adapters.generic.usersync.redirect.url' : "$networkServiceContainer.rootUri/generic-usersync&redir={{redirect_url}}".toString(),
233+
'adapters.generic.usersync.redirect.support-cors' : 'false',
234+
'adapters.generic.usersync.redirect.format-override': 'blank']
235+
def prebidServerService = pbsServiceFactory.getService(pbsConfig)
236+
237+
and: "Get default SetuidRequest and set account, gdpr=1 "
238+
def request = SetuidRequest.defaultSetuidRequest
239+
request.gdpr = 1
240+
request.account = PBSUtils.randomNumber.toString()
241+
def uidsCookie = UidsCookie.defaultUidsCookie
242+
243+
and: "Prepare default account response"
244+
def httpSettingsResponse = HttpAccountsResponse.getDefaultHttpAccountsResponse(request.account)
245+
httpSettings.setRfcResponse(request.account, httpSettingsResponse)
246+
247+
when: "PBS processes setuid request"
248+
def response = prebidServerService.sendSetUidRequest(request, uidsCookie)
249+
250+
then: "Response should contain tempUIDs cookie"
251+
assert !response.uidsCookie.uids
252+
assert response.uidsCookie.tempUIDs
253+
assert response.responseBody ==
254+
ResourceUtil.readByteArrayFromClassPath("org/prebid/server/functional/tracking-pixel.png")
255+
256+
and: "There should be only one account request"
257+
assert httpSettings.getRfcRequestCount(request.account) == 1
258+
259+
cleanup: "Stop and remove pbs container"
260+
pbsServiceFactory.removeContainer(pbsConfig)
261+
}
262+
140263
def "PBS should take account information from http data source on vtrack request"() {
141264
given: "Default VtrackRequest"
142265
String payload = PBSUtils.randomString
@@ -162,6 +285,31 @@ class HttpSettingsSpec extends BaseSpec {
162285
assert prebidCacheRequest.contains("/event?t=imp&b=${request.puts[0].bidid}&a=$accountId&bidder=${request.puts[0].bidder}")
163286
}
164287

288+
def "PBS should take account information from http data source on vtrack request when rfc3986 enabled"() {
289+
given: "Default VtrackRequest"
290+
String payload = PBSUtils.randomString
291+
def request = VtrackRequest.getDefaultVtrackRequest(encodeXml(Vast.getDefaultVastModel(payload)))
292+
def accountId = PBSUtils.randomNumber.toString()
293+
294+
and: "Prepare default account response"
295+
def httpSettingsResponse = HttpAccountsResponse.getDefaultHttpAccountsResponse(accountId)
296+
httpSettings.setRfcResponse(accountId, httpSettingsResponse)
297+
298+
when: "PBS processes vtrack request"
299+
def response = prebidServerServiceWithRfc.sendVtrackRequest(request, accountId)
300+
301+
then: "Response should contain uid"
302+
assert response.responses[0]?.uuid
303+
304+
and: "There should be only one account request and pbc request"
305+
assert httpSettings.getRfcRequestCount(accountId.toString()) == 1
306+
assert prebidCache.getXmlRequestCount(payload) == 1
307+
308+
and: "VastXml that was send to PrebidCache must contain event url"
309+
def prebidCacheRequest = prebidCache.getXmlRecordedRequestsBody(payload)[0]
310+
assert prebidCacheRequest.contains("/event?t=imp&b=${request.puts[0].bidid}&a=$accountId&bidder=${request.puts[0].bidder}")
311+
}
312+
165313
def "PBS should return error if account settings isn't found"() {
166314
given: "Default EventRequest"
167315
def eventRequest = EventRequest.defaultEventRequest
@@ -174,4 +322,17 @@ class HttpSettingsSpec extends BaseSpec {
174322
assert exception.statusCode == 401
175323
assert exception.responseBody.contains("Account '$eventRequest.accountId' doesn't support events")
176324
}
325+
326+
def "PBS should return error if account settings isn't found when rfc3986 enabled"() {
327+
given: "Default EventRequest"
328+
def eventRequest = EventRequest.defaultEventRequest
329+
330+
when: "PBS processes event request"
331+
prebidServerServiceWithRfc.sendEventRequest(eventRequest)
332+
333+
then: "Request should fail with error"
334+
def exception = thrown(PrebidServerException)
335+
assert exception.statusCode == 401
336+
assert exception.responseBody.contains("Account '$eventRequest.accountId' doesn't support events")
337+
}
177338
}

0 commit comments

Comments
 (0)