Files
dc-project/src/test/kotlin/integration/steps/then/schema.kt
Fabrice Lecomte 0cf1aea9bf Test openapi schema of Register
Fix some routes
Improve Schema Validation
2021-03-16 00:53:10 +01:00

96 lines
3.6 KiB
Kotlin

package integration.steps.then
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.node.TextNode
import fr.dcproject.common.utils.getResource
import io.ktor.http.ContentType
import io.ktor.http.Url
import io.ktor.request.contentType
import io.ktor.request.httpMethod
import io.ktor.request.uri
import io.ktor.server.testing.TestApplicationResponse
import org.openapi4j.core.model.v3.OAI3
import org.openapi4j.parser.OpenApi3Parser
import org.openapi4j.parser.model.v3.OpenApi3
import org.openapi4j.parser.model.v3.Operation
import org.openapi4j.parser.model.v3.Schema
import org.openapi4j.schema.validator.ValidationContext
import org.openapi4j.schema.validator.ValidationData
import org.openapi4j.schema.validator.v3.SchemaValidator
import java.io.File
import kotlin.test.assertTrue
import kotlin.test.fail
fun Schema.validate(api: OpenApi3, toValidate: JsonNode) {
val validationContext: ValidationContext<OAI3> = ValidationContext(api.context)
val schemaValidator = SchemaValidator(validationContext, "", this.toNode())
val results = ValidationData<Unit>()
schemaValidator.validate(toValidate, results)
assertTrue(results.isValid, results.results().toString())
}
fun TestApplicationResponse.operation(route: String? = null, callback: Operation.(OpenApi3, String) -> Unit): Operation {
val filePath = "/openapi2.yaml"
return OpenApi3Parser().parse(File(filePath.getResource().toURI()), true).let { api: OpenApi3 ->
val httpMethod = call.request.httpMethod
val uri = route ?: "/" + Url(call.request.uri).encodedPath
val path = api.paths
.keys
.firstOrNull { uri.matches(it.replace("""\{[^{}]+}""".toRegex(), "[^/]+").toRegex()) }
api.getPath(path)
?.getOperation(httpMethod.value.toLowerCase())
?.apply {
this.callback(api, uri)
}
?: fail("""No path found for "${httpMethod.value} $uri". (on file "$filePath")""")
}
}
fun TestApplicationResponse.`And the schema response body must be valid`(contentType: ContentType? = ContentType.Application.Json) {
operation { api, uri ->
/* Validate Response */
this.apply {
val status = call.response.status()
val responseContent: JsonNode = if (content != null)
ObjectMapper().readTree(content)
else TextNode("")
getResponse(status?.value?.toString() ?: error("HttpStatus not found"))
?.getContentMediaType(contentType.toString())
?.schema
?.validate(api, responseContent)
?: fail("""No Status "${status.value}" found with media type "$contentType" for "$this $uri".""")
}
}
}
fun TestApplicationResponse.`And the schema parameters must be valid`() {
operation { api, uri ->
/* Validate Request URL */
this.apply {
Url(call.request.uri).parameters.forEach { parameter: String, values: List<String> ->
getParametersIn(api.context, "query")
?.firstOrNull { it.name == parameter }?.schema
?.validate(api, TextNode(values.first()))
?: error("""No parameter found ($parameter) for "$this $uri".""")
}
}
}
}
/**
* Validate request body
*/
fun TestApplicationResponse.`And the schema request body must be valid`(body: String) {
operation { api, uri ->
requestBody
.getContentMediaType(call.request.contentType().toString())
.schema
.validate(api, ObjectMapper().readTree(body))
}
}