Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ class NetworkServiceContainer extends MockServerContainer {

NetworkServiceContainer(String version) {
super(DockerImageName.parse("mockserver/mockserver:mockserver-$version"))
def aliasWithTopLevelDomain = "${getNetworkAliases().first()}.com".toString()
withCreateContainerCmdModifier { it.withHostName(aliasWithTopLevelDomain) }
setNetworkAliases([aliasWithTopLevelDomain])
}

String getHostAndPort() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
package org.prebid.server.functional.testcontainers.scaffolding

import org.mockserver.matchers.Times
import org.mockserver.model.Header
import org.mockserver.model.HttpRequest
import org.mockserver.model.HttpStatusCode
import org.prebid.server.functional.model.ResponseModel
import org.testcontainers.containers.MockServerContainer

import static org.mockserver.model.HttpRequest.request
import static org.mockserver.model.HttpResponse.response
import static org.mockserver.model.HttpStatusCode.OK_200
import static org.mockserver.model.MediaType.APPLICATION_JSON

class HttpSettings extends NetworkScaffolding {

private static final String ENDPOINT = "/stored-requests"
private static final String RFC_ENDPOINT = "/stored-requests-rfc"
private static final String AMP_ENDPOINT = "/amp-stored-requests"

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

@Override
void setResponse() {
}

protected HttpRequest getRfcRequest(String accountId) {
request().withPath(RFC_ENDPOINT)
.withQueryStringParameter("account-id", accountId)
}


void setRfcResponse(String value,
ResponseModel responseModel,
HttpStatusCode statusCode = OK_200,
Map<String, String> headers = [:]) {
def responseHeaders = headers.collect { new Header(it.key, it.value) }
def mockResponse = encode(responseModel)
mockServerClient.when(getRfcRequest(value), Times.unlimited())
.respond(response().withStatusCode(statusCode.code())
.withBody(mockResponse, APPLICATION_JSON)
.withHeaders(responseHeaders))
}

int getRfcRequestCount(String value) {
mockServerClient.retrieveRecordedRequests(getRfcRequest(value))
.size()
}

@Override
void reset() {
super.reset(ENDPOINT)
super.reset(RFC_ENDPOINT)
super.reset(AMP_ENDPOINT)
}

static String getEndpoint() {
return ENDPOINT
}

static String getAmpEndpoint() {
return AMP_ENDPOINT
}

static String getRfcEndpoint() {
return RFC_ENDPOINT
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,41 @@ import org.prebid.server.functional.testcontainers.PbsConfig
import org.prebid.server.functional.testcontainers.scaffolding.HttpSettings
import org.prebid.server.functional.util.PBSUtils
import org.prebid.server.util.ResourceUtil
import spock.lang.Shared

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

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

@Shared
HttpSettings httpSettings = new HttpSettings(networkServiceContainer)
static PrebidServerService prebidServerService
static PrebidServerService prebidServerServiceWithRfc

@Shared
PrebidServerService prebidServerService = pbsServiceFactory.getService(PbsConfig.httpSettingsConfig)
private static final HttpSettings httpSettings = new HttpSettings(networkServiceContainer)
private static final Map<String, String> PBS_CONFIG_WITH_RFC = new HashMap<>(PbsConfig.httpSettingsConfig) +
['settings.http.endpoint': "${networkServiceContainer.rootUri}${HttpSettings.rfcEndpoint}".toString(),
'settings.http.rfc3986-compatible': 'true']

def setupSpec() {
prebidServerService = pbsServiceFactory.getService(PbsConfig.httpSettingsConfig)
prebidServerServiceWithRfc = pbsServiceFactory.getService(PBS_CONFIG_WITH_RFC)
bidder.setResponse()
vendorList.setResponse()
}

def cleanupSpec() {
prebidServerService = pbsServiceFactory.removeContainer(PbsConfig.httpSettingsConfig)
prebidServerService = pbsServiceFactory.removeContainer(PBS_CONFIG_WITH_RFC)
}

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

and: "Prepare default account response with gdpr = 0"
def httpSettingsResponse = HttpAccountsResponse.getDefaultHttpAccountsResponse(bidRequest?.site?.publisher?.id)
httpSettings.setResponse(bidRequest?.site?.publisher?.id, httpSettingsResponse)
def httpSettingsResponse = HttpAccountsResponse.getDefaultHttpAccountsResponse(bidRequest.accountId)
httpSettings.setResponse(bidRequest.accountId, httpSettingsResponse)

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

and: "There should be only one account request"
assert httpSettings.getRequestCount(bidRequest?.site?.publisher?.id) == 1
assert httpSettings.getRequestCount(bidRequest.accountId) == 1
}

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

and: "Prepare default account response with gdpr = 0"
def httpSettingsResponse = HttpAccountsResponse.getDefaultHttpAccountsResponse(bidRequest.accountId)
httpSettings.setRfcResponse(bidRequest.accountId, httpSettingsResponse)

when: "PBS processes auction request"
def response = prebidServerServiceWithRfc.sendAuctionRequest(bidRequest)

then: "Response should contain basic fields"
assert response.id
assert response.seatbid?.size() == 1
assert response.seatbid.first().seat == GENERIC
assert response.seatbid?.first()?.bid?.size() == 1

and: "There should be only one call to bidder"
assert bidder.getRequestCount(bidRequest.id) == 1

and: "There should be only one account request"
assert httpSettings.getRfcRequestCount(bidRequest.accountId) == 1
}

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

def "PBS should take account information from http data source on AMP request when rfc3986 enabled"() {
given: "Default AmpRequest"
def ampRequest = AmpRequest.defaultAmpRequest

and: "Get basic stored request and set gdpr = 1"
def ampStoredRequest = BidRequest.defaultBidRequest
ampStoredRequest.site.publisher.id = ampRequest.account
ampStoredRequest.regs.gdpr = 1

and: "Save storedRequest into DB"
def storedRequest = StoredRequest.getStoredRequest(ampRequest, ampStoredRequest)
storedRequestDao.save(storedRequest)

and: "Prepare default account response with gdpr = 0"
def httpSettingsResponse = HttpAccountsResponse.getDefaultHttpAccountsResponse(ampRequest.account.toString())
httpSettings.setRfcResponse(ampRequest.account.toString(), httpSettingsResponse)

when: "PBS processes amp request"
def response = prebidServerServiceWithRfc.sendAmpRequest(ampRequest)

then: "Response should contain httpcalls"
assert !response.ext?.debug?.httpcalls?.isEmpty()

and: "There should be only one account request"
assert httpSettings.getRfcRequestCount(ampRequest.account.toString()) == 1

then: "Response should contain targeting"
assert !response.ext?.debug?.httpcalls?.isEmpty()
}

def "PBS should take account information from http data source on event request"() {
given: "Default EventRequest"
def eventRequest = EventRequest.defaultEventRequest
Expand All @@ -103,6 +171,25 @@ class HttpSettingsSpec extends BaseSpec {
assert httpSettings.getRequestCount(eventRequest.accountId.toString()) == 1
}

def "PBS should take account information from http data source on event request when rfc3986 enabled"() {
given: "Default EventRequest"
def eventRequest = EventRequest.defaultEventRequest

and: "Prepare default account response"
def httpSettingsResponse = HttpAccountsResponse.getDefaultHttpAccountsResponse(eventRequest.accountId.toString())
httpSettings.setRfcResponse(eventRequest.accountId.toString(), httpSettingsResponse)

when: "PBS processes event request"
def responseBody = prebidServerServiceWithRfc.sendEventRequest(eventRequest)

then: "Event response should contain and corresponding content-type"
assert responseBody ==
ResourceUtil.readByteArrayFromClassPath("org/prebid/server/functional/tracking-pixel.png")

and: "There should be only one account request"
assert httpSettings.getRfcRequestCount(eventRequest.accountId.toString()) == 1
}

def "PBS should take account information from http data source on setuid request"() {
given: "Pbs config with adapters.generic.usersync.redirect.*"
def pbsConfig = PbsConfig.httpSettingsConfig +
Expand Down Expand Up @@ -137,6 +224,42 @@ class HttpSettingsSpec extends BaseSpec {
pbsServiceFactory.removeContainer(pbsConfig)
}

def "PBS should take account information from http data source on setuid request when rfc3986 enabled"() {
given: "Pbs config with adapters.generic.usersync.redirect.*"
def pbsConfig = new HashMap<>(PbsConfig.httpSettingsConfig) +
['settings.http.endpoint': "${networkServiceContainer.rootUri}${HttpSettings.rfcEndpoint}".toString(),
'settings.http.rfc3986-compatible': 'true',
'adapters.generic.usersync.redirect.url' : "$networkServiceContainer.rootUri/generic-usersync&redir={{redirect_url}}".toString(),
'adapters.generic.usersync.redirect.support-cors' : 'false',
'adapters.generic.usersync.redirect.format-override': 'blank']
def prebidServerService = pbsServiceFactory.getService(pbsConfig)

and: "Get default SetuidRequest and set account, gdpr=1 "
def request = SetuidRequest.defaultSetuidRequest
request.gdpr = 1
request.account = PBSUtils.randomNumber.toString()
def uidsCookie = UidsCookie.defaultUidsCookie

and: "Prepare default account response"
def httpSettingsResponse = HttpAccountsResponse.getDefaultHttpAccountsResponse(request.account)
httpSettings.setRfcResponse(request.account, httpSettingsResponse)

when: "PBS processes setuid request"
def response = prebidServerService.sendSetUidRequest(request, uidsCookie)

then: "Response should contain tempUIDs cookie"
assert !response.uidsCookie.uids
assert response.uidsCookie.tempUIDs
assert response.responseBody ==
ResourceUtil.readByteArrayFromClassPath("org/prebid/server/functional/tracking-pixel.png")

and: "There should be only one account request"
assert httpSettings.getRfcRequestCount(request.account) == 1

cleanup: "Stop and remove pbs container"
pbsServiceFactory.removeContainer(pbsConfig)
}

def "PBS should take account information from http data source on vtrack request"() {
given: "Default VtrackRequest"
String payload = PBSUtils.randomString
Expand All @@ -162,6 +285,31 @@ class HttpSettingsSpec extends BaseSpec {
assert prebidCacheRequest.contains("/event?t=imp&b=${request.puts[0].bidid}&a=$accountId&bidder=${request.puts[0].bidder}")
}

def "PBS should take account information from http data source on vtrack request when rfc3986 enabled"() {
given: "Default VtrackRequest"
String payload = PBSUtils.randomString
def request = VtrackRequest.getDefaultVtrackRequest(encodeXml(Vast.getDefaultVastModel(payload)))
def accountId = PBSUtils.randomNumber.toString()

and: "Prepare default account response"
def httpSettingsResponse = HttpAccountsResponse.getDefaultHttpAccountsResponse(accountId)
httpSettings.setRfcResponse(accountId, httpSettingsResponse)

when: "PBS processes vtrack request"
def response = prebidServerServiceWithRfc.sendVtrackRequest(request, accountId)

then: "Response should contain uid"
assert response.responses[0]?.uuid

and: "There should be only one account request and pbc request"
assert httpSettings.getRfcRequestCount(accountId.toString()) == 1
assert prebidCache.getXmlRequestCount(payload) == 1

and: "VastXml that was send to PrebidCache must contain event url"
def prebidCacheRequest = prebidCache.getXmlRecordedRequestsBody(payload)[0]
assert prebidCacheRequest.contains("/event?t=imp&b=${request.puts[0].bidid}&a=$accountId&bidder=${request.puts[0].bidder}")
}

def "PBS should return error if account settings isn't found"() {
given: "Default EventRequest"
def eventRequest = EventRequest.defaultEventRequest
Expand All @@ -174,4 +322,17 @@ class HttpSettingsSpec extends BaseSpec {
assert exception.statusCode == 401
assert exception.responseBody.contains("Account '$eventRequest.accountId' doesn't support events")
}

def "PBS should return error if account settings isn't found when rfc3986 enabled"() {
given: "Default EventRequest"
def eventRequest = EventRequest.defaultEventRequest

when: "PBS processes event request"
prebidServerServiceWithRfc.sendEventRequest(eventRequest)

then: "Request should fail with error"
def exception = thrown(PrebidServerException)
assert exception.statusCode == 401
assert exception.responseBody.contains("Account '$eventRequest.accountId' doesn't support events")
}
}