Skip to content

Commit

Permalink
Add draft functional tests for prevent external POST
Browse files Browse the repository at this point in the history
  • Loading branch information
osulzhenko committed Aug 8, 2024
1 parent f9313e7 commit 3aef20a
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,10 @@ class ApacheIgniteCacheSpec : ShouldSpec({
val requestObject = RequestObject.of(xmlPayloadTransfer)
val requestTransferValue = objectMapper.readValue(requestObject.puts[0].value, TransferValue::class.java)

// and: First request object is saved to Aerospike cache
// and: The first request object is saved to Apache ignite cache
prebidCacheApi.postCache(requestObject)

// and: Second request object with already existing UUID is prepared
// and: A second request object with already existing UUID is prepared
val jsonPayloadTransfer = PayloadTransfer.getDefaultJsonPayloadTransfer().apply { key = uuid }
val secondRequestObject = RequestObject.of(jsonPayloadTransfer)

Expand All @@ -181,7 +181,7 @@ class ApacheIgniteCacheSpec : ShouldSpec({
responseObject.responses.size shouldBe 1
responseObject.responses[0].uuid shouldBe secondRequestObject.puts[0].key

// and: Cache record was updated in Aerospike with a second request object payload
// and: Cache record was updated in Apache ignite with a second request object payload
val getCacheResponse = prebidCacheApi.getCache(responseObject.responses[0].uuid)
val responseTransferValue = objectMapper.readValue(getCacheResponse.bodyAsText(), TransferValue::class.java)

Expand Down
2 changes: 1 addition & 1 deletion src/test/kotlin/org/prebid/cache/functional/BaseSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ abstract class BaseSpec {

fun getPrebidCacheApi(config: Map<String, String> = prebidCacheConfig.getBaseRedisConfig("false")): PrebidCacheApi {
return ContainerDependencies.prebidCacheContainerPool.getPrebidCacheContainer(config)
.let { container -> PrebidCacheApi(container.host, container.getHostPort()) }
.let { container -> PrebidCacheApi(container.host, container.getHostPort(), container.getHostAdminPort()) }
}
}
}
60 changes: 55 additions & 5 deletions src/test/kotlin/org/prebid/cache/functional/GeneralCacheSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import io.kotest.matchers.string.shouldContain
import io.ktor.client.statement.bodyAsText
import io.ktor.http.HttpStatusCode
import io.ktor.http.contentType
import org.prebid.cache.functional.BaseSpec.Companion.prebidCacheConfig
import org.prebid.cache.functional.mapper.objectMapper
import org.prebid.cache.functional.model.request.MediaType.UNSUPPORTED
import org.prebid.cache.functional.model.request.RequestObject
Expand Down Expand Up @@ -48,7 +49,7 @@ class GeneralCacheSpec : ShouldSpec({

should("throw an exception when allow_external_UUID=true and payload transfer key not in UUID format is given") {
// given: Prebid Cache with allow_external_UUID=true property
val prebidCacheApi = BaseSpec.getPrebidCacheApi(BaseSpec.prebidCacheConfig.getBaseRedisConfig("true"))
val prebidCacheApi = BaseSpec.getPrebidCacheApi(prebidCacheConfig.getBaseRedisConfig("true"))

// and: Request object with set payload transfer key not in UUID format
val requestObject = RequestObject.getDefaultJsonRequestObject().apply { puts[0].key = getRandomUuid() + "*" }
Expand All @@ -65,7 +66,7 @@ class GeneralCacheSpec : ShouldSpec({

should("throw an exception when allow_external_UUID=true and empty payload transfer key is given") {
// given: Prebid Cache with allow_external_UUID=true property
val prebidCacheApi = BaseSpec.getPrebidCacheApi(BaseSpec.prebidCacheConfig.getBaseRedisConfig("true"))
val prebidCacheApi = BaseSpec.getPrebidCacheApi(prebidCacheConfig.getBaseRedisConfig("true"))

// and: Request object with set empty payload transfer key
val requestObject = RequestObject.getDefaultJsonRequestObject().apply { puts[0].key = "" }
Expand Down Expand Up @@ -98,13 +99,16 @@ class GeneralCacheSpec : ShouldSpec({
}
}

should("return the same JSON transfer value which was saved to cache") {
// given: Request object with JSON transfer value
should("return the same JSON transfer value which was saved to cache when routes.allow_public_write is enabled") {
// given: Prebid Cache with routes.allow_public_write=true property
val prebidCacheApi = BaseSpec.getPrebidCacheApi(prebidCacheConfig.getBaseRedisConfig("true", "true"))

// and: Request object with JSON transfer value
val requestObject = RequestObject.getDefaultJsonRequestObject()
val requestTransferValue = objectMapper.readValue(requestObject.puts[0].value, TransferValue::class.java)

// and: POST cache endpoint is called
val postResponse = BaseSpec.getPrebidCacheApi().postCache(requestObject)
val postResponse = prebidCacheApi.postCache(requestObject)

// when: GET cache endpoint is called
val getCacheResponse = BaseSpec.getPrebidCacheApi().getCache(postResponse.responses[0].uuid)
Expand All @@ -123,6 +127,52 @@ class GeneralCacheSpec : ShouldSpec({
}
}

should("return the same JSON transfer value which was saved to admin cache when routes.allow_public_write is disabled") {
// given: Prebid Cache with routes.allow_public_write=true property
val prebidCacheApi = BaseSpec.getPrebidCacheApi(prebidCacheConfig.getBaseRedisConfig("true", "false"))

// and: Request object with JSON transfer value
val requestObject = RequestObject.getDefaultJsonRequestObject()
val requestTransferValue = objectMapper.readValue(requestObject.puts[0].value, TransferValue::class.java)

// and: POST cache endpoint is called

val postResponse = prebidCacheApi.postCacheAdminRequest(requestObject)

// when: GET cache endpoint is called
val getCacheResponse = prebidCacheApi.getCache(postResponse.responses[0].uuid)

// then: response content type is the same as request object type
getCacheResponse.contentType()?.contentType shouldBe "application"
getCacheResponse.contentType()?.contentSubtype shouldBe requestObject.puts[0].type.getValue()

// and: transfer value is returned
val responseTransferValue = objectMapper.readValue(getCacheResponse.bodyAsText(), TransferValue::class.java)

assertSoftly {
responseTransferValue.adm shouldBe requestTransferValue.adm
responseTransferValue.width shouldBe requestTransferValue.width
responseTransferValue.height shouldBe requestTransferValue.height
}
}

should("throw an exception when routes.allow_public_write is disabled and trying to save payload transfer by general cache") {
// given: Prebid Cache with routes.allow_public_write=true property
val prebidCacheApi = BaseSpec.getPrebidCacheApi(prebidCacheConfig.getBaseRedisConfig("true", "false"))

// and: Request object with JSON transfer value
val requestObject = RequestObject.getDefaultJsonRequestObject()

// when: POST cache endpoint is called
val exception = shouldThrowExactly<ApiException> { prebidCacheApi.postCache(requestObject) }

// then: Bad Request exception is thrown
assertSoftly {
exception.statusCode shouldBe BAD_REQUEST.value()
exception.responseBody shouldContain "Main server will only accept GET requests"
}
}

should("return the same XML transfer value which was saved to cache") {
// given: Request object with XML transfer value
val requestObject = RequestObject.getDefaultXmlRequestObject()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import io.ktor.client.plugins.defaultRequest
import io.ktor.client.request.get
import io.ktor.client.request.header
import io.ktor.client.request.parameter
import io.ktor.client.request.port
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.client.statement.HttpResponse
Expand All @@ -22,37 +23,54 @@ import org.prebid.cache.functional.model.request.PayloadTransfer
import org.prebid.cache.functional.model.request.RequestObject
import org.prebid.cache.functional.model.response.ResponseObject

class PrebidCacheApi(prebidCacheHost: String, prebidCachePort: Int) {
class PrebidCacheApi(
private val prebidCacheHost: String,
private val prebidCachePort: Int,
private val prebidCacheAdminPort: Int
) {

suspend fun getCache(uuid: String?, proxyCacheHost: String? = null): HttpResponse =
get(CACHE_ENDPOINT, mapOf(UUID_QUERY_PARAMETER to uuid, PROXY_CACHE_HOST_QUERY_PARAMETER to proxyCacheHost))
get(endpoint = CACHE_ENDPOINT,
parameters = mapOf(UUID_QUERY_PARAMETER to uuid, PROXY_CACHE_HOST_QUERY_PARAMETER to proxyCacheHost))

suspend fun postCache(requestObject: RequestObject, secondaryCache: String? = null): ResponseObject =
post(CACHE_ENDPOINT, requestObject, mapOf(SECONDARY_CACHE_QUERY_PARAMETER to secondaryCache)).body()
post(endpoint = CACHE_ENDPOINT,
requestObject = requestObject,
parameters = mapOf(SECONDARY_CACHE_QUERY_PARAMETER to secondaryCache)).body()

suspend fun getCacheAdminRequest(uuid: String?, proxyCacheHost: String? = null): HttpResponse =
get(endpoint = CACHE_ENDPOINT,
requestPort = prebidCacheAdminPort,
parameters = mapOf(UUID_QUERY_PARAMETER to uuid, PROXY_CACHE_HOST_QUERY_PARAMETER to proxyCacheHost))

suspend fun postCacheAdminRequest(requestObject: RequestObject, secondaryCache: String? = null): ResponseObject =
post(endpoint = CACHE_ENDPOINT,
requestPort = prebidCacheAdminPort,
requestObject = requestObject,
parameters = mapOf(SECONDARY_CACHE_QUERY_PARAMETER to secondaryCache)).body()

suspend fun getStorageCache(
payloadTransferKey: String?,
application: String?,
apiKey: String?
): PayloadTransfer =
get(
STORAGE_ENDPOINT,
mapOf(KEY_PARAMETER to payloadTransferKey, APPLICATION_PARAMETER to application),
mapOf(API_KEY_PARAMETER to apiKey)
endpoint = STORAGE_ENDPOINT,
parameters = mapOf(KEY_PARAMETER to payloadTransferKey, APPLICATION_PARAMETER to application),
headers = mapOf(API_KEY_PARAMETER to apiKey)
).body()

suspend fun postStorageCache(requestObject: PayloadTransfer, apiKey: String? = null): Boolean =
post(
STORAGE_ENDPOINT,
requestObject,
endpoint = STORAGE_ENDPOINT,
requestObject = requestObject,
headers = mapOf(API_KEY_PARAMETER to apiKey)
).status == HttpStatusCode.NoContent

private val client = HttpClient(Apache) {
expectSuccess = true
defaultRequest {
host = prebidCacheHost
port = prebidCachePort
header(ContentType, Json)
}
install(ContentNegotiation) {
Expand All @@ -69,9 +87,11 @@ class PrebidCacheApi(prebidCacheHost: String, prebidCachePort: Int) {

private suspend fun get(
endpoint: String,
requestPort: Int = prebidCachePort,
parameters: Map<String, String?> = emptyMap(),
headers: Map<String, String?> = emptyMap()
): HttpResponse = client.get(endpoint) {
port = requestPort
parameters.forEach { (key, value) ->
value?.let { parameter(key, value) }
}
Expand All @@ -82,11 +102,13 @@ class PrebidCacheApi(prebidCacheHost: String, prebidCachePort: Int) {

private suspend fun post(
endpoint: String,
requestPort: Int = prebidCachePort,
requestObject: Any,
parameters: Map<String, String?> = emptyMap(),
headers: Map<String, String?> = emptyMap()
): HttpResponse =
client.post(endpoint) {
port = requestPort
setBody(requestObject)
parameters.forEach { (key, value) ->
value?.let { parameter(key, value) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,26 @@ import org.prebid.cache.functional.testcontainers.container.ApacheIgniteContaine
import org.prebid.cache.functional.testcontainers.container.RedisContainer
import org.prebid.cache.functional.testcontainers.container.WebCacheContainer.Companion.WEB_CACHE_PATH

class PrebidCacheContainerConfig(private val redisHost: String,
private val aerospikeHost: String,
private val apacheIgniteHost: String) {

fun getBaseRedisConfig(allowExternalUuid: String): Map<String, String> =
getBaseConfig(allowExternalUuid) + getRedisConfig()

fun getBaseAerospikeConfig(allowExternalUuid: String, aerospikeNamespace: String = NAMESPACE): Map<String, String> =
getBaseConfig(allowExternalUuid) + getAerospikeConfig(aerospikeNamespace)

fun getBaseApacheIgniteConfig(allowExternalUuid: String, ingineCacheName: String = CACHE_NAME): Map<String, String> =
getBaseConfig(allowExternalUuid) + getApacheIgniteConfig(ingineCacheName)
class PrebidCacheContainerConfig(
private val redisHost: String,
private val aerospikeHost: String,
private val apacheIgniteHost: String
) {

fun getBaseRedisConfig(allowExternalUuid: String, allowPublicWrite: String = "true"): Map<String, String> =
getBaseConfig(allowExternalUuid, allowPublicWrite) + getRedisConfig()

fun getBaseAerospikeConfig(allowExternalUuid: String,
aerospikeNamespace: String = NAMESPACE,
allowPublicWrite: String = "true"): Map<String, String> =
getBaseConfig(allowExternalUuid, allowPublicWrite) + getAerospikeConfig(aerospikeNamespace)

fun getBaseApacheIgniteConfig(
allowExternalUuid: String,
allowPublicWrite: String = "true",
ingineCacheName: String = CACHE_NAME
): Map<String, String> =
getBaseConfig(allowExternalUuid, allowPublicWrite) + getApacheIgniteConfig(ingineCacheName)

fun getBaseModuleStorageConfig(applicationName: String, apiKey: String): Map<String, String> =
getBaseConfig("true") + getModuleStorageRedisConfig(apiKey, applicationName) + getRedisConfig()
Expand Down Expand Up @@ -89,12 +97,18 @@ class PrebidCacheContainerConfig(private val redisHost: String,
"storage.default-ttl-seconds" to 1000L.toString()
)

private fun getBaseConfig(allowExternalUuid: String): Map<String, String> =
getCachePrefixConfig() + getCacheExpiryConfig() + getAllowExternalUuidConfig(allowExternalUuid) +
getCacheTimeoutConfig("2500")
private fun getBaseConfig(allowExternalUuid: String, allowPublicWrite: String = "true"): Map<String, String> =
getCachePrefixConfig() +
getCacheExpiryConfig() +
getAllowExternalUuidConfig(allowExternalUuid) +
getCacheTimeoutConfig("2500") +
getAllowPublicWriteConfig(allowPublicWrite)

private fun getCachePrefixConfig(): Map<String, String> = mapOf("cache.prefix" to "prebid_")

private fun getAllowExternalUuidConfig(allowExternalUuid: String): Map<String, String> =
mapOf("cache.allow-external-u-u-i-d" to allowExternalUuid)

private fun getAllowPublicWriteConfig(allowPublicWrite: String): Map<String, String> =
mapOf("routes.allow_public_write" to allowPublicWrite)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ class PrebidCacheContainer(imageName: String, config: Map<String, String>) :

init {
withNetwork(ContainerDependencies.network)
withExposedPorts(PORT, DEBUG_PORT)
withExposedPorts(PORT, DEBUG_PORT, ADMIN_PORT)
withFixedExposedPorts()
withJavaToolOptions()
withConfig(config)
}

fun getHostPort(): Int = getMappedPort(PORT)
fun getHostAdminPort(): Int = getMappedPort(ADMIN_PORT)

private fun withConfig(config: Map<String, String>): PrebidCacheContainer =
withEnv(normalizeProperties(config))
Expand All @@ -23,6 +24,7 @@ class PrebidCacheContainer(imageName: String, config: Map<String, String>) :
if (USE_FIXED_PORTS) {
addFixedExposedPort(FIXED_EXPOSED_APPLICATION_PORT, PORT)
addFixedExposedPort(FIXED_EXPOSED_DEBUG_PORT, DEBUG_PORT)
addFixedExposedPort(FIXED_EXPOSED_ADMIN_PORT, ADMIN_PORT)
}
}

Expand Down Expand Up @@ -68,8 +70,10 @@ class PrebidCacheContainer(imageName: String, config: Map<String, String>) :
companion object {
private const val PORT = 8080
private const val DEBUG_PORT = 8000
private const val ADMIN_PORT = 8081
private const val FIXED_EXPOSED_APPLICATION_PORT = 49100
private const val FIXED_EXPOSED_DEBUG_PORT = 49101
private const val FIXED_EXPOSED_ADMIN_PORT = 49102

private val USE_FIXED_PORTS = System.getProperty("useFixedContainerPorts")?.toBoolean() ?: false
}
Expand Down

0 comments on commit 3aef20a

Please sign in to comment.