io.specmatic.test.ScenarioAsTest.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of specmatic-core Show documentation
Show all versions of specmatic-core Show documentation
Turn your contracts into executable specifications. Contract Driven Development - Collaboratively Design & Independently Deploy MicroServices & MicroFrontends.
package io.specmatic.test
import io.specmatic.conversions.convertPathParameterStyle
import io.specmatic.core.*
import io.specmatic.core.log.HttpLogMessage
import io.specmatic.core.log.LogMessage
import io.specmatic.core.log.logger
import io.specmatic.core.pattern.ContractException
import io.specmatic.core.utilities.exceptionCauseMessage
import io.specmatic.core.value.JSONObjectValue
import io.specmatic.core.value.Value
data class ScenarioAsTest(
val scenario: Scenario,
private val flagsBased: FlagsBased,
private val sourceProvider: String? = null,
private val sourceRepository: String? = null,
private val sourceRepositoryBranch: String? = null,
private val specification: String? = null,
private val serviceType: String? = null,
private val annotations: String? = null,
private val validators: List = emptyList(),
private val originalScenario: Scenario,
private val workflow: Workflow = Workflow(),
) : ContractTest {
companion object {
private var id: Value? = null
}
override fun testResultRecord(result: Result, response: HttpResponse?): TestResultRecord {
val resultStatus = result.testResult()
return TestResultRecord(
convertPathParameterStyle(scenario.path),
scenario.method,
scenario.status,
resultStatus,
sourceProvider,
sourceRepository,
sourceRepositoryBranch,
specification,
serviceType,
actualResponseStatus = response?.status ?: 0,
scenarioResult = result
)
}
override fun testDescription(): String {
return scenario.testDescription()
}
override fun runTest(testBaseURL: String, timeoutInMilliseconds: Long): Pair {
val log: (LogMessage) -> Unit = { logMessage ->
logger.log(logMessage.withComment(this.annotations))
}
val httpClient = HttpClient(testBaseURL, log = log, timeoutInMilliseconds = timeoutInMilliseconds)
return runTest(httpClient)
}
override fun runTest(testExecutor: TestExecutor): Pair {
val (result, response) = executeTestAndReturnResultAndResponse(scenario, testExecutor, flagsBased)
return Pair(result.updateScenario(scenario), response)
}
override fun plusValidator(validator: ResponseValidator): ScenarioAsTest {
return this.copy(
validators = this.validators.plus(validator)
)
}
private fun logComment() {
if (annotations != null) {
logger.log(annotations)
}
}
private fun executeTestAndReturnResultAndResponse(
testScenario: Scenario,
testExecutor: TestExecutor,
flagsBased: FlagsBased
): Pair {
val request = testScenario.generateHttpRequest(flagsBased).let {
workflow.updateRequest(it, originalScenario)
}
return try {
testExecutor.setServerState(testScenario.serverState)
testExecutor.preExecuteScenario(testScenario, request)
val response = testExecutor.execute(request)
workflow.extractDataFrom(response, originalScenario)
val validatorResult = validators.asSequence().map { it.validate(scenario, response) }.filterNotNull().firstOrNull()
val result = validatorResult ?: testResult(request, response, testScenario, flagsBased)
Pair(result.withBindings(testScenario.bindings, response), response)
} catch (exception: Throwable) {
Pair(
Result.Failure(exceptionCauseMessage(exception))
.also { failure -> failure.updateScenario(testScenario) }, null)
}
}
private fun testResult(
request: HttpRequest,
response: HttpResponse,
testScenario: Scenario,
flagsBased: FlagsBased? = null
): Result {
val result = when {
response.specmaticResultHeaderValue() == "failure" -> Result.Failure(response.body.toStringLiteral())
.updateScenario(testScenario)
else -> testScenario.matches(request, response, ContractAndResponseMismatch, flagsBased?.unexpectedKeyCheck ?: ValidateUnexpectedKeys)
}
if (result is Result.Success && result.isPartialSuccess()) {
logger.log(" PARTIAL SUCCESS: ${result.partialSuccessMessage}")
logger.newLine()
}
return result
}
}
private fun LogMessage.withComment(comment: String?): LogMessage {
return if (this is HttpLogMessage) {
this.copy(comment = comment)
} else {
this
}
}